--- /dev/null
+## @file\r
+# Library producing Pci Express Helper routines.\r
+#\r
+# Copyright (c) 2013 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = PlatformPcieHelperLib\r
+ FILE_GUID = C153F460-5D8A-4d44-83BB-A8AF5CEF132C\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = PlatformPcieHelperLib\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32\r
+#\r
+\r
+[Sources]\r
+ PlatformPcieHelperLib.c\r
+ SocUnit.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+ QuarkPlatformPkg/QuarkPlatformPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ PcdLib\r
+ IoLib\r
+ DebugLib\r
+ TimerLib\r
+ QNCAccessLib\r
+ IntelQNCLib\r
--- /dev/null
+\r
+======================\r
+= Code Contributions =\r
+======================\r
+\r
+To make a contribution to a TianoCore project, follow these steps.\r
+1. Create a change description in the format specified below to\r
+ use in the source control commit log.\r
+2. Your commit message must include your "Signed-off-by" signature,\r
+ and "Contributed-under" message.\r
+3. Your "Contributed-under" message explicitly states that the\r
+ contribution is made under the terms of the specified\r
+ contribution agreement. Your "Contributed-under" message\r
+ must include the name of contribution agreement and version.\r
+ For example: Contributed-under: TianoCore Contribution Agreement 1.0\r
+ The "TianoCore Contribution Agreement" is included below in\r
+ this document.\r
+4. Submit your code to the TianoCore project using the process\r
+ that the project documents on its web page. If the process is\r
+ not documented, then submit the code on development email list\r
+ for the project.\r
+5. It is preferred that contributions are submitted using the same\r
+ copyright license as the base project. When that is not possible,\r
+ then contributions using the following licenses can be accepted:\r
+ * BSD (2-clause): http://opensource.org/licenses/BSD-2-Clause\r
+ * BSD (3-clause): http://opensource.org/licenses/BSD-3-Clause\r
+ * MIT: http://opensource.org/licenses/MIT\r
+ * Python-2.0: http://opensource.org/licenses/Python-2.0\r
+ * Zlib: http://opensource.org/licenses/Zlib\r
+\r
+ Contributions of code put into the public domain can also be\r
+ accepted.\r
+\r
+ Contributions using other licenses might be accepted, but further\r
+ review will be required.\r
+\r
+=====================================================\r
+= Change Description / Commit Message / Patch Email =\r
+=====================================================\r
+\r
+Your change description should use the standard format for a\r
+commit message, and must include your "Signed-off-by" signature\r
+and the "Contributed-under" message.\r
+\r
+== Sample Change Description / Commit Message =\r
+\r
+=== Start of sample patch email message ===\r
+\r
+From: Contributor Name <contributor@example.com>\r
+Subject: [PATCH] CodeModule: Brief-single-line-summary\r
+\r
+Full-commit-message\r
+\r
+Contributed-under: TianoCore Contribution Agreement 1.0\r
+Signed-off-by: Contributor Name <contributor@example.com>\r
+---\r
+\r
+An extra message for the patch email which will not be considered part\r
+of the commit message can be added here.\r
+\r
+Patch content inline or attached\r
+\r
+=== End of sample patch email message ===\r
+\r
+=== Notes for sample patch email ===\r
+\r
+* The first line of commit message is taken from the email's subject\r
+ line following [PATCH]. The remaining portion of the commit message\r
+ is the email's content until the '---' line.\r
+* git format-patch is one way to create this format\r
+\r
+=== Definitions for sample patch email ===\r
+\r
+* "CodeModule" is a short idenfier for the affected code. For\r
+ example MdePkg, or MdeModulePkg UsbBusDxe.\r
+* "Brief-single-line-summary" is a short summary of the change.\r
+* The entire first line should be less than ~70 characters.\r
+* "Full-commit-message" a verbose multiple line comment describing\r
+ the change. Each line should be less than ~70 characters.\r
+* "Contributed-under" explicitely states that the contribution is\r
+ made under the terms of the contribtion agreement. This\r
+ agreement is included below in this document.\r
+* "Signed-off-by" is the contributor's signature identifying them\r
+ by their real/legal name and their email address.\r
+\r
+========================================\r
+= TianoCore Contribution Agreement 1.0 =\r
+========================================\r
+\r
+INTEL CORPORATION ("INTEL") MAKES AVAILABLE SOFTWARE, DOCUMENTATION,\r
+INFORMATION AND/OR OTHER MATERIALS FOR USE IN THE TIANOCORE OPEN SOURCE\r
+PROJECT (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE\r
+TERMS AND CONDITIONS OF THIS AGREEMENT BETWEEN YOU AND INTEL AND/OR THE\r
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR\r
+REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE\r
+CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS\r
+OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\r
+BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS\r
+AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE\r
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT\r
+USE THE CONTENT.\r
+\r
+Unless otherwise indicated, all Content made available on the TianoCore\r
+site is provided to you under the terms and conditions of the BSD\r
+License ("BSD"). A copy of the BSD License is available at\r
+http://opensource.org/licenses/bsd-license.php\r
+or when applicable, in the associated License.txt file.\r
+\r
+Certain other content may be made available under other licenses as\r
+indicated in or with such Content. (For example, in a License.txt file.)\r
+\r
+You accept and agree to the following terms and conditions for Your\r
+present and future Contributions submitted to TianoCore site. Except\r
+for the license granted to Intel hereunder, You reserve all right,\r
+title, and interest in and to Your Contributions.\r
+\r
+== SECTION 1: Definitions ==\r
+* "You" or "Contributor" shall mean the copyright owner or legal\r
+ entity authorized by the copyright owner that is making a\r
+ Contribution hereunder. All other entities that control, are\r
+ controlled by, or are under common control with that entity are\r
+ considered to be a single Contributor. For the purposes of this\r
+ definition, "control" means (i) the power, direct or indirect, to\r
+ cause the direction or management of such entity, whether by\r
+ contract or otherwise, or (ii) ownership of fifty percent (50%)\r
+ or more of the outstanding shares, or (iii) beneficial ownership\r
+ of such entity.\r
+* "Contribution" shall mean any original work of authorship,\r
+ including any modifications or additions to an existing work,\r
+ that is intentionally submitted by You to the TinaoCore site for\r
+ inclusion in, or documentation of, any of the Content. For the\r
+ purposes of this definition, "submitted" means any form of\r
+ electronic, verbal, or written communication sent to the\r
+ TianoCore site or its representatives, including but not limited\r
+ to communication on electronic mailing lists, source code\r
+ control systems, and issue tracking systems that are managed by,\r
+ or on behalf of, the TianoCore site for the purpose of\r
+ discussing and improving the Content, but excluding\r
+ communication that is conspicuously marked or otherwise\r
+ designated in writing by You as "Not a Contribution."\r
+\r
+== SECTION 2: License for Contributions ==\r
+* Contributor hereby agrees that redistribution and use of the\r
+ Contribution in source and binary forms, with or without\r
+ modification, are permitted provided that the following\r
+ conditions are met:\r
+** Redistributions of source code must retain the Contributor's\r
+ copyright notice, this list of conditions and the following\r
+ disclaimer.\r
+** Redistributions in binary form must reproduce the Contributor's\r
+ copyright notice, this list of conditions and the following\r
+ disclaimer in the documentation and/or other materials provided\r
+ with the distribution.\r
+* Disclaimer. None of the names of Contributor, Intel, or the names\r
+ of their respective contributors may be used to endorse or\r
+ promote products derived from this software without specific\r
+ prior written permission.\r
+* Contributor grants a license (with the right to sublicense) under\r
+ claims of Contributor's patents that Contributor can license that\r
+ are infringed by the Contribution (as delivered by Contributor) to\r
+ make, use, distribute, sell, offer for sale, and import the\r
+ Contribution and derivative works thereof solely to the minimum\r
+ extent necessary for licensee to exercise the granted copyright\r
+ license; this patent license applies solely to those portions of\r
+ the Contribution that are unmodified. No hardware per se is\r
+ licensed.\r
+* EXCEPT AS EXPRESSLY SET FORTH IN SECTION 3 BELOW, THE\r
+ CONTRIBUTION IS PROVIDED BY THE CONTRIBUTOR "AS IS" AND ANY\r
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\r
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\r
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
+ CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\r
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE\r
+ CONTRIBUTION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\r
+ DAMAGE.\r
+\r
+== SECTION 3: Representations ==\r
+* You represent that You are legally entitled to grant the above\r
+ license. If your employer(s) has rights to intellectual property\r
+ that You create that includes Your Contributions, You represent\r
+ that You have received permission to make Contributions on behalf\r
+ of that employer, that Your employer has waived such rights for\r
+ Your Contributions.\r
+* You represent that each of Your Contributions is Your original\r
+ creation (see Section 4 for submissions on behalf of others).\r
+ You represent that Your Contribution submissions include complete\r
+ details of any third-party license or other restriction\r
+ (including, but not limited to, related patents and trademarks)\r
+ of which You are personally aware and which are associated with\r
+ any part of Your Contributions.\r
+\r
+== SECTION 4: Third Party Contributions ==\r
+* Should You wish to submit work that is not Your original creation,\r
+ You may submit it to TianoCore site separately from any\r
+ Contribution, identifying the complete details of its source\r
+ and of any license or other restriction (including, but not\r
+ limited to, related patents, trademarks, and license agreements)\r
+ of which You are personally aware, and conspicuously marking the\r
+ work as "Submitted on behalf of a third-party: [named here]".\r
+\r
+== SECTION 5: Miscellaneous ==\r
+* Applicable Laws. Any claims arising under or relating to this\r
+ Agreement shall be governed by the internal substantive laws of\r
+ the State of Delaware or federal courts located in Delaware,\r
+ without regard to principles of conflict of laws.\r
+* Language. This Agreement is in the English language only, which\r
+ language shall be controlling in all respects, and all versions\r
+ of this Agreement in any other language shall be for accommodation\r
+ only and shall not be binding. All communications and notices made\r
+ or given pursuant to this Agreement, and all documentation and\r
+ support to be provided, unless otherwise noted, shall be in the\r
+ English language.\r
+\r
--- /dev/null
+Copyright (c) 2012, Intel Corporation. All rights reserved.\r
+\r
+Redistribution and use in source and binary forms, with or without\r
+modification, are permitted provided that the following conditions\r
+are met:\r
+\r
+* Redistributions of source code must retain the above copyright\r
+ notice, this list of conditions and the following disclaimer.\r
+* Redistributions in binary form must reproduce the above copyright\r
+ notice, this list of conditions and the following disclaimer in\r
+ the documentation and/or other materials provided with the\r
+ distribution.\r
+\r
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\r
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\r
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+POSSIBILITY OF SUCH DAMAGE.\r
--- /dev/null
+/** @file\r
+Memory controller configuration.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#ifndef __DDR_MEMORY_CONTROLLER_H__\r
+#define __DDR_MEMORY_CONTROLLER_H__\r
+\r
+//\r
+// DDR timing data definitions.\r
+// These are used to create bitmaps of valid timing configurations.\r
+//\r
+\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_FREQUENCY_UNKNOWN 0xFF\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_REFRESH_RATE_UNKNOWN 0xFF\r
+\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_20 0x01\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_25 0x00\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_30 0x02\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_ALL 0x03\r
+\r
+\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_02 0x02\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_03 0x01\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_04 0x00\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_ALL 0x03\r
+\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_02 0x02\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_03 0x01\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_04 0x00\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_ALL 0x03\r
+\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_05 0x05\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_06 0x04\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_07 0x03\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_08 0x02\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_09 0x01\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_10 0x00\r
+#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_ALL 0x07\r
+\r
+#define DUAL_CHANNEL_DDR_DATA_TYPE_REGISTERED 0x01\r
+#define DUAL_CHANNEL_DDR_DATA_TYPE_UNREGISTERED 0x02\r
+#define DUAL_CHANNEL_DDR_DATA_TYPE_BUFFERED 0x04\r
+#define DUAL_CHANNEL_DDR_DATA_TYPE_UNBUFFERED 0x08\r
+#define DUAL_CHANNEL_DDR_DATA_TYPE_SDR 0x10\r
+#define DUAL_CHANNEL_DDR_DATA_TYPE_DDR 0x20\r
+\r
+\r
+//\r
+// Maximum number of SDRAM channels supported by the memory controller\r
+//\r
+#define MAX_CHANNELS 1\r
+\r
+//\r
+// Maximum number of DIMM sockets supported by the memory controller\r
+//\r
+#define MAX_SOCKETS 1\r
+\r
+//\r
+// Maximum number of sides supported per DIMM\r
+//\r
+#define MAX_SIDES 2\r
+\r
+//\r
+// Maximum number of "Socket Sets", where a "Socket Set is a set of matching\r
+// DIMM's from the various channels\r
+//\r
+#define MAX_SOCKET_SETS 2\r
+\r
+//\r
+// Maximum number of rows supported by the memory controller\r
+//\r
+#define MAX_ROWS (MAX_SIDES * MAX_SOCKETS)\r
+\r
+//\r
+// Maximum number of memory ranges supported by the memory controller\r
+//\r
+#define MAX_RANGES (MAX_ROWS + 5)\r
+\r
+//\r
+// Maximum Number of Log entries\r
+//\r
+#define MEMORY_LOG_MAX_INDEX 16\r
+\r
+\r
+typedef struct _MEMORY_LOG_ENTRY {\r
+ EFI_STATUS_CODE_VALUE Event;\r
+ EFI_STATUS_CODE_TYPE Severity;\r
+ UINT8 Data;\r
+} MEMORY_LOG_ENTRY;\r
+\r
+typedef struct _MEMORY_LOG {\r
+ UINT8 Index;\r
+ MEMORY_LOG_ENTRY Entry[MEMORY_LOG_MAX_INDEX];\r
+} MEMORY_LOG;\r
+\r
+\r
+\r
+//\r
+// Defined ECC types\r
+//\r
+#define DUAL_CHANNEL_DDR_ECC_TYPE_NONE 0x01 // No error checking\r
+#define DUAL_CHANNEL_DDR_ECC_TYPE_EC 0x02 // Error checking only\r
+#define DUAL_CHANNEL_DDR_ECC_TYPE_SECC 0x04 // Software Scrubbing ECC\r
+#define DUAL_CHANNEL_DDR_ECC_TYPE_HECC 0x08 // Hardware Scrubbing ECC\r
+#define DUAL_CHANNEL_DDR_ECC_TYPE_CKECC 0x10 // Chip Kill ECC\r
+\r
+//\r
+// Row configuration status values\r
+//\r
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_SUCCESS 0x00 // No error\r
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_UNKNOWN 0x01 // Pattern mismatch, no memory\r
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_UNSUPPORTED 0x02 // Memory type not supported\r
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_ADDRESS_ERROR 0x03 // Row/Col/Bnk mismatch\r
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_ECC_ERROR 0x04 // Received ECC error\r
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_NOT_PRESENT 0x05 // Row is not present\r
+#define DUAL_CHANNEL_DDR_ROW_CONFIG_DISABLED 0x06 // Row is disabled\r
+\r
+\r
+//\r
+// Memory range types\r
+//\r
+typedef enum {\r
+ DualChannelDdrMainMemory,\r
+ DualChannelDdrSmramCacheable,\r
+ DualChannelDdrSmramNonCacheable,\r
+ DualChannelDdrGraphicsMemoryCacheable,\r
+ DualChannelDdrGraphicsMemoryNonCacheable,\r
+ DualChannelDdrReservedMemory,\r
+ DualChannelDdrMaxMemoryRangeType\r
+} DUAL_CHANNEL_DDR_MEMORY_RANGE_TYPE;\r
+\r
+//\r
+// Memory map range information\r
+//\r
+typedef struct {\r
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
+ EFI_PHYSICAL_ADDRESS CpuAddress;\r
+ EFI_PHYSICAL_ADDRESS RangeLength;\r
+ DUAL_CHANNEL_DDR_MEMORY_RANGE_TYPE Type;\r
+} DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE;\r
+typedef struct {\r
+ unsigned dramType :1; /**< Type: 0 = RESERVED; 1 = DDR2 */\r
+ unsigned dramWidth :1; /**< Width: 0 = x8; 1 = x16 */\r
+ unsigned dramDensity :2; /**< Density: 00b = 2Gb; 01b = 1Gb; 10b = 512Mb; 11b = 256Mb */\r
+ unsigned dramSpeed :1; /**< Speed Grade: 0 = RESERVED; 1 = 800MT/s;*/\r
+ unsigned dramTimings :3; /**< Timings: 4-4-4, 5-5-5, 6-6-6 */\r
+ unsigned dramRanks :1; /**< Ranks: 0 = Single Rank; 1 = Dual Rank */\r
+} DramGeometry; /**< DRAM Geometry Descriptor */\r
+\r
+typedef union _RegDRP {\r
+ UINT32 raw;\r
+ struct {\r
+ unsigned rank0Enabled :1; /**< Rank 0 Enable */\r
+ unsigned rank0DevWidth :2; /**< DRAM Device Width (x8,x16) */\r
+ unsigned rank0DevDensity :2; /**< DRAM Device Density (256Mb,512Mb,1Gb,2Gb) */\r
+ unsigned reserved2 :1;\r
+ unsigned rank1Enabled :1; /**< Rank 1 Enable */\r
+ unsigned reserved3 :5;\r
+ unsigned dramType :1; /**< DRAM Type (0=DDR2) */\r
+ unsigned reserved4 :5;\r
+ unsigned reserved5 :14;\r
+ } field;\r
+} RegDRP; /**< DRAM Rank Population and Interface Register */\r
+\r
+\r
+typedef union {\r
+ UINT32 raw;\r
+ struct {\r
+ unsigned dramFrequency :3; /**< DRAM Frequency (000=RESERVED,010=667,011=800) */\r
+ unsigned tRP :2; /**< Precharge to Activate Delay (3,4,5,6) */\r
+ unsigned reserved1 :1;\r
+ unsigned tRCD :2; /**< Activate to CAS Delay (3,4,5,6) */\r
+ unsigned reserved2 :1;\r
+ unsigned tCL :2; /**< CAS Latency (3,4,5,6) */\r
+ unsigned reserved3 :21;\r
+ } field;\r
+} RegDTR0; /**< DRAM Timing Register 0 */\r
+\r
+typedef union {\r
+ UINT32 raw;\r
+ struct {\r
+ unsigned tWRRD_dly :2; /**< Additional Write to Read Delay (0,1,2,3) */\r
+ unsigned reserved1 :1;\r
+ unsigned tRDWR_dly :2; /**< Additional Read to Write Delay (0,1,2,3) */\r
+ unsigned reserved2 :1;\r
+ unsigned tRDRD_dr_dly :1; /**< Additional Read to Read Delay (1,2) */\r
+ unsigned reserved3 :1;\r
+ unsigned tRD_dly :3; /**< Additional Read Data Sampling Delay (0-7) */\r
+ unsigned reserved4 :1;\r
+ unsigned tRCVEN_halfclk_dly :4; /**< Additional RCVEN Half Clock Delay Control */\r
+ unsigned reserved5 :1;\r
+ unsigned readDqDelay :2; /**< Read DQ Delay */\r
+ unsigned reserved6 :13;\r
+ } field;\r
+} RegDTR1; /**< DRAM Timing Register 1 */\r
+\r
+typedef union {\r
+ UINT32 raw;\r
+ struct {\r
+ unsigned ckStaticDisable :1; /**< CK/CK# Static Disable */\r
+ unsigned reserved1 :3;\r
+ unsigned ckeStaticDisable :2; /**< CKE Static Disable */\r
+ unsigned reserved2 :8;\r
+ unsigned refreshPeriod :2; /**< Refresh Period (disabled,128clks,3.9us,7.8us) */\r
+ unsigned refreshQueueDepth :2; /**< Refresh Queue Depth (1,2,4,8) */\r
+ unsigned reserved5 :13;\r
+ unsigned initComplete :1; /**< Initialization Complete */\r
+ } field;\r
+} RegDCO;\r
+\r
+//\r
+// MRC Data Structure\r
+//\r
+typedef struct {\r
+ RegDRP drp;\r
+ RegDTR0 dtr0;\r
+ RegDTR1 dtr1;\r
+ RegDCO dco;\r
+ UINT32 reg0104;\r
+ UINT32 reg0120;\r
+ UINT32 reg0121;\r
+ UINT32 reg0123;\r
+ UINT32 reg0111;\r
+ UINT32 reg0130;\r
+ UINT8 refreshPeriod; /**< Placeholder for the chosen refresh\r
+ * period. This value will NOT be\r
+ * programmed into DCO until all\r
+ * initialization is done.\r
+ */\r
+ UINT8 ddr2Odt; /**< 0 = Disabled, 1 = 75 ohm, 2 = 150ohm, 3 = 50ohm */\r
+ UINT8 sku; /**< Detected QuarkNcSocId SKU */\r
+ UINT8 capabilities; /**< Capabilities Available on this part */\r
+ UINT8 state; /**< NORMAL_BOOT, S3_RESUME */\r
+ UINT32 memSize; /**< Memory size */\r
+ UINT16 pmBase; /**< PM Base */\r
+ UINT16 mrcVersion; /**< MRC Version */\r
+ UINT32 hecbase; /**< HECBASE shifted left 16 bits */\r
+ DramGeometry geometry; /**< DRAM Geometry */\r
+} MRC_DATA_STRUCTURE; /**< QuarkNcSocId Memory Parameters for MRC */\r
+\r
+typedef struct _EFI_MEMINIT_CONFIG_DATA {\r
+ MRC_DATA_STRUCTURE MrcData;\r
+} EFI_MEMINIT_CONFIG_DATA;\r
+\r
+\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Public include file for the QNC Base\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __INTEL_QNC_BASE_H__\r
+#define __INTEL_QNC_BASE_H__\r
+\r
+#include <IntelQNCRegs.h>\r
+#include <IntelQNCConfig.h>\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+Some configuration of QNC Package\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __INTEL_QNC_CONFIG_H__\r
+#define __INTEL_QNC_CONFIG_H__\r
+\r
+//\r
+// QNC Fixed configurations.\r
+//\r
+\r
+//\r
+// Memory arbiter fixed config values.\r
+//\r
+#define QNC_FIXED_CONFIG_ASTATUS ((UINT32) (\\r
+ (ASTATUS_PRI_NORMAL << ASTATUS0_DEFAULT_BP) | \\r
+ (ASTATUS_PRI_NORMAL << ASTATUS1_DEFAULT_BP) | \\r
+ (ASTATUS_PRI_URGENT << ASTATUS0_RASISED_BP) | \\r
+ (ASTATUS_PRI_URGENT << ASTATUS1_RASISED_BP) \\r
+ ))\r
+\r
+//\r
+// Memory Manager fixed config values.\r
+//\r
+#define V_DRAM_NON_HOST_RQ_LIMIT 2\r
+\r
+//\r
+// RMU Thermal config fixed config values for TS in Vref Mode.\r
+//\r
+#define V_TSCGF1_CONFIG_ISNSCURRENTSEL_VREF_MODE 0x04\r
+#define V_TSCGF2_CONFIG2_ISPARECTRL_VREF_MODE 0x01\r
+#define V_TSCGF1_CONFIG_IBGEN_VREF_MODE 1\r
+#define V_TSCGF2_CONFIG_IDSCONTROL_VREF_MODE 0x011b\r
+#define V_TSCGF2_CONFIG2_ICALCOARSETUNE_VREF_MODE 0x34\r
+\r
+//\r
+// RMU Thermal config fixed config values for TS in Ratiometric mode.\r
+//\r
+#define V_TSCGF1_CONFIG_ISNSCURRENTSEL_RATIO_MODE 0x04\r
+#define V_TSCGF1_CONFIG_ISNSCHOPSEL_RATIO_MODE 0x02\r
+#define V_TSCGF1_CONFIG_ISNSINTERNALVREFEN_RATIO_MODE 1\r
+#define V_TSCGF2_CONFIG_IDSCONTROL_RATIO_MODE 0x011f\r
+#define V_TSCGF2_CONFIG_IDSTIMING_RATIO_MODE 0x0001\r
+#define V_TSCGF2_CONFIG2_ICALCONFIGSEL_RATIO_MODE 0x01\r
+#define V_TSCGF2_CONFIG2_ISPARECTRL_RATIO_MODE 0x00\r
+#define V_TSCGF1_CONFIG_IBGEN_RATIO_MODE 0\r
+#define V_TSCGF1_CONFIG_IBGCHOPEN_RATIO_MODE 0\r
+#define V_TSCGF3_CONFIG_ITSGAMMACOEFF_RATIO_MODE 0xC8\r
+#define V_TSCGF2_CONFIG2_ICALCOARSETUNE_RATIO_MODE 0x17\r
+\r
+//\r
+// iCLK fixed config values.\r
+//\r
+#define V_MUXTOP_FLEX2 3\r
+#define V_MUXTOP_FLEX1 1\r
+\r
+//\r
+// PCIe Root Port fixed config values.\r
+//\r
+#define V_PCIE_ROOT_PORT_SBIC_VALUE (B_QNC_PCIE_IOSFSBCTL_SBIC_IDLE_NEVER)\r
+\r
+//\r
+// QNC structures for configuration.\r
+//\r
+\r
+typedef union {\r
+ struct {\r
+ UINT32 PortErrorMask :8;\r
+ UINT32 SlotImplemented :1;\r
+ UINT32 Reserved1 :1;\r
+ UINT32 AspmEnable :1;\r
+ UINT32 AspmAutoEnable :1;\r
+ UINT32 AspmL0sEnable :2;\r
+ UINT32 AspmL1Enable :1;\r
+ UINT32 PmeInterruptEnable :1;\r
+ UINT32 PhysicalSlotNumber :13;\r
+ UINT32 Reserved2 :1;\r
+ UINT32 PmSciEnable :1;\r
+ UINT32 HotplugSciEnable :1;\r
+ } Bits;\r
+ UINT32 Uint32;\r
+} PCIEXP_ROOT_PORT_CONFIGURATION;\r
+\r
+typedef union {\r
+ UINT32 Uint32;\r
+ struct {\r
+ UINT32 Pcie_0 :1; // 0: Disabled; 1: Enabled*\r
+ UINT32 Pcie_1 :1; // 0: Disabled; 1: Enabled*\r
+ UINT32 Smbus :1; // 0: Disabled; 1: Enabled*\r
+ UINT32 Rsvd :29; // 0\r
+ } Bits;\r
+} QNC_DEVICE_ENABLES;\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+Public include file for the QNC Dxe\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __INTEL_QNC_DXE_H__\r
+#define __INTEL_QNC_DXE_H__\r
+\r
+#include <IntelQNCRegs.h>\r
+#include <IntelQNCConfig.h>\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+Public include file for the QNC Pei\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __INTEL_QNC_PEIM_H__\r
+#define __INTEL_QNC_PEIM_H__\r
+\r
+#include <IntelQNCRegs.h>\r
+#include <IntelQNCConfig.h>\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+Registers definition for Intel QuarkNcSocId.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __INTEL_QNC_REGS_H__\r
+#define __INTEL_QNC_REGS_H__\r
+\r
+#include <QNCAccess.h>\r
+\r
+//\r
+// PCI HostBridge Segment number\r
+//\r
+#define QNC_PCI_HOST_BRIDGE_SEGMENT_NUMBER 0\r
+\r
+//\r
+// PCI RootBridge resource allocation's attribute\r
+//\r
+#define QNC_PCI_ROOT_BRIDGE_RESOURCE_ALLOCATION_ATTRIBUTE \\r
+ EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM\r
+\r
+//\r
+// PCI HostBridge resource appeture\r
+//\r
+#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSBASE 0x0\r
+#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSLIMIT 0xff\r
+#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_TSEG_SIZE 0x10000000\r
+\r
+//\r
+// PCI RootBridge configure port\r
+//\r
+#define QNC_PCI_ROOT_BRIDGE_CONFIGURATION_ADDRESS_PORT 0xCF8\r
+#define QNC_PCI_ROOT_BRIDGE_CONFIGURATION_DATA_PORT 0xCFC\r
+\r
+//\r
+// PCI Rootbridge's support feature\r
+//\r
+#define QNC_PCI_ROOT_BRIDGE_SUPPORTED (EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | \\r
+ EFI_PCI_ATTRIBUTE_ISA_IO | \\r
+ EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | \\r
+ EFI_PCI_ATTRIBUTE_VGA_MEMORY | \\r
+ EFI_PCI_ATTRIBUTE_VGA_IO)\r
+\r
+#endif // __INTEL_QNC_REGS_H__\r
--- /dev/null
+/** @file\r
+Library that provides QNC specific library services in PEI phase\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __INTEL_QNC_LIB_H__\r
+#define __INTEL_QNC_LIB_H__\r
+\r
+/**\r
+ This function initializes the QNC register before MRC.\r
+ It sets RCBA, PMBASE, disable Watchdog timer and initialize QNC GPIO.\r
+ If the function cannot complete it'll ASSERT().\r
+**/\r
+VOID\r
+EFIAPI\r
+PeiQNCPreMemInit (\r
+ VOID\r
+ );\r
+\r
+\r
+/**\r
+ Used to check SCH if it's S3 state. Clear the register state after query.\r
+\r
+ @retval TRUE if it's S3 state.\r
+ @retval FALSE if it's not S3 state.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QNCCheckS3AndClearState (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Used to check SCH if system wakes up from power on reset. Clear the register state after query.\r
+\r
+ @retval TRUE if system wakes up from power on reset\r
+ @retval FALSE if system does not wake up from power on reset\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QNCCheckPowerOnResetAndClearState (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ This function is used to clear SMI and wake status.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCClearSmiAndWake (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Used to initialize the QNC register after MRC.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PeiQNCPostMemInit (\r
+ VOID\r
+ );\r
+\r
+/** Send DRAM Ready opcode.\r
+\r
+ @param[in] OpcodeParam Parameter to DRAM ready opcode.\r
+\r
+ @retval VOID\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCSendOpcodeDramReady (\r
+ IN UINT32 OpcodeParam\r
+ );\r
+\r
+/**\r
+\r
+ Relocate RMU Main binary to memory after MRC to improve performance.\r
+\r
+ @param[in] DestBaseAddress - Specify the new memory address for the RMU Main binary.\r
+ @param[in] SrcBaseAddress - Specify the current memory address for the RMU Main binary.\r
+ @param[in] Size - Specify size of the RMU Main binary.\r
+\r
+ @retval VOID\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RmuMainRelocation (\r
+ IN CONST UINT32 DestBaseAddress,\r
+ IN CONST UINT32 SrcBaseAddress,\r
+ IN CONST UINTN Size\r
+ );\r
+\r
+/**\r
+ Get the total memory size\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+QNCGetTotalMemorysize (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Get the memory range of TSEG.\r
+ The TSEG's memory is below TOLM.\r
+\r
+ @param[out] BaseAddress The base address of TSEG's memory range\r
+ @param[out] MemorySize The size of TSEG's memory range\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCGetTSEGMemoryRange (\r
+ OUT UINT64 *BaseAddress,\r
+ OUT UINT64 *MemorySize\r
+ );\r
+\r
+/**\r
+ Updates the PAM registers in the MCH for the requested range and mode.\r
+\r
+ @param Start The start address of the memory region\r
+ @param Length The length, in bytes, of the memory region\r
+ @param ReadEnable Pointer to the boolean variable on whether to enable read for legacy memory section.\r
+ If NULL, then read attribute will not be touched by this call.\r
+ @param ReadEnable Pointer to the boolean variable on whether to enable write for legacy memory section.\r
+ If NULL, then write attribute will not be touched by this call.\r
+ @param Granularity A pointer to granularity, in bytes, that the PAM registers support\r
+\r
+ @retval RETURN_SUCCESS The PAM registers in the MCH were updated\r
+ @retval RETURN_INVALID_PARAMETER The memory range is not valid in legacy region.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+QNCLegacyRegionManipulation (\r
+ IN UINT32 Start,\r
+ IN UINT32 Length,\r
+ IN BOOLEAN *ReadEnable,\r
+ IN BOOLEAN *WriteEnable,\r
+ OUT UINT32 *Granularity\r
+ );\r
+\r
+/**\r
+ Do early init of pci express rootports on Soc.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PciExpressEarlyInit (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Complete initialization of all the pci express rootports on Soc.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PciExpressInit (\r
+ );\r
+\r
+/**\r
+ Determine if QNC is supported.\r
+\r
+ @retval FALSE QNC is not supported.\r
+ @retval TRUE QNC is supported.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsQncSupported (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Get the DeviceId of the SoC\r
+\r
+ @retval PCI DeviceId of the SoC\r
+**/\r
+UINT16\r
+EFIAPI\r
+QncGetSocDeviceId (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Enable SMI detection of legacy flash access violations.\r
+**/\r
+VOID\r
+EFIAPI\r
+QncEnableLegacyFlashAccessViolationSmi (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Setup RMU Thermal sensor registers for Vref mode.\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCThermalSensorSetVRefMode (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Setup RMU Thermal sensor registers for Ratiometric mode.\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCThermalSensorSetRatiometricMode (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Setup RMU Thermal sensor trip point values.\r
+\r
+ @param[in] CatastrophicTripOnDegreesCelsius - Catastrophic set trip point threshold.\r
+ @param[in] HotTripOnDegreesCelsius - Hot set trip point threshold.\r
+ @param[in] HotTripOffDegreesCelsius - Hot clear trip point threshold.\r
+\r
+ @retval VOID\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+QNCThermalSensorSetTripValues (\r
+ IN CONST UINTN CatastrophicTripOnDegreesCelsius,\r
+ IN CONST UINTN HotTripOnDegreesCelsius,\r
+ IN CONST UINTN HotTripOffDegreesCelsius\r
+ );\r
+\r
+/**\r
+ Enable RMU Thermal sensor with a Catastrophic Trip point.\r
+\r
+ @retval EFI_SUCCESS Trip points setup.\r
+ @retval EFI_INVALID_PARAMETER Invalid trip point value.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+QNCThermalSensorEnableWithCatastrophicTrip (\r
+ IN CONST UINTN CatastrophicTripOnDegreesCelsius\r
+ );\r
+\r
+/**\r
+ Lock all RMU Thermal sensor control & trip point registers.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCThermalSensorLockAllRegisters (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Set chipset policy for double bit ECC error.\r
+\r
+ @param[in] PolicyValue Policy to config on double bit ECC error.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCPolicyDblEccBitErr (\r
+ IN CONST UINT32 PolicyValue\r
+ );\r
+\r
+/**\r
+ Determine if running on secure Quark hardware Sku.\r
+\r
+ @retval FALSE Base Quark Sku or unprovisioned Secure Sku running.\r
+ @retval TRUE Provisioned SecureSku hardware running.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QncIsSecureProvisionedSku (\r
+ VOID\r
+ );\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+Library functions for Setting QNC internal network port\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __QNC_ACCESS_LIB_H__\r
+#define __QNC_ACCESS_LIB_H__\r
+\r
+#include <IntelQNCRegs.h>\r
+\r
+#define MESSAGE_READ_DW(Port, Reg) \\r
+ (UINT32)((QUARK_OPCODE_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)\r
+\r
+#define MESSAGE_WRITE_DW(Port, Reg) \\r
+ (UINT32)((QUARK_OPCODE_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)\r
+\r
+#define ALT_MESSAGE_READ_DW(Port, Reg) \\r
+ (UINT32)((QUARK_ALT_OPCODE_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)\r
+\r
+#define ALT_MESSAGE_WRITE_DW(Port, Reg) \\r
+ (UINT32)((QUARK_ALT_OPCODE_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)\r
+\r
+#define MESSAGE_IO_READ_DW(Port, Reg) \\r
+ (UINT32)((QUARK_OPCODE_IO_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)\r
+\r
+#define MESSAGE_IO_WRITE_DW(Port, Reg) \\r
+ (UINT32)((QUARK_OPCODE_IO_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)\r
+\r
+#define MESSAGE_SHADOW_DW(Port, Reg) \\r
+ (UINT32)((QUARK_DRAM_BASE_ADDR_READY << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)\r
+\r
+\r
+/**\r
+ Read required data from QNC internal message network\r
+**/\r
+UINT32\r
+EFIAPI\r
+QNCPortRead(\r
+ UINT8 Port,\r
+ UINT32 RegAddress\r
+ );\r
+\r
+/**\r
+ Write prepared data into QNC internal message network.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCPortWrite (\r
+ UINT8 Port,\r
+ UINT32 RegAddress,\r
+ UINT32 WriteValue\r
+ );\r
+\r
+/**\r
+ Read required data from QNC internal message network\r
+**/\r
+UINT32\r
+EFIAPI\r
+QNCAltPortRead(\r
+ UINT8 Port,\r
+ UINT32 RegAddress\r
+ );\r
+\r
+/**\r
+ Write prepared data into QNC internal message network.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCAltPortWrite (\r
+ UINT8 Port,\r
+ UINT32 RegAddress,\r
+ UINT32 WriteValue\r
+ );\r
+\r
+/**\r
+ Read required data from QNC internal message network\r
+**/\r
+UINT32\r
+EFIAPI\r
+QNCPortIORead(\r
+ UINT8 Port,\r
+ UINT32 RegAddress\r
+ );\r
+\r
+/**\r
+ Write prepared data into QNC internal message network.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCPortIOWrite (\r
+ UINT8 Port,\r
+ UINT32 RegAddress,\r
+ UINT32 WriteValue\r
+ );\r
+\r
+/**\r
+ This is for the special consideration for QNC MMIO write, as required by FWG,\r
+ a reading must be performed after MMIO writing to ensure the expected write\r
+ is processed and data is flushed into chipset\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+QNCMmIoWrite (\r
+ UINT32 MmIoAddress,\r
+ QNC_MEM_IO_WIDTH Width,\r
+ UINT32 DataNumber,\r
+ VOID *pData\r
+ );\r
+\r
+UINT32\r
+EFIAPI\r
+QncHsmmcRead (\r
+ VOID\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+QncHsmmcWrite (\r
+ UINT32 WriteValue\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+QncImrWrite (\r
+ UINT32 ImrBaseOffset,\r
+ UINT32 ImrLow,\r
+ UINT32 ImrHigh,\r
+ UINT32 ImrReadMask,\r
+ UINT32 ImrWriteMask\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+QncIClkAndThenOr (\r
+ UINT32 RegAddress,\r
+ UINT32 AndValue,\r
+ UINT32 OrValue\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+QncIClkOr (\r
+ UINT32 RegAddress,\r
+ UINT32 OrValue\r
+ );\r
+\r
+UINTN\r
+EFIAPI\r
+QncGetPciExpressBaseAddress (\r
+ VOID\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+QNC Smm Library Services header file.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __QNC_SMM_LIB_H__\r
+#define __QNC_SMM_LIB_H__\r
+\r
+/**\r
+ This routine is the chipset code that accepts a request to "open" a region of SMRAM.\r
+ The region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.\r
+ The use of "open" means that the memory is visible from all boot-service\r
+ and SMM agents.\r
+\r
+ @retval FALSE Cannot open a locked SMRAM region\r
+ @retval TRUE Success to open SMRAM region.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QNCOpenSmramRegion (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ This routine is the chipset code that accepts a request to "close" a region of SMRAM.\r
+ The region could be legacy AB or TSEG near top of physical memory.\r
+ The use of "close" means that the memory is only visible from SMM agents,\r
+ not from BS or RT code.\r
+\r
+ @retval FALSE Cannot open a locked SMRAM region\r
+ @retval TRUE Success to open SMRAM region.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QNCCloseSmramRegion (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ This routine is the chipset code that accepts a request to "lock" SMRAM.\r
+ The region could be legacy AB or TSEG near top of physical memory.\r
+ The use of "lock" means that the memory can no longer be opened\r
+ to BS state.\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCLockSmramRegion (\r
+ VOID\r
+ );\r
+\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+Memory Initialization PPI used in EFI PEI interface\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __QNC_MEMORY_INIT_H__\r
+#define __QNC_MEMORY_INIT_H__\r
+\r
+#include "mrc.h"\r
+\r
+#define PEI_QNC_MEMORY_INIT_PPI_GUID \\r
+ {0x21ff1fee, 0xd33a, 0x4fce, {0xa6, 0x5e, 0x95, 0x5e, 0xa3, 0xc4, 0x1f, 0x40}}\r
+\r
+\r
+\r
+\r
+//\r
+// PPI Function Declarations\r
+//\r
+typedef\r
+VOID\r
+(EFIAPI *PEI_QNC_MEMORY_INIT) (\r
+ IN OUT MRCParams_t *MRCDATA\r
+ );\r
+\r
+typedef struct _PEI_QNC_MEMORY_INIT_PPI {\r
+ PEI_QNC_MEMORY_INIT MrcStart;\r
+}PEI_QNC_MEMORY_INIT_PPI;\r
+\r
+extern EFI_GUID gQNCMemoryInitPpiGuid;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This file defines the QNC Info Protocol.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+#ifndef _PCH_INFO_H_\r
+#define _PCH_INFO_H_\r
+\r
+//\r
+// Extern the GUID for protocol users.\r
+//\r
+extern EFI_GUID gEfiQncInfoProtocolGuid;\r
+\r
+//\r
+// Forward reference for ANSI C compatibility\r
+//\r
+typedef struct _EFI_QNC_INFO_PROTOCOL EFI_QNC_INFO_PROTOCOL;\r
+\r
+//\r
+// Protocol revision number\r
+// Any backwards compatible changes to this protocol will result in an update in the revision number\r
+// Major changes will require publication of a new protocol\r
+//\r
+// Revision 1: Original version\r
+// Revision 2: Add RCVersion item to EFI_QNC_INFO_PROTOCOL\r
+//\r
+#define QNC_INFO_PROTOCOL_REVISION_1 1\r
+#define QNC_INFO_PROTOCOL_REVISION_2 2\r
+\r
+//\r
+// RCVersion[7:0] is the release number.\r
+//\r
+#define QNC_RC_VERSION 0x01020000\r
+\r
+//\r
+// Protocol definition\r
+//\r
+struct _EFI_QNC_INFO_PROTOCOL {\r
+ UINT8 Revision;\r
+ UINT8 BusNumber;\r
+ UINT32 RCVersion;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Protocol used for Platform Policy definition.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+#ifndef _PLATFORM_POLICY_H_\r
+#define _PLATFORM_POLICY_H_\r
+\r
+typedef struct _EFI_PLATFORM_POLICY_PROTOCOL EFI_PLATFORM_POLICY_PROTOCOL;\r
+\r
+#define EFI_PLATFORM_POLICY_PROTOCOL_GUID \\r
+ { \\r
+ 0x2977064f, 0xab96, 0x4fa9, { 0x85, 0x45, 0xf9, 0xc4, 0x02, 0x51, 0xe0, 0x7f } \\r
+ }\r
+\r
+//\r
+// Protocol to describe various platform information. Add to this as needed.\r
+//\r
+struct _EFI_PLATFORM_POLICY_PROTOCOL {\r
+ UINT8 NumRsvdSmbusAddresses;\r
+ UINT8 *RsvdSmbusAddresses;\r
+};\r
+\r
+extern EFI_GUID gEfiPlatformPolicyProtocolGuid;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This file defines the QNC S3 support Protocol.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+#ifndef _QNC_S3_SUPPORT_PROTOCOL_H_\r
+#define _QNC_S3_SUPPORT_PROTOCOL_H_\r
+\r
+//\r
+// Extern the GUID for protocol users.\r
+//\r
+extern EFI_GUID gEfiQncS3SupportProtocolGuid;\r
+\r
+//\r
+// Forward reference for ANSI C compatibility\r
+//\r
+typedef struct _EFI_QNC_S3_SUPPORT_PROTOCOL EFI_QNC_S3_SUPPORT_PROTOCOL;\r
+\r
+typedef enum {\r
+ QncS3ItemTypeInitPcieRootPortDownstream,\r
+ QncS3ItemTypeMax\r
+} EFI_QNC_S3_DISPATCH_ITEM_TYPE;\r
+\r
+//\r
+// It's better not to use pointer here because the size of pointer in DXE is 8, but it's 4 in PEI\r
+// plug 4 to ParameterSize in PEIM if you really need it\r
+//\r
+typedef struct {\r
+ UINT32 Reserved;\r
+} EFI_QNC_S3_PARAMETER_INIT_PCIE_ROOT_PORT_DOWNSTREAM;\r
+\r
+typedef union {\r
+ EFI_QNC_S3_PARAMETER_INIT_PCIE_ROOT_PORT_DOWNSTREAM PcieRootPortData;\r
+} EFI_DISPATCH_CONTEXT_UNION;\r
+\r
+typedef struct {\r
+ EFI_QNC_S3_DISPATCH_ITEM_TYPE Type;\r
+ VOID *Parameter;\r
+} EFI_QNC_S3_DISPATCH_ITEM;\r
+\r
+//\r
+// Member functions\r
+//\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_QNC_S3_SUPPORT_SET_S3_DISPATCH_ITEM) (\r
+ IN EFI_QNC_S3_SUPPORT_PROTOCOL * This,\r
+ IN EFI_QNC_S3_DISPATCH_ITEM * DispatchItem,\r
+ OUT VOID **S3DispatchEntryPoint,\r
+ OUT VOID **Context\r
+ );\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set an item to be dispatched at S3 resume time. At the same time, the entry point\r
+ of the QNC S3 support image is returned to be used in subsequent boot script save\r
+ call\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the protocol instance.\r
+ DispatchItem - The item to be dispatched.\r
+ S3DispatchEntryPoint - The entry point of the QNC S3 support image.\r
+\r
+Returns:\r
+\r
+ EFI_STATUS\r
+\r
+--*/\r
+\r
+//\r
+// Protocol definition\r
+//\r
+struct _EFI_QNC_S3_SUPPORT_PROTOCOL {\r
+ EFI_QNC_S3_SUPPORT_SET_S3_DISPATCH_ITEM SetDispatchItem;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Intel-only SMM Child Dispatcher Protocol.\r
+\r
+This protocol provides a parent dispatch service for a collection of\r
+chipset-specific SMI source.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef __SMM_ICHN_DISPATCH2_H__\r
+#define __SMM_ICHN_DISPATCH2_H__\r
+\r
+//\r
+// Share some common definitions with Framework SMM\r
+//\r
+#include <Protocol/SmmIchnDispatch.h>\r
+\r
+#include <PiSmm.h>\r
+\r
+//\r
+// Global ID for the ICH SMI Protocol\r
+//\r
+#define EFI_SMM_ICHN_DISPATCH2_PROTOCOL_GUID \\r
+ { \\r
+ 0xadf3a128, 0x416d, 0x4060, {0x8d, 0xdf, 0x30, 0xa1, 0xd7, 0xaa, 0xb6, 0x99 } \\r
+ }\r
+\r
+typedef struct _EFI_SMM_ICHN_DISPATCH2_PROTOCOL EFI_SMM_ICHN_DISPATCH2_PROTOCOL;\r
+\r
+typedef struct {\r
+ EFI_SMM_ICHN_SMI_TYPE Type;\r
+} EFI_SMM_ICHN_REGISTER_CONTEXT;\r
+\r
+//\r
+// Member functions\r
+//\r
+/**\r
+ Register a child SMI source dispatch function with a parent SMM driver\r
+\r
+ @param This Protocol instance pointer.\r
+ @param DispatchFunction Pointer to dispatch function to be invoked for\r
+ this SMI source\r
+ @param RegisterContext Pointer to the dispatch function's context.\r
+ The caller fills this context in before calling\r
+ the register function to indicate to the register\r
+ function the ICHN SMI source for which the dispatch\r
+ function should be invoked.\r
+ @param DispatchHandle Handle generated by the dispatcher to track the\r
+ function instance.\r
+\r
+ @retval EFI_SUCCESS The dispatch function has been successfully\r
+ registered and the SMI source has been enabled.\r
+ @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI source.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory (system or SMM) to manage this\r
+ child.\r
+ @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The ICHN input value\r
+ is not within valid range.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SMM_ICHN_DISPATCH2_REGISTER) (\r
+ IN CONST EFI_SMM_ICHN_DISPATCH2_PROTOCOL *This,\r
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,\r
+ IN OUT EFI_SMM_ICHN_REGISTER_CONTEXT *RegisterContext,\r
+ OUT EFI_HANDLE *DispatchHandle\r
+ );\r
+\r
+/**\r
+ Unregister a child SMI source dispatch function with a parent SMM driver\r
+\r
+ @param This Protocol instance pointer.\r
+ @param DispatchHandle Handle of dispatch function to deregister.\r
+\r
+ @retval EFI_SUCCESS The dispatch function has been successfully\r
+ unregistered and the SMI source has been disabled\r
+ if there are no other registered child dispatch\r
+ functions for this SMI source.\r
+ @retval EFI_INVALID_PARAMETER Handle is invalid.\r
+ @retval other\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SMM_ICHN_DISPATCH2_UNREGISTER) (\r
+ IN EFI_SMM_ICHN_DISPATCH2_PROTOCOL *This,\r
+ IN EFI_HANDLE DispatchHandle\r
+ );\r
+\r
+//\r
+// Interface structure for the SMM Ich n specific SMI Dispatch Protocol\r
+//\r
+/**\r
+ @par Protocol Description:\r
+ Provides a parent dispatch service for ICH SMI sources.\r
+\r
+ @param Register\r
+ Installs a child service to be dispatched by this protocol.\r
+\r
+ @param UnRegister\r
+ Removes a child service dispatched by this protocol.\r
+\r
+**/\r
+struct _EFI_SMM_ICHN_DISPATCH2_PROTOCOL {\r
+ EFI_SMM_ICHN_DISPATCH2_REGISTER Register;\r
+ EFI_SMM_ICHN_DISPATCH2_UNREGISTER UnRegister;\r
+};\r
+\r
+extern EFI_GUID gEfiSmmIchnDispatch2ProtocolGuid;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This file defines the EFI SPI Protocol which implements the\r
+Intel(R) ICH SPI Host Controller Compatibility Interface.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+#ifndef _SPI_H_\r
+#define _SPI_H_\r
+\r
+//\r
+// Define the SPI protocol GUID\r
+//\r
+// EDK and EDKII have different GUID formats\r
+//\r
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)\r
+#define EFI_SPI_PROTOCOL_GUID \\r
+ { \\r
+ 0x1156efc6, 0xea32, 0x4396, 0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 \\r
+ }\r
+#define EFI_SMM_SPI_PROTOCOL_GUID \\r
+ { \\r
+ 0xD9072C35, 0xEB8F, 0x43ad, 0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 \\r
+ }\r
+#else\r
+#define EFI_SPI_PROTOCOL_GUID \\r
+ { \\r
+ 0x1156efc6, 0xea32, 0x4396, \\r
+ { \\r
+ 0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 \\r
+ } \\r
+ }\r
+#define EFI_SMM_SPI_PROTOCOL_GUID \\r
+ { \\r
+ 0xD9072C35, 0xEB8F, 0x43ad, \\r
+ { \\r
+ 0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 \\r
+ } \\r
+ }\r
+#endif\r
+//\r
+// Extern the GUID for protocol users.\r
+//\r
+extern EFI_GUID gEfiSpiProtocolGuid;\r
+extern EFI_GUID gEfiSmmSpiProtocolGuid;\r
+\r
+//\r
+// Forward reference for ANSI C compatibility\r
+//\r
+typedef struct _EFI_SPI_PROTOCOL EFI_SPI_PROTOCOL;\r
+\r
+//\r
+// SPI protocol data structures and definitions\r
+//\r
+//\r
+// Number of Prefix Opcodes allowed on the SPI interface\r
+//\r
+#define SPI_NUM_PREFIX_OPCODE 2\r
+\r
+//\r
+// Number of Opcodes in the Opcode Menu\r
+//\r
+#define SPI_NUM_OPCODE 8\r
+\r
+#ifdef SERVER_BIOS_FLAG\r
+//\r
+// SPI default opcode slots\r
+//\r
+#define SPI_OPCODE_JEDEC_ID_INDEX 0\r
+#endif // SERVER_BIOS_FLAG\r
+\r
+//\r
+// Opcode Type\r
+// EnumSpiOpcodeCommand: Command without address\r
+// EnumSpiOpcodeRead: Read with address\r
+// EnumSpiOpcodeWrite: Write with address\r
+//\r
+typedef enum {\r
+ EnumSpiOpcodeReadNoAddr,\r
+ EnumSpiOpcodeWriteNoAddr,\r
+ EnumSpiOpcodeRead,\r
+ EnumSpiOpcodeWrite,\r
+ EnumSpiOpcodeMax\r
+} SPI_OPCODE_TYPE;\r
+\r
+typedef enum {\r
+ EnumSpiCycle20MHz,\r
+ EnumSpiCycle33MHz,\r
+ EnumSpiCycle66MHz, // not supported by PCH\r
+ EnumSpiCycle50MHz,\r
+ EnumSpiCycleMax\r
+} SPI_CYCLE_FREQUENCY;\r
+\r
+typedef enum {\r
+ EnumSpiRegionAll,\r
+ EnumSpiRegionBios,\r
+ EnumSpiRegionMe,\r
+ EnumSpiRegionGbE,\r
+ EnumSpiRegionDescriptor,\r
+ EnumSpiRegionPlatformData,\r
+ EnumSpiRegionMax\r
+} SPI_REGION_TYPE;\r
+\r
+//\r
+// Hardware Sequencing required operations (as listed in CougarPoint EDS Table 5-55: "Hardware\r
+// Sequencing Commands and Opcode Requirements"\r
+//\r
+typedef enum {\r
+ EnumSpiOperationWriteStatus,\r
+ EnumSpiOperationProgramData_1_Byte,\r
+ EnumSpiOperationProgramData_64_Byte,\r
+ EnumSpiOperationReadData,\r
+ EnumSpiOperationWriteDisable,\r
+ EnumSpiOperationReadStatus,\r
+ EnumSpiOperationWriteEnable,\r
+ EnumSpiOperationFastRead,\r
+ EnumSpiOperationEnableWriteStatus,\r
+ EnumSpiOperationErase_256_Byte,\r
+ EnumSpiOperationErase_4K_Byte,\r
+ EnumSpiOperationErase_8K_Byte,\r
+ EnumSpiOperationErase_64K_Byte,\r
+ EnumSpiOperationFullChipErase,\r
+ EnumSpiOperationJedecId,\r
+ EnumSpiOperationDualOutputFastRead,\r
+ EnumSpiOperationDiscoveryParameters,\r
+ EnumSpiOperationOther,\r
+ EnumSpiOperationMax\r
+} SPI_OPERATION;\r
+\r
+//\r
+// Opcode menu entries\r
+// Type Operation Type (value to be programmed to the OPTYPE register)\r
+// Code The opcode (value to be programmed to the OPMENU register)\r
+// Frequency The expected frequency to be used (value to be programmed to the SSFC\r
+// Register)\r
+// Operation Which Hardware Sequencing required operation this opcode respoinds to.\r
+// The required operations are listed in EDS Table 5-55: "Hardware\r
+// Sequencing Commands and Opcode Requirements"\r
+// If the opcode does not corresponds to any operation listed, use\r
+// EnumSpiOperationOther\r
+//\r
+typedef struct _SPI_OPCODE_MENU_ENTRY {\r
+ SPI_OPCODE_TYPE Type;\r
+ UINT8 Code;\r
+ SPI_CYCLE_FREQUENCY Frequency;\r
+ SPI_OPERATION Operation;\r
+} SPI_OPCODE_MENU_ENTRY;\r
+\r
+//\r
+// Initialization data table loaded to the SPI host controller\r
+// VendorId Vendor ID of the SPI device\r
+// DeviceId0 Device ID0 of the SPI device\r
+// DeviceId1 Device ID1 of the SPI device\r
+// PrefixOpcode Prefix opcodes which are loaded into the SPI host controller\r
+// OpcodeMenu Opcodes which are loaded into the SPI host controller Opcode Menu\r
+// BiosStartOffset The offset of the start of the BIOS image relative to the flash device.\r
+// Please note this is a Flash Linear Address, NOT a memory space address.\r
+// This value is platform specific and depends on the system flash map.\r
+// This value is only used on non Descriptor mode.\r
+// BiosSize The the BIOS Image size in flash. This value is platform specific\r
+// and depends on the system flash map. Please note BIOS Image size may\r
+// be smaller than BIOS Region size (in Descriptor Mode) or the flash size\r
+// (in Non Descriptor Mode), and in this case, BIOS Image is supposed to be\r
+// placed at the top end of the BIOS Region (in Descriptor Mode) or the flash\r
+// (in Non Descriptor Mode)\r
+//\r
+typedef struct _SPI_INIT_TABLE {\r
+ UINT8 VendorId;\r
+ UINT8 DeviceId0;\r
+ UINT8 DeviceId1;\r
+ UINT8 PrefixOpcode[SPI_NUM_PREFIX_OPCODE];\r
+ SPI_OPCODE_MENU_ENTRY OpcodeMenu[SPI_NUM_OPCODE];\r
+ UINTN BiosStartOffset;\r
+ UINTN BiosSize;\r
+} SPI_INIT_TABLE;\r
+\r
+//\r
+// Public Info struct to show current initialized state of the spi interface.\r
+// OpcodeIndex must be less then SPI_NUM_OPCODE for operation to be supported.\r
+//\r
+typedef struct _SPI_INIT_INFO {\r
+ SPI_INIT_TABLE *InitTable;\r
+ UINT8 JedecIdOpcodeIndex;\r
+ UINT8 OtherOpcodeIndex;\r
+ UINT8 WriteStatusOpcodeIndex;\r
+ UINT8 ProgramOpcodeIndex;\r
+ UINT8 ReadOpcodeIndex;\r
+ UINT8 EraseOpcodeIndex;\r
+ UINT8 ReadStatusOpcodeIndex;\r
+ UINT8 FullChipEraseOpcodeIndex;\r
+} SPI_INIT_INFO;\r
+\r
+//\r
+// Protocol member functions\r
+//\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SPI_INIT) (\r
+ IN EFI_SPI_PROTOCOL * This,\r
+ IN SPI_INIT_TABLE * InitTable\r
+ );\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initializes the host controller to execute SPI commands.\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+ InitTable Pointer to caller-allocated buffer containing the SPI\r
+ interface initialization table.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Opcode initialization on the SPI host controller completed.\r
+ EFI_ACCESS_DENIED The SPI configuration interface is locked.\r
+ EFI_OUT_OF_RESOURCES Not enough resource available to initialize the device.\r
+ EFI_DEVICE_ERROR Device error, operation failed.\r
+\r
+--*/\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SPI_LOCK) (\r
+ IN EFI_SPI_PROTOCOL * This\r
+ );\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Lock the SPI Static Configuration Interface.\r
+ Once locked, the interface is no longer open for configuration changes.\r
+ The lock state automatically clears on next system reset.\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Lock operation succeed.\r
+ EFI_DEVICE_ERROR Device error, operation failed.\r
+ EFI_ACCESS_DENIED The interface has already been locked.\r
+\r
+--*/\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SPI_EXECUTE) (\r
+ IN EFI_SPI_PROTOCOL * This,\r
+ IN UINT8 OpcodeIndex,\r
+ IN UINT8 PrefixOpcodeIndex,\r
+ IN BOOLEAN DataCycle,\r
+ IN BOOLEAN Atomic,\r
+ IN BOOLEAN ShiftOut,\r
+ IN UINTN Address,\r
+ IN UINT32 DataByteCount,\r
+ IN OUT UINT8 *Buffer,\r
+ IN SPI_REGION_TYPE SpiRegionType\r
+ );\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Execute SPI commands from the host controller.\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+ OpcodeIndex Index of the command in the OpCode Menu.\r
+ PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.\r
+ DataCycle TRUE if the SPI cycle contains data\r
+ Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.\r
+ ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.\r
+ Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform\r
+ Region, this value specifies the offset from the Region Base; for BIOS Region,\r
+ this value specifies the offset from the start of the BIOS Image. In Non\r
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.\r
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor\r
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is\r
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or\r
+ the flash (in Non Descriptor Mode)\r
+ DataByteCount Number of bytes in the data portion of the SPI cycle.\r
+ Buffer Pointer to caller-allocated buffer containing the dada received or sent during the SPI cycle.\r
+ SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,\r
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in\r
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode\r
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative\r
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Command succeed.\r
+ EFI_INVALID_PARAMETER The parameters specified are not valid.\r
+ EFI_UNSUPPORTED Command not supported.\r
+ EFI_DEVICE_ERROR Device error, command aborts abnormally.\r
+\r
+--*/\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SPI_INFO) (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ OUT SPI_INIT_INFO **InitInfoPtr\r
+ );\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Return info about SPI host controller, to help callers usage of Execute\r
+ service.\r
+\r
+ If 0xff is returned as an opcode index in init info struct\r
+ then device does not support the operation.\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+ InitInfoPtr Pointer to init info written to this memory location.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Information returned.\r
+ EFI_INVALID_PARAMETER Invalid parameter.\r
+ EFI_NOT_READY Required resources not setup.\r
+ Others Unexpected error happened.\r
+\r
+--*/\r
+\r
+//\r
+// Protocol definition\r
+//\r
+struct _EFI_SPI_PROTOCOL {\r
+ EFI_SPI_INIT Init;\r
+ EFI_SPI_LOCK Lock;\r
+ EFI_SPI_EXECUTE Execute;\r
+ EFI_SPI_INFO Info;\r
+};\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Macros to simplify and abstract the interface to PCI configuration.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+#ifndef _QNC_ACCESS_H_\r
+#define _QNC_ACCESS_H_\r
+\r
+#include "QuarkNcSocId.h"\r
+#include "QNCCommonDefinitions.h"\r
+\r
+#define EFI_LPC_PCI_ADDRESS( Register ) \\r
+ EFI_PCI_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, Register)\r
+\r
+//\r
+// QNC Controller PCI access macros\r
+//\r
+#define QNC_RCRB_BASE (QNCMmio32 (PciDeviceMmBase (0, PCI_DEVICE_NUMBER_QNC_LPC, 0), R_QNC_LPC_RCBA) & B_QNC_LPC_RCBA_MASK)\r
+\r
+//\r
+// Device 0x1f, Function 0\r
+//\r
+\r
+#define LpcPciCfg32( Register ) \\r
+ QNCMmPci32(0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register )\r
+\r
+#define LpcPciCfg32Or( Register, OrData ) \\r
+ QNCMmPci32Or( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData )\r
+\r
+#define LpcPciCfg32And( Register, AndData ) \\r
+ QNCMmPci32And( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData )\r
+\r
+#define LpcPciCfg32AndThenOr( Register, AndData, OrData ) \\r
+ QNCMmPci32AndThenOr( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData )\r
+\r
+#define LpcPciCfg16( Register ) \\r
+ QNCMmPci16( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register )\r
+\r
+#define LpcPciCfg16Or( Register, OrData ) \\r
+ QNCMmPci16Or( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData )\r
+\r
+#define LpcPciCfg16And( Register, AndData ) \\r
+ QNCMmPci16And( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData )\r
+\r
+#define LpcPciCfg16AndThenOr( Register, AndData, OrData ) \\r
+ QNCMmPci16AndThenOr( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData )\r
+\r
+#define LpcPciCfg8( Register ) \\r
+ QNCMmPci8( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register )\r
+\r
+#define LpcPciCfg8Or( Register, OrData ) \\r
+ QNCMmPci8Or( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData )\r
+\r
+#define LpcPciCfg8And( Register, AndData ) \\r
+ QNCMmPci8And( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData )\r
+\r
+#define LpcPciCfg8AndThenOr( Register, AndData, OrData ) \\r
+ QNCMmPci8AndThenOr( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData )\r
+\r
+//\r
+// Root Complex Register Block\r
+//\r
+\r
+#define MmRcrb32( Register ) \\r
+ QNCMmio32( QNC_RCRB_BASE, Register )\r
+\r
+#define MmRcrb32Or( Register, OrData ) \\r
+ QNCMmio32Or( QNC_RCRB_BASE, Register, OrData )\r
+\r
+#define MmRcrb32And( Register, AndData ) \\r
+ QNCMmio32And( QNC_RCRB_BASE, Register, AndData )\r
+\r
+#define MmRcrb32AndThenOr( Register, AndData, OrData ) \\r
+ QNCMmio32AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData )\r
+\r
+#define MmRcrb16( Register ) \\r
+ QNCMmio16( QNC_RCRB_BASE, Register )\r
+\r
+#define MmRcrb16Or( Register, OrData ) \\r
+ QNCMmio16Or( QNC_RCRB_BASE, Register, OrData )\r
+\r
+#define MmRcrb16And( Register, AndData ) \\r
+ QNCMmio16And( QNC_RCRB_BASE, Register, AndData )\r
+\r
+#define MmRcrb16AndThenOr( Register, AndData, OrData ) \\r
+ QNCMmio16AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData )\r
+\r
+#define MmRcrb8( Register ) \\r
+ QNCMmio8( QNC_RCRB_BASE, Register )\r
+\r
+#define MmRcrb8Or( Register, OrData ) \\r
+ QNCMmio8Or( QNC_RCRB_BASE, Register, OrData )\r
+\r
+#define MmRcrb8And( Register, AndData ) \\r
+ QNCMmio8And( QNC_RCRB_BASE, Register, AndData )\r
+\r
+#define MmRcrb8AndThenOr( Register, AndData, OrData ) \\r
+ QNCMmio8AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData )\r
+\r
+//\r
+// Memory Controller PCI access macros\r
+//\r
+\r
+//\r
+// Device 0, Function 0\r
+//\r
+\r
+#define McD0PciCfg64(Register) QNCMmPci32 (0, MC_BUS, 0, 0, Register)\r
+#define McD0PciCfg64Or(Register, OrData) QNCMmPci32Or (0, MC_BUS, 0, 0, Register, OrData)\r
+#define McD0PciCfg64And(Register, AndData) QNCMmPci32And (0, MC_BUS, 0, 0, Register, AndData)\r
+#define McD0PciCfg64AndThenOr(Register, AndData, OrData) QNCMmPci32AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData)\r
+\r
+#define McD0PciCfg32(Register) QNCMmPci32 (0, MC_BUS, 0, 0, Register)\r
+#define McD0PciCfg32Or(Register, OrData) QNCMmPci32Or (0, MC_BUS, 0, 0, Register, OrData)\r
+#define McD0PciCfg32And(Register, AndData) QNCMmPci32And (0, MC_BUS, 0, 0, Register, AndData)\r
+#define McD0PciCfg32AndThenOr(Register, AndData, OrData) QNCMmPci32AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData)\r
+\r
+#define McD0PciCfg16(Register) QNCMmPci16 (0, MC_BUS, 0, 0, Register)\r
+#define McD0PciCfg16Or(Register, OrData) QNCMmPci16Or (0, MC_BUS, 0, 0, Register, OrData)\r
+#define McD0PciCfg16And(Register, AndData) QNCMmPci16And (0, MC_BUS, 0, 0, Register, AndData)\r
+#define McD0PciCfg16AndThenOr(Register, AndData, OrData) QNCMmPci16AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData)\r
+\r
+#define McD0PciCfg8(Register) QNCMmPci8 (0, MC_BUS, 0, 0, Register)\r
+#define McD0PciCfg8Or(Register, OrData) QNCMmPci8Or (0, MC_BUS, 0, 0, Register, OrData)\r
+#define McD0PciCfg8And(Register, AndData) QNCMmPci8And (0, MC_BUS, 0, 0, Register, AndData)\r
+#define McD0PciCfg8AndThenOr( Register, AndData, OrData ) QNCMmPci8AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData)\r
+\r
+\r
+//\r
+// Memory Controller Hub Memory Mapped IO register access ???\r
+//\r
+#define MCH_REGION_BASE (McD0PciCfg64 (MC_MCHBAR_OFFSET) & ~BIT0)\r
+#define McMmioAddress(Register) ((UINTN) MCH_REGION_BASE + (UINTN) (Register))\r
+\r
+#define McMmio32Ptr(Register) ((volatile UINT32*) McMmioAddress (Register))\r
+#define McMmio64Ptr(Register) ((volatile UINT64*) McMmioAddress (Register))\r
+\r
+#define McMmio64(Register) *McMmio64Ptr( Register )\r
+#define McMmio64Or(Register, OrData) (McMmio64 (Register) |= (UINT64)(OrData))\r
+#define McMmio64And(Register, AndData) (McMmio64 (Register) &= (UINT64)(AndData))\r
+#define McMmio64AndThenOr(Register, AndData, OrData) (McMmio64 ( Register ) = (McMmio64( Register ) & (UINT64)(AndData)) | (UINT64)(OrData))\r
+\r
+#define McMmio32(Register) *McMmio32Ptr (Register)\r
+#define McMmio32Or(Register, OrData) (McMmio32 (Register) |= (UINT32)(OrData))\r
+#define McMmio32And(Register, AndData) (McMmio32 (Register) &= (UINT32)(AndData))\r
+#define McMmio32AndThenOr(Register, AndData, OrData) (McMmio32 (Register) = (McMmio32 (Register) & (UINT32) (AndData)) | (UINT32) (OrData))\r
+\r
+#define McMmio16Ptr(Register) ((volatile UINT16*) McMmioAddress (Register))\r
+#define McMmio16(Register) *McMmio16Ptr (Register)\r
+#define McMmio16Or(Register, OrData) (McMmio16 (Register) |= (UINT16) (OrData))\r
+#define McMmio16And(Register, AndData) (McMmio16 (Register) &= (UINT16) (AndData))\r
+#define McMmio16AndThenOr(Register, AndData, OrData) (McMmio16 (Register) = (McMmio16 (Register) & (UINT16) (AndData)) | (UINT16) (OrData))\r
+\r
+#define McMmio8Ptr(Register) ((volatile UINT8 *)McMmioAddress (Register))\r
+#define McMmio8(Register) *McMmio8Ptr (Register)\r
+#define McMmio8Or(Register, OrData) (McMmio8 (Register) |= (UINT8) (OrData))\r
+#define McMmio8And(Register, AndData) (McMmio8 (Register) &= (UINT8) (AndData))\r
+#define McMmio8AndThenOr(Register, AndData, OrData) (McMmio8 (Register) = (McMmio8 (Register) & (UINT8) (AndData)) | (UINT8) (OrData))\r
+\r
+//\r
+// QNC memory mapped related data structure deifinition\r
+//\r
+typedef enum {\r
+ QNCMmioWidthUint8 = 0,\r
+ QNCMmioWidthUint16 = 1,\r
+ QNCMmioWidthUint32 = 2,\r
+ QNCMmioWidthUint64 = 3,\r
+ QNCMmioWidthMaximum\r
+} QNC_MEM_IO_WIDTH;\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+This header file provides common definitions just for MCH using to avoid including extra module's file.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _QNC_COMMON_DEFINITIONS_H_\r
+#define _QNC_COMMON_DEFINITIONS_H_\r
+\r
+//\r
+// PCI CONFIGURATION MAP REGISTER OFFSETS\r
+//\r
+#ifndef PCI_VID\r
+#define PCI_VID 0x0000 // Vendor ID Register\r
+#define PCI_DID 0x0002 // Device ID Register\r
+#define PCI_CMD 0x0004 // PCI Command Register\r
+#define PCI_STS 0x0006 // PCI Status Register\r
+#define PCI_RID 0x0008 // Revision ID Register\r
+#define PCI_IFT 0x0009 // Interface Type\r
+#define PCI_SCC 0x000A // Sub Class Code Register\r
+#define PCI_BCC 0x000B // Base Class Code Register\r
+#define PCI_CLS 0x000C // Cache Line Size\r
+#define PCI_PMLT 0x000D // Primary Master Latency Timer\r
+#define PCI_HDR 0x000E // Header Type Register\r
+#define PCI_BIST 0x000F // Built in Self Test Register\r
+#define PCI_BAR0 0x0010 // Base Address Register 0\r
+#define PCI_BAR1 0x0014 // Base Address Register 1\r
+#define PCI_BAR2 0x0018 // Base Address Register 2\r
+#define PCI_PBUS 0x0018 // Primary Bus Number Register\r
+#define PCI_SBUS 0x0019 // Secondary Bus Number Register\r
+#define PCI_SUBUS 0x001A // Subordinate Bus Number Register\r
+#define PCI_SMLT 0x001B // Secondary Master Latency Timer\r
+#define PCI_BAR3 0x001C // Base Address Register 3\r
+#define PCI_IOBASE 0x001C // I/O base Register\r
+#define PCI_IOLIMIT 0x001D // I/O Limit Register\r
+#define PCI_SECSTATUS 0x001E // Secondary Status Register\r
+#define PCI_BAR4 0x0020 // Base Address Register 4\r
+#define PCI_MEMBASE 0x0020 // Memory Base Register\r
+#define PCI_MEMLIMIT 0x0022 // Memory Limit Register\r
+#define PCI_BAR5 0x0024 // Base Address Register 5\r
+#define PCI_PRE_MEMBASE 0x0024 // Prefetchable memory Base register\r
+#define PCI_PRE_MEMLIMIT 0x0026 // Prefetchable memory Limit register\r
+#define PCI_PRE_MEMBASE_U 0x0028 // Prefetchable memory base upper 32 bits\r
+#define PCI_PRE_MEMLIMIT_U 0x002C // Prefetchable memory limit upper 32 bits\r
+#define PCI_SVID 0x002C // Subsystem Vendor ID\r
+#define PCI_SID 0x002E // Subsystem ID\r
+#define PCI_IOBASE_U 0x0030 // I/O base Upper Register\r
+#define PCI_IOLIMIT_U 0x0032 // I/O Limit Upper Register\r
+#define PCI_CAPP 0x0034 // Capabilities Pointer\r
+#define PCI_EROM 0x0038 // Expansion ROM Base Address\r
+#define PCI_INTLINE 0x003C // Interrupt Line Register\r
+#define PCI_INTPIN 0x003D // Interrupt Pin Register\r
+#define PCI_MAXGNT 0x003E // Max Grant Register\r
+#define PCI_BRIDGE_CNTL 0x003E // Bridge Control Register\r
+#define PCI_MAXLAT 0x003F // Max Latency Register\r
+#endif\r
+//\r
+// Bit Difinitions\r
+//\r
+#ifndef BIT0\r
+#define BIT0 0x0001\r
+#define BIT1 0x0002\r
+#define BIT2 0x0004\r
+#define BIT3 0x0008\r
+#define BIT4 0x0010\r
+#define BIT5 0x0020\r
+#define BIT6 0x0040\r
+#define BIT7 0x0080\r
+#define BIT8 0x0100\r
+#define BIT9 0x0200\r
+#define BIT10 0x0400\r
+#define BIT11 0x0800\r
+#define BIT12 0x1000\r
+#define BIT13 0x2000\r
+#define BIT14 0x4000\r
+#define BIT15 0x8000\r
+#define BIT16 0x00010000\r
+#define BIT17 0x00020000\r
+#define BIT18 0x00040000\r
+#define BIT19 0x00080000\r
+#define BIT20 0x00100000\r
+#define BIT21 0x00200000\r
+#define BIT22 0x00400000\r
+#define BIT23 0x00800000\r
+#define BIT24 0x01000000\r
+#define BIT25 0x02000000\r
+#define BIT26 0x04000000\r
+#define BIT27 0x08000000\r
+#define BIT28 0x10000000\r
+#define BIT29 0x20000000\r
+#define BIT30 0x40000000\r
+#define BIT31 0x80000000\r
+#endif\r
+\r
+\r
+//\r
+// Common Memory mapped Io access macros ------------------------------------------\r
+//\r
+#define QNCMmioAddress( BaseAddr, Register ) \\r
+ ( (UINTN)BaseAddr + \\r
+ (UINTN)(Register) \\r
+ )\r
+\r
+//\r
+// UINT64\r
+//\r
+#define QNCMmio64Ptr( BaseAddr, Register ) \\r
+ ( (volatile UINT64 *)QNCMmioAddress( BaseAddr, Register ) )\r
+\r
+#define QNCMmio64( BaseAddr, Register ) \\r
+ *QNCMmio64Ptr( BaseAddr, Register )\r
+\r
+#define QNCMmio64Or( BaseAddr, Register, OrData ) \\r
+ QNCMmio64( BaseAddr, Register ) = \\r
+ (UINT64) ( \\r
+ QNCMmio64( BaseAddr, Register ) | \\r
+ (UINT64)(OrData) \\r
+ )\r
+\r
+#define QNCMmio64And( BaseAddr, Register, AndData ) \\r
+ QNCMmio64( BaseAddr, Register ) = \\r
+ (UINT64) ( \\r
+ QNCMmio64( BaseAddr, Register ) & \\r
+ (UINT64)(AndData) \\r
+ )\r
+\r
+#define QNCMmio64AndThenOr( BaseAddr, Register, AndData, OrData ) \\r
+ QNCMmio64( BaseAddr, Register ) = \\r
+ (UINT64) ( \\r
+ ( QNCMmio64( BaseAddr, Register ) & \\r
+ (UINT64)(AndData) \\r
+ ) | \\r
+ (UINT64)(OrData) \\r
+ )\r
+\r
+//\r
+// UINT32\r
+//\r
+#define QNCMmio32Ptr( BaseAddr, Register ) \\r
+ ( (volatile UINT32 *)QNCMmioAddress( BaseAddr, Register ) )\r
+\r
+#define QNCMmio32( BaseAddr, Register ) \\r
+ *QNCMmio32Ptr( BaseAddr, Register )\r
+\r
+#define QNCMmio32Or( BaseAddr, Register, OrData ) \\r
+ QNCMmio32( BaseAddr, Register ) = \\r
+ (UINT32) ( \\r
+ QNCMmio32( BaseAddr, Register ) | \\r
+ (UINT32)(OrData) \\r
+ )\r
+\r
+#define QNCMmio32And( BaseAddr, Register, AndData ) \\r
+ QNCMmio32( BaseAddr, Register ) = \\r
+ (UINT32) ( \\r
+ QNCMmio32( BaseAddr, Register ) & \\r
+ (UINT32)(AndData) \\r
+ )\r
+\r
+#define QNCMmio32AndThenOr( BaseAddr, Register, AndData, OrData ) \\r
+ QNCMmio32( BaseAddr, Register ) = \\r
+ (UINT32) ( \\r
+ ( QNCMmio32( BaseAddr, Register ) & \\r
+ (UINT32)(AndData) \\r
+ ) | \\r
+ (UINT32)(OrData) \\r
+ )\r
+//\r
+// UINT16\r
+//\r
+\r
+#define QNCMmio16Ptr( BaseAddr, Register ) \\r
+ ( (volatile UINT16 *)QNCMmioAddress( BaseAddr, Register ) )\r
+\r
+#define QNCMmio16( BaseAddr, Register ) \\r
+ *QNCMmio16Ptr( BaseAddr, Register )\r
+\r
+#define QNCMmio16Or( BaseAddr, Register, OrData ) \\r
+ QNCMmio16( BaseAddr, Register ) = \\r
+ (UINT16) ( \\r
+ QNCMmio16( BaseAddr, Register ) | \\r
+ (UINT16)(OrData) \\r
+ )\r
+\r
+#define QNCMmio16And( BaseAddr, Register, AndData ) \\r
+ QNCMmio16( BaseAddr, Register ) = \\r
+ (UINT16) ( \\r
+ QNCMmio16( BaseAddr, Register ) & \\r
+ (UINT16)(AndData) \\r
+ )\r
+\r
+#define QNCMmio16AndThenOr( BaseAddr, Register, AndData, OrData ) \\r
+ QNCMmio16( BaseAddr, Register ) = \\r
+ (UINT16) ( \\r
+ ( QNCMmio16( BaseAddr, Register ) & \\r
+ (UINT16)(AndData) \\r
+ ) | \\r
+ (UINT16)(OrData) \\r
+ )\r
+//\r
+// UINT8\r
+//\r
+#define QNCMmio8Ptr( BaseAddr, Register ) \\r
+ ( (volatile UINT8 *)QNCMmioAddress( BaseAddr, Register ) )\r
+\r
+#define QNCMmio8( BaseAddr, Register ) \\r
+ *QNCMmio8Ptr( BaseAddr, Register )\r
+\r
+#define QNCMmio8Or( BaseAddr, Register, OrData ) \\r
+ QNCMmio8( BaseAddr, Register ) = \\r
+ (UINT8) ( \\r
+ QNCMmio8( BaseAddr, Register ) | \\r
+ (UINT8)(OrData) \\r
+ )\r
+\r
+#define QNCMmio8And( BaseAddr, Register, AndData ) \\r
+ QNCMmio8( BaseAddr, Register ) = \\r
+ (UINT8) ( \\r
+ QNCMmio8( BaseAddr, Register ) & \\r
+ (UINT8)(AndData) \\r
+ )\r
+\r
+#define QNCMmio8AndThenOr( BaseAddr, Register, AndData, OrData ) \\r
+ QNCMmio8( BaseAddr, Register ) = \\r
+ (UINT8) ( \\r
+ ( QNCMmio8( BaseAddr, Register ) & \\r
+ (UINT8)(AndData) \\r
+ ) | \\r
+ (UINT8)(OrData) \\r
+ )\r
+\r
+//\r
+// Common Memory mapped Pci access macros ------------------------------------------\r
+//\r
+\r
+#define QNCMmPciAddress( Segment, Bus, Device, Function, Register ) \\r
+ ( (UINTN) QncGetPciExpressBaseAddress() + \\r
+ (UINTN)(Bus << 20) + \\r
+ (UINTN)(Device << 15) + \\r
+ (UINTN)(Function << 12) + \\r
+ (UINTN)(Register) \\r
+ )\r
+\r
+//\r
+// Macro to calculate the Pci device's base memory mapped address\r
+//\r
+#define PciDeviceMmBase( Bus, Device, Function) \\r
+ ( (UINTN) QncGetPciExpressBaseAddress () + \\r
+ (UINTN)(Bus << 20) + \\r
+ (UINTN)(Device << 15) + \\r
+ (UINTN)(Function << 12) \\r
+ )\r
+\r
+//\r
+// UINT32\r
+//\r
+#define QNCMmPci32Ptr( Segment, Bus, Device, Function, Register ) \\r
+ ( (volatile UINT32 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) )\r
+\r
+#define QNCMmPci32( Segment, Bus, Device, Function, Register ) \\r
+ *QNCMmPci32Ptr( Segment, Bus, Device, Function, Register )\r
+\r
+#define QNCMmPci32Or( Segment, Bus, Device, Function, Register, OrData ) \\r
+ QNCMmPci32( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT32) ( \\r
+ QNCMmPci32( Segment, Bus, Device, Function, Register ) | \\r
+ (UINT32)(OrData) \\r
+ )\r
+\r
+#define QNCMmPci32And( Segment, Bus, Device, Function, Register, AndData ) \\r
+ QNCMmPci32( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT32) ( \\r
+ QNCMmPci32( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT32)(AndData) \\r
+ )\r
+\r
+#define QNCMmPci32AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \\r
+ QNCMmPci32( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT32) ( \\r
+ ( QNCMmPci32( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT32)(AndData) \\r
+ ) | \\r
+ (UINT32)(OrData) \\r
+ )\r
+//\r
+// UINT16\r
+//\r
+#define QNCMmPci16Ptr( Segment, Bus, Device, Function, Register ) \\r
+ ( (volatile UINT16 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) )\r
+\r
+#define QNCMmPci16( Segment, Bus, Device, Function, Register ) \\r
+ *QNCMmPci16Ptr( Segment, Bus, Device, Function, Register )\r
+\r
+#define QNCMmPci16Or( Segment, Bus, Device, Function, Register, OrData ) \\r
+ QNCMmPci16( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT16) ( \\r
+ QNCMmPci16( Segment, Bus, Device, Function, Register ) | \\r
+ (UINT16)(OrData) \\r
+ )\r
+\r
+#define QNCMmPci16And( Segment, Bus, Device, Function, Register, AndData ) \\r
+ QNCMmPci16( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT16) ( \\r
+ QNCMmPci16( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT16)(AndData) \\r
+ )\r
+\r
+#define QNCMmPci16AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \\r
+ QNCMmPci16( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT16) ( \\r
+ ( QNCMmPci16( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT16)(AndData) \\r
+ ) | \\r
+ (UINT16)(OrData) \\r
+ )\r
+//\r
+// UINT8\r
+//\r
+#define QNCMmPci8Ptr( Segment, Bus, Device, Function, Register ) \\r
+ ( (volatile UINT8 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) )\r
+\r
+#define QNCMmPci8( Segment, Bus, Device, Function, Register ) \\r
+ *QNCMmPci8Ptr( Segment, Bus, Device, Function, Register )\r
+\r
+#define QNCMmPci8Or( Segment, Bus, Device, Function, Register, OrData ) \\r
+ QNCMmPci8( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT8) ( \\r
+ QNCMmPci8( Segment, Bus, Device, Function, Register ) | \\r
+ (UINT8)(OrData) \\r
+ )\r
+\r
+#define QNCMmPci8And( Segment, Bus, Device, Function, Register, AndData ) \\r
+ QNCMmPci8( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT8) ( \\r
+ QNCMmPci8( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT8)(AndData) \\r
+ )\r
+\r
+#define QNCMmPci8AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \\r
+ QNCMmPci8( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT8) ( \\r
+ ( QNCMmPci8( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT8)(AndData) \\r
+ ) | \\r
+ (UINT8)(OrData) \\r
+ )\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+QuarkNcSocId Register Definitions\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Definitions beginning with "R_" are registers\r
+Definitions beginning with "B_" are bits within registers\r
+Definitions beginning with "V_" are meaningful values of bits within the registers\r
+Definitions beginning with "S_" are register sizes\r
+Definitions beginning with "N_" are the bit position\r
+\r
+**/\r
+\r
+#ifndef _QUARK_NC_SOC_ID_H_\r
+#define _QUARK_NC_SOC_ID_H_\r
+\r
+//\r
+// QNC GMCH Equates\r
+//\r
+\r
+//\r
+// DEVICE 0 (Memroy Controller Hub)\r
+//\r
+#define MC_BUS PCI_BUS_NUMBER_QNC\r
+#define MC_DEV 0x00\r
+#define MC_FUN 0x00\r
+\r
+#define QUARK_MC_VENDOR_ID V_INTEL_VENDOR_ID\r
+#define QUARK_MC_DEVICE_ID 0x0958\r
+#define QUARK2_MC_DEVICE_ID 0x12C0\r
+#define QNC_MC_REV_ID_A0 0x00\r
+\r
+\r
+//\r
+// MCR - B0:D0:F0:RD0h (WO)- Message control register\r
+// [31:24] Message opcode - D0 read; E0 write;\r
+// [23:16] Message port\r
+// [15:8 ] Message target register address\r
+// [ 7:4 ] Message write byte enable : F is enable\r
+// [ 3:0 ] Reserved\r
+//\r
+#define QNC_ACCESS_PORT_MCR 0xD0 // Message Control Register\r
+// Always Set to 0xF0\r
+\r
+//\r
+//MDR - B0:D0:F0:RD4h (RW)- Message data register\r
+//\r
+#define QNC_ACCESS_PORT_MDR 0xD4 // Message Data Register\r
+\r
+//\r
+//MEA - B0:D0:F0:RD8h (RW)- Message extended address register\r
+//\r
+#define QNC_ACCESS_PORT_MEA 0xD8 // Message Extended Address Register\r
+\r
+#define QNC_MCR_OP_OFFSET 24 // Offset of the opcode field in MCR\r
+#define QNC_MCR_PORT_OFFSET 16 // Offset of the port field in MCR\r
+#define QNC_MCR_REG_OFFSET 8 // Offset of the register field in MCR\r
+\r
+//\r
+// Misc Useful Macros\r
+//\r
+\r
+#define LShift16(value) (value << 16)\r
+\r
+//\r
+// QNC Message OpCodes and Attributes\r
+//\r
+#define QUARK_OPCODE_READ 0x10 // Quark message bus "read" opcode\r
+#define QUARK_OPCODE_WRITE 0x11 // Quark message bus "write" opcode\r
+\r
+//\r
+// Alternative opcodes for the SCSS block\r
+//\r
+#define QUARK_ALT_OPCODE_READ 0x06 // Quark message bus "read" opcode\r
+#define QUARK_ALT_OPCODE_WRITE 0x07 // Quark message bus "write" opcode\r
+\r
+//\r
+// QNC Message OpCodes and Attributes for IO\r
+//\r
+#define QUARK_OPCODE_IO_READ 0x02 // Quark message bus "IO read" opcode\r
+#define QUARK_OPCODE_IO_WRITE 0x03 // Quark message bus "IO write" opcode\r
+\r
+\r
+#define QUARK_DRAM_BASE_ADDR_READY 0x78 // Quark message bus "RMU Main binary shadow" opcode\r
+\r
+#define QUARK_ECC_SCRUB_RESUME 0xC2 // Quark Remote Management Unit "scrub resume" opcode\r
+#define QUARK_ECC_SCRUB_PAUSE 0xC3 // Quark Remote Management Unit "scrub pause" opcode\r
+\r
+//\r
+// QNC Message Ports and Registers\r
+//\r
+// Start of SB Port IDs\r
+#define QUARK_NC_MEMORY_ARBITER_SB_PORT_ID 0x00\r
+#define QUARK_NC_MEMORY_CONTROLLER_SB_PORT_ID 0x01\r
+#define QUARK_NC_HOST_BRIDGE_SB_PORT_ID 0x03\r
+#define QUARK_NC_RMU_SB_PORT_ID 0x04\r
+#define QUARK_NC_MEMORY_MANAGER_SB_PORT_ID 0x05\r
+#define QUARK_SC_USB_AFE_SB_PORT_ID 0x14\r
+#define QUARK_SC_PCIE_AFE_SB_PORT_ID 0x16\r
+#define QUARK_SCSS_SOC_UNIT_SB_PORT_ID 0x31\r
+#define QUARK_SCSS_FUSE_SB_PORT_ID 0x33\r
+#define QUARK_ICLK_SB_PORT_ID 0x32\r
+#define QUARK_SCSS_CRU_SB_PORT_ID 0x34\r
+\r
+//\r
+// Quark Memory Arbiter Registers.\r
+//\r
+#define QUARK_NC_MEMORY_ARBITER_REG_ASTATUS 0x21 // Memory Arbiter PRI Status encodings register.\r
+#define ASTATUS_PRI_CASUAL 0x0 // Serviced only if convenient\r
+#define ASTATUS_PRI_IMPENDING 0x1 // Serviced if the DRAM is in Self-Refresh.\r
+#define ASTATUS_PRI_NORMAL 0x2 // Normal request servicing.\r
+#define ASTATUS_PRI_URGENT 0x3 // Urgent request servicing.\r
+#define ASTATUS1_RASISED_BP (10)\r
+#define ASTATUS1_RASISED_BP_MASK (0x03 << ASTATUS1_RASISED_BP)\r
+#define ASTATUS0_RASISED_BP (8)\r
+#define ASTATUS0_RASISED_BP_MASK (0x03 << ASTATUS1_RASISED_BP)\r
+#define ASTATUS1_DEFAULT_BP (2)\r
+#define ASTATUS1_DEFAULT_BP_MASK (0x03 << ASTATUS1_RASISED_BP)\r
+#define ASTATUS0_DEFAULT_BP (0)\r
+#define ASTATUS0_DEFAULT_BP_MASK (0x03 << ASTATUS1_RASISED_BP)\r
+\r
+//\r
+// Quark Memory Controller Registers.\r
+//\r
+#define QUARK_NC_MEMORY_CONTROLLER_REG_DFUSESTAT 0x70 // Fuse status register.\r
+#define B_DFUSESTAT_ECC_DIS (BIT0) // Disable ECC.\r
+\r
+//\r
+// Quark Remote Management Unit Registers.\r
+//\r
+#define QNC_MSG_TMPM_REG_PMBA 0x70 // Power Management I/O Base Address\r
+\r
+#define QUARK_NC_RMU_REG_CONFIG 0x71 // Remote Management Unit configuration register.\r
+#define TS_LOCK_AUX_TRIP_PT_REGS_ENABLE (BIT6)\r
+#define TS_LOCK_THRM_CTRL_REGS_ENABLE (BIT5)\r
+\r
+#define QUARK_NC_RMU_REG_OPTIONS_1 0x72 // Remote Management Unit Options register 1.\r
+#define OPTIONS_1_DMA_DISABLE (BIT0)\r
+\r
+#define QUARK_NC_RMU_REG_WDT_CONTROL 0x74 // Remote Management Unit Watchdog control register.\r
+#define B_WDT_CONTROL_DBL_ECC_BIT_ERR_MASK (BIT19 | BIT18)\r
+#define B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP 18\r
+#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_NONE (0x0 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)\r
+#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_CAT (0x1 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)\r
+#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_WARM (0x2 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)\r
+#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_SERR (0x3 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)\r
+\r
+#define QUARK_NC_RMU_REG_TS_MODE 0xB0 // Remote Management Unit Thermal sensor mode register.\r
+#define TS_ENABLE (BIT15)\r
+#define QUARK_NC_RMU_REG_TS_TRIP 0xB2 // Remote Management Unit Thermal sensor programmable trip point register.\r
+#define TS_HOT_TRIP_CLEAR_THOLD_BP 24\r
+#define TS_HOT_TRIP_CLEAR_THOLD_MASK (0xFF << TS_HOT_TRIP_CLEAR_THOLD_BP)\r
+#define TS_CAT_TRIP_CLEAR_THOLD_BP 16\r
+#define TS_CAT_TRIP_CLEAR_THOLD_MASK (0xFF << TS_CAT_TRIP_CLEAR_THOLD_BP)\r
+#define TS_HOT_TRIP_SET_THOLD_BP 8\r
+#define TS_HOT_TRIP_SET_THOLD_MASK (0xFF << TS_HOT_TRIP_SET_THOLD_BP)\r
+#define TS_CAT_TRIP_SET_THOLD_BP 0\r
+#define TS_CAT_TRIP_SET_THOLD_MASK (0xFF << TS_CAT_TRIP_SET_THOLD_BP)\r
+\r
+#define QUARK_NC_ECC_SCRUB_CONFIG_REG 0x50\r
+#define SCRUB_CFG_INTERVAL_SHIFT 0x00\r
+#define SCRUB_CFG_INTERVAL_MASK 0xFF\r
+#define SCRUB_CFG_BLOCKSIZE_SHIFT 0x08\r
+#define SCRUB_CFG_BLOCKSIZE_MASK 0x1F\r
+#define SCRUB_CFG_ACTIVE (BIT13)\r
+#define SCRUB_CFG_INVALID 0x00000FFF\r
+\r
+#define QUARK_NC_ECC_SCRUB_START_MEM_REG 0x76\r
+#define QUARK_NC_ECC_SCRUB_END_MEM_REG 0x77\r
+#define QUARK_NC_ECC_SCRUB_NEXT_READ_REG 0x7C\r
+\r
+#define SCRUB_RESUME_MSG() ((UINT32)( \\r
+ (QUARK_ECC_SCRUB_RESUME << QNC_MCR_OP_OFFSET) | \\r
+ (QUARK_NC_RMU_SB_PORT_ID << QNC_MCR_PORT_OFFSET) | \\r
+ 0xF0))\r
+\r
+#define SCRUB_PAUSE_MSG() ((UINT32)( \\r
+ (QUARK_ECC_SCRUB_PAUSE << QNC_MCR_OP_OFFSET) | \\r
+ (QUARK_NC_RMU_SB_PORT_ID << QNC_MCR_PORT_OFFSET) | \\r
+ 0xF0))\r
+\r
+//\r
+// Quark Memory Manager Registers\r
+//\r
+#define QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK 0x82\r
+#define BLOCK_ENABLE_PG (1 << 28)\r
+#define BLOCK_DISABLE_PG (1 << 29)\r
+#define QUARK_NC_MEMORY_MANAGER_BIMRVCTL 0x19\r
+#define EnableIMRInt BIT31\r
+#define QUARK_NC_MEMORY_MANAGER_BSMMVCTL 0x1C\r
+#define EnableSMMInt BIT31\r
+#define QUARK_NC_MEMORY_MANAGER_BTHCTRL 0x20\r
+#define DRAM_NON_HOST_RQ_LIMIT_BP 0\r
+#define DRAM_NON_HOST_RQ_LIMIT_MASK (0x3f << DRAM_NON_HOST_RQ_LIMIT_BP)\r
+\r
+#define QUARK_NC_TOTAL_IMR_SET 0x8\r
+#define QUARK_NC_MEMORY_MANAGER_IMR0 0x40\r
+#define QUARK_NC_MEMORY_MANAGER_IMR1 0x44\r
+#define QUARK_NC_MEMORY_MANAGER_IMR2 0x48\r
+#define QUARK_NC_MEMORY_MANAGER_IMR3 0x4C\r
+#define QUARK_NC_MEMORY_MANAGER_IMR4 0x50\r
+#define QUARK_NC_MEMORY_MANAGER_IMR5 0x54\r
+#define QUARK_NC_MEMORY_MANAGER_IMR6 0x58\r
+#define QUARK_NC_MEMORY_MANAGER_IMR7 0x5C\r
+ #define QUARK_NC_MEMORY_MANAGER_IMRXL 0x00\r
+ #define IMR_LOCK BIT31\r
+ #define IMR_EN BIT30\r
+ #define IMRL_MASK 0x00FFFFFC\r
+ #define IMRL_RESET 0x00000000\r
+ #define QUARK_NC_MEMORY_MANAGER_IMRXH 0x01\r
+ #define IMRH_MASK 0x00FFFFFC\r
+ #define IMRH_RESET 0x00000000\r
+ #define QUARK_NC_MEMORY_MANAGER_IMRXRM 0x02\r
+ #define QUARK_NC_MEMORY_MANAGER_IMRXWM 0x03\r
+ #define IMRX_ALL_ACCESS 0xFFFFFFFF\r
+ #define CPU_SNOOP BIT30\r
+ #define RMU BIT29\r
+ #define CPU0_NON_SMM BIT0\r
+\r
+//\r
+// Quark Host Bridge Registers\r
+//\r
+#define QNC_MSG_FSBIC_REG_HMISC 0x03 // Host Misellaneous Controls\r
+#define SMI_EN (BIT19) // SMI Global Enable (from Legacy Bridge)\r
+#define QNC_MSG_FSBIC_REG_HSMMC 0x04 // Host SMM Control\r
+#define NON_HOST_SMM_WR_OPEN (BIT18) // SMM Writes OPEN\r
+#define NON_HOST_SMM_RD_OPEN (BIT17) // SMM Writes OPEN\r
+#define SMM_CODE_RD_OPEN (BIT16) // SMM Code read OPEN\r
+#define SMM_CTL_EN (BIT3) // SMM enable\r
+#define SMM_WRITE_OPEN (BIT2) // SMM Writes OPEN\r
+#define SMM_READ_OPEN (BIT1) // SMM Reads OPEN\r
+#define SMM_LOCKED (BIT0) // SMM Locked\r
+#define SMM_START_MASK 0x0000FFF0\r
+#define SMM_END_MASK 0xFFF00000\r
+#define QUARK_NC_HOST_BRIDGE_HMBOUND_REG 0x08\r
+#define HMBOUND_MASK 0x0FFFFF000\r
+#define HMBOUND_LOCK BIT0\r
+#define QUARK_NC_HOST_BRIDGE_HLEGACY_REG 0x0A\r
+#define HLEGACY_SMI_PIN_VALUE BIT12\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_CAP 0x40\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE 0x41\r
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 0x42\r
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_80000 0x44\r
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_A0000 0x46\r
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C0000 0x48\r
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C8000 0x4A\r
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D0000 0x4C\r
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D8000 0x4E\r
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E0000 0x50\r
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E8000 0x52\r
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F0000 0x54\r
+#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000 0x56\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSBASE 0x58\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK 0x59\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 0x5A\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK0 0x5B\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE1 0x5C\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK1 0x5D\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE2 0x5E\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK2 0x5F\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE3 0x60\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK3 0x61\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE4 0x62\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK4 0x63\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE5 0x64\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK5 0x65\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE6 0x66\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK6 0x67\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE7 0x68\r
+#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK7 0x69\r
+\r
+//\r
+// System On Chip Unit (SOCUnit) Registers.\r
+//\r
+#define QUARK_SCSS_SOC_UNIT_STPDDRCFG 0x00\r
+#define B_STPDDRCFG_FORCE_RECOVERY BIT0\r
+#define QUARK_SCSS_SOC_UNIT_SPI_ROM_FUSE 0x25\r
+#define B_ROM_FUSE_IN_SECURE_SKU BIT6\r
+\r
+#define QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG 0x31\r
+#define B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK (BIT5 | BIT4 | BIT3)\r
+#define B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP 3\r
+#define B_TSCGF1_CONFIG_ISNSCHOPSEL_MASK (BIT12 | BIT11 | BIT10 | BIT9 | BIT8)\r
+#define B_TSCGF1_CONFIG_ISNSCHOPSEL_BP 8\r
+#define B_TSCGF1_CONFIG_IBGEN BIT17\r
+#define B_TSCGF1_CONFIG_IBGEN_BP 17\r
+#define B_TSCGF1_CONFIG_IBGCHOPEN BIT18\r
+#define B_TSCGF1_CONFIG_IBGCHOPEN_BP 18\r
+#define B_TSCGF1_CONFIG_ISNSINTERNALVREFEN BIT14\r
+#define B_TSCGF1_CONFIG_ISNSINTERNALVREFEN_BP 14\r
+\r
+#define QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG 0x32\r
+#define B_TSCGF2_CONFIG_IDSCONTROL_MASK 0x0000FFFF\r
+#define B_TSCGF2_CONFIG_IDSCONTROL_BP 0\r
+#define B_TSCGF2_CONFIG_IDSTIMING_MASK 0xFFFF0000\r
+#define B_TSCGF2_CONFIG_IDSTIMING_BP 16\r
+\r
+#define QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2 0x33\r
+#define B_TSCGF2_CONFIG2_ISPARECTRL_MASK 0xFF000000\r
+#define B_TSCGF2_CONFIG2_ISPARECTRL_BP 24\r
+#define B_TSCGF2_CONFIG2_ICALCONFIGSEL_MASK (BIT9 | BIT8)\r
+#define B_TSCGF2_CONFIG2_ICALCONFIGSEL_BP 8\r
+#define B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK 0x000000FF\r
+#define B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP 0\r
+\r
+#define QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG 0x34\r
+#define B_TSCGF3_CONFIG_ITSRST BIT0\r
+#define B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP 11\r
+#define B_TSCGF3_CONFIG_ITSGAMMACOEFF_MASK (0xFFF << B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP)\r
+\r
+#define QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG 0x36\r
+#define SOCCLKEN_CONFIG_PHY_I_SIDE_RST_L BIT20\r
+#define SOCCLKEN_CONFIG_PHY_I_CMNRESET_L BIT19\r
+#define SOCCLKEN_CONFIG_SBI_BB_RST_B BIT18\r
+#define SOCCLKEN_CONFIG_SBI_RST_100_CORE_B BIT17\r
+#define SOCCLKEN_CONFIG_BB_RST_B BIT16\r
+\r
+#define QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG 0x36\r
+\r
+#define QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW 0x51\r
+#define B_CFG_STICKY_RW_SMM_VIOLATION BIT0\r
+#define B_CFG_STICKY_RW_HMB_VIOLATION BIT1\r
+#define B_CFG_STICKY_RW_IMR_VIOLATION BIT2\r
+#define B_CFG_STICKY_RW_DECC_VIOLATION BIT3\r
+#define B_CFG_STICKY_RW_WARM_RST BIT4\r
+#define B_CFG_STICKY_RW_FORCE_RECOVERY BIT9\r
+#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)\r
+#define B_CFG_STICKY_RW_ALL (B_CFG_STICKY_RW_VIOLATION | B_CFG_STICKY_RW_WARM_RST)\r
+\r
+//\r
+// iCLK Registers.\r
+//\r
+#define QUARK_ICLK_MUXTOP 0x0140\r
+#define B_MUXTOP_FLEX2_MASK (BIT25 | BIT24 | BIT23)\r
+#define B_MUXTOP_FLEX2_BP 23\r
+#define B_MUXTOP_FLEX1_MASK (BIT22 | BIT21 | BIT20)\r
+#define B_MUXTOP_FLEX1_BP 20\r
+\r
+#define QUARK_ICLK_SSC1 0x0314\r
+#define QUARK_ICLK_SSC2 0x0414\r
+#define QUARK_ICLK_SSC3 0x0514\r
+#define QUARK_ICLK_REF2_DBUFF0 0x2000\r
+\r
+//\r
+// PCIe AFE Unit Registers (QUARK_SC_PCIE_AFE_SB_PORT_ID).\r
+//\r
+#define QUARK_PCIE_AFE_PCIE_RXPICTRL0_L0 0x2080\r
+#define QUARK_PCIE_AFE_PCIE_RXPICTRL0_L1 0x2180\r
+#define OCFGPIMIXLOAD_1_0 BIT6\r
+#define OCFGPIMIXLOAD_1_0_MASK 0xFFFFFF3F\r
+\r
+//\r
+// QNC ICH Equates\r
+//\r
+#define V_INTEL_VENDOR_ID 0x8086\r
+\r
+#define PCI_BUS_NUMBER_QNC 0x00\r
+\r
+//\r
+// PCI to LPC Bridge Registers (D31:F0)\r
+//\r
+#define PCI_DEVICE_NUMBER_QNC_LPC 31\r
+#define PCI_FUNCTION_NUMBER_QNC_LPC 0\r
+\r
+#define R_QNC_LPC_VENDOR_ID 0x00\r
+#define V_LPC_VENDOR_ID V_INTEL_VENDOR_ID\r
+#define R_QNC_LPC_DEVICE_ID 0x02\r
+#define QUARK_V_LPC_DEVICE_ID_0 0x095E\r
+#define R_QNC_LPC_REV_ID 0x08\r
+\r
+#define R_QNC_LPC_SMBUS_BASE 0x40 //~0x43\r
+#define B_QNC_LPC_SMBUS_BASE_EN (BIT31)\r
+#define B_QNC_LPC_SMBUS_BASE_MASK 0x0000FFC0 //[15:6]\r
+//\r
+// SMBus register offsets from SMBA - "SMBA" (D31:F0:R40h)\r
+// Suggested Value for SMBA = 0x1040\r
+//\r
+#define R_QNC_SMBUS_HCTL 0x00 // Host Control Register R/W\r
+#define B_QNC_SMBUS_START (BIT4) // Start/Stop\r
+#define V_QNC_SMBUS_HCTL_CMD_QUICK 0\r
+#define V_QNC_SMBUS_HCTL_CMD_BYTE 1\r
+#define V_QNC_SMBUS_HCTL_CMD_BYTE_DATA 2\r
+#define V_QNC_SMBUS_HCTL_CMD_WORD_DATA 3\r
+#define V_QNC_SMBUS_HCTL_CMD_PROCESS_CALL 4\r
+#define V_QNC_SMBUS_HCTL_CMD_BLOCK 5\r
+\r
+#define R_QNC_SMBUS_HSTS 0x01 // Host Status Register R/W\r
+#define B_QNC_SMBUS_BERR (BIT2) // BUS Error\r
+#define B_QNC_SMBUS_DERR (BIT1) // Device Error\r
+#define B_QNC_SMBUS_BYTE_DONE_STS (BIT0) // Completion Status\r
+#define B_QNC_SMBUS_HSTS_ALL 0x07\r
+\r
+#define R_QNC_SMBUS_HCLK 0x02 // Host Clock Divider Register R/W\r
+#define V_QNC_SMBUS_HCLK_100KHZ 0x0054\r
+\r
+#define R_QNC_SMBUS_TSA 0x04 // Transmit Slave Address Register R/W\r
+#define V_QNC_SMBUS_RW_SEL_READ 1\r
+#define V_QNC_SMBUS_RW_SEL_WRITE 0\r
+\r
+#define R_QNC_SMBUS_HCMD 0x05 // Host Command Register R/W\r
+#define R_QNC_SMBUS_HD0 0x06 // Data 0 Register R/W\r
+#define R_QNC_SMBUS_HD1 0x07 // Data 1 Register R/W\r
+#define R_QNC_SMBUS_HBD 0x20 // Host Block Data Register R/W [255:0] ~ 3Fh\r
+\r
+#define R_QNC_LPC_GBA_BASE 0x44\r
+#define B_QNC_LPC_GPA_BASE_MASK 0x0000FFC0\r
+//\r
+// GPIO register offsets from GBA - "GPIO" (D31:F0:R44h)\r
+// Suggested Value for GBA = 0x1080\r
+//\r
+#define R_QNC_GPIO_CGEN_CORE_WELL 0x00\r
+#define R_QNC_GPIO_CGIO_CORE_WELL 0x04\r
+#define R_QNC_GPIO_CGLVL_CORE_WELL 0x08\r
+#define R_QNC_GPIO_CGTPE_CORE_WELL 0x0C // Core well GPIO Trigger Positive Edge Enable\r
+#define R_QNC_GPIO_CGTNE_CORE_WELL 0x10 // Core well GPIO Trigger Negative Edge Enable\r
+#define R_QNC_GPIO_CGGPE_CORE_WELL 0x14 // Core well GPIO GPE Enable\r
+#define R_QNC_GPIO_CGSMI_CORE_WELL 0x18 // Core well GPIO SMI Enable\r
+#define R_QNC_GPIO_CGTS_CORE_WELL 0x1C // Core well GPIO Trigger Status\r
+#define R_QNC_GPIO_RGEN_RESUME_WELL 0x20\r
+#define R_QNC_GPIO_RGIO_RESUME_WELL 0x24\r
+#define R_QNC_GPIO_RGLVL_RESUME_WELL 0x28\r
+#define R_QNC_GPIO_RGTPE_RESUME_WELL 0x2C // Resume well GPIO Trigger Positive Edge Enable\r
+#define R_QNC_GPIO_RGTNE_RESUME_WELL 0x30 // Resume well GPIO Trigger Negative Edge Enable\r
+#define R_QNC_GPIO_RGGPE_RESUME_WELL 0x34 // Resume well GPIO GPE Enable\r
+#define R_QNC_GPIO_RGSMI_RESUME_WELL 0x38 // Resume well GPIO SMI Enable\r
+#define R_QNC_GPIO_RGTS_RESUME_WELL 0x3C // Resume well GPIO Trigger Status\r
+#define R_QNC_GPIO_CNMIEN_CORE_WELL 0x40 // Core well GPIO NMI Enable\r
+#define R_QNC_GPIO_RNMIEN_RESUME_WELL 0x44 // Resume well GPIO NMI Enable\r
+\r
+#define R_QNC_LPC_PM1BLK 0x48\r
+#define B_QNC_LPC_PM1BLK_MASK 0x0000FFF0\r
+//\r
+// ACPI register offsets from PM1BLK - "ACPI PM1 Block" (D31:F0:R48h)\r
+// Suggested Value for PM1BLK = 0x1000\r
+//\r
+#define R_QNC_PM1BLK_PM1S 0x00\r
+#define S_QNC_PM1BLK_PM1S 2\r
+#define B_QNC_PM1BLK_PM1S_ALL (BIT15+BIT14+BIT10+BIT5+BIT0)\r
+#define B_QNC_PM1BLK_PM1S_WAKE (BIT15)\r
+#define B_QNC_PM1BLK_PM1S_PCIEWSTS (BIT14)\r
+#define B_QNC_PM1BLK_PM1S_RTC (BIT10)\r
+#define B_QNC_PM1BLK_PM1S_GLOB (BIT5)\r
+#define B_QNC_PM1BLK_PM1S_TO (BIT0)\r
+#define N_QNC_PM1BLK_PM1S_RTC 10\r
+\r
+\r
+#define R_QNC_PM1BLK_PM1E 0x02\r
+#define S_QNC_PM1BLK_PM1E 2\r
+#define B_QNC_PM1BLK_PM1E_PWAKED (BIT14)\r
+#define B_QNC_PM1BLK_PM1E_RTC (BIT10)\r
+#define B_QNC_PM1BLK_PM1E_GLOB (BIT5)\r
+#define N_QNC_PM1BLK_PM1E_RTC 10\r
+\r
+#define R_QNC_PM1BLK_PM1C 0x04\r
+#define B_QNC_PM1BLK_PM1C_SLPEN (BIT13)\r
+#define B_QNC_PM1BLK_PM1C_SLPTP (BIT12+BIT11+BIT10)\r
+#define V_S0 0x00000000\r
+#define V_S3 0x00001400\r
+#define V_S4 0x00001800\r
+#define V_S5 0x00001C00\r
+#define B_QNC_PM1BLK_PM1C_SCIEN (BIT0)\r
+\r
+#define R_QNC_PM1BLK_PM1T 0x08\r
+\r
+#define R_QNC_LPC_GPE0BLK 0x4C\r
+#define B_QNC_LPC_GPE0BLK_MASK 0x0000FFC0\r
+// Suggested Value for GPE0BLK = 0x10C0\r
+//\r
+#define R_QNC_GPE0BLK_GPE0S 0x00 // General Purpose Event 0 Status\r
+#define S_QNC_GPE0BLK_GPE0S 4\r
+#define B_QNC_GPE0BLK_GPE0S_ALL 0x00003F800 // used to clear the status reg\r
+#define B_QNC_GPE0BLK_GPE0S_PCIE (BIT17) // PCIE\r
+#define B_QNC_GPE0BLK_GPE0S_GPIO (BIT14) // GPIO\r
+#define B_QNC_GPE0BLK_GPE0S_EGPE (BIT13) // External GPE\r
+#define N_QNC_GPE0BLK_GPE0S_THRM 12\r
+\r
+#define R_QNC_GPE0BLK_GPE0E 0x04 // General Purpose Event 0 Enable\r
+#define S_QNC_GPE0BLK_GPE0E 4\r
+#define B_QNC_GPE0BLK_GPE0E_PCIE (BIT17) // PCIE\r
+#define B_QNC_GPE0BLK_GPE0E_GPIO (BIT14) // GPIO\r
+#define B_QNC_GPE0BLK_GPE0E_EGPE (BIT13) // External GPE\r
+#define N_QNC_GPE0BLK_GPE0E_THRM 12\r
+\r
+#define R_QNC_GPE0BLK_SMIE 0x10 // SMI_B Enable\r
+#define S_QNC_GPE0BLK_SMIE 4\r
+#define B_QNC_GPE0BLK_SMIE_ALL 0x0003871F\r
+#define B_QNC_GPE0BLK_SMIE_APM (BIT4) // APM\r
+#define B_QNC_GPE0BLK_SMIE_SLP (BIT2) // Sleep\r
+#define B_QNC_GPE0BLK_SMIE_SWT (BIT1) // Software Timer\r
+#define N_QNC_GPE0BLK_SMIE_GPIO 9\r
+#define N_QNC_GPE0BLK_SMIE_ESMI 8\r
+#define N_QNC_GPE0BLK_SMIE_APM 4\r
+#define N_QNC_GPE0BLK_SMIE_SPI 3\r
+#define N_QNC_GPE0BLK_SMIE_SLP 2\r
+#define N_QNC_GPE0BLK_SMIE_SWT 1\r
+\r
+#define R_QNC_GPE0BLK_SMIS 0x14 // SMI Status Register.\r
+#define S_QNC_GPE0BLK_SMIS 4\r
+#define B_QNC_GPE0BLK_SMIS_ALL 0x0003871F\r
+#define B_QNC_GPE0BLK_SMIS_EOS (BIT31) // End of SMI\r
+#define B_QNC_GPE0BLK_SMIS_APM (BIT4) // APM\r
+#define B_QNC_GPE0BLK_SMIS_SPI (BIT3) // SPI\r
+#define B_QNC_GPE0BLK_SMIS_SLP (BIT2) // Sleep\r
+#define B_QNC_GPE0BLK_SMIS_SWT (BIT1) // Software Timer\r
+#define B_QNC_GPE0BLK_SMIS_BIOS (BIT0) // BIOS\r
+#define N_QNC_GPE0BLK_SMIS_GPIO 9\r
+#define N_QNC_GPE0BLK_SMIS_APM 4\r
+#define N_QNC_GPE0BLK_SMIS_SPI 3\r
+#define N_QNC_GPE0BLK_SMIS_SLP 2\r
+#define N_QNC_GPE0BLK_SMIS_SWT 1\r
+\r
+#define R_QNC_GPE0BLK_PMCW 0x28 // Power Management Configuration Core Well\r
+#define B_QNC_GPE0BLK_PMCW_PSE (BIT31) // Periodic SMI Enable\r
+\r
+#define R_QNC_GPE0BLK_PMSW 0x2C // Power Management Configuration Suspend/Resume Well\r
+#define B_QNC_GPE0BLK_PMSW_DRAM_INIT (BIT0) // Dram Initialization Sctrachpad\r
+\r
+#define R_QNC_LPC_ACTL 0x58\r
+#define V_QNC_LPC_ACTL_SCIS_IRQ9 0x00\r
+\r
+//\r
+// Number of PIRQs supported. PIRQA~PIRQH\r
+//\r
+#define QNC_NUMBER_PIRQS 8\r
+#define R_QNC_LPC_PIRQA_ROUT 0x60\r
+#define R_QNC_LPC_PIRQB_ROUT 0x61\r
+#define R_QNC_LPC_PIRQC_ROUT 0x62\r
+#define R_QNC_LPC_PIRQD_ROUT 0x63\r
+#define R_QNC_LPC_PIRQE_ROUT 0x64\r
+#define R_QNC_LPC_PIRQF_ROUT 0x65\r
+#define R_QNC_LPC_PIRQG_ROUT 0x66\r
+#define R_QNC_LPC_PIRQH_ROUT 0x67\r
+\r
+//\r
+// Bit values are the same for R_TNC_LPC_PIRQA_ROUT to\r
+// R_TNC_LPC_PIRQH_ROUT\r
+#define B_QNC_LPC_PIRQX_ROUT (BIT3+BIT2+BIT1+BIT0)\r
+\r
+#define R_QNC_LPC_WDTBA 0x84\r
+// Watchdog Timer register offsets from WDTBASE (in R_QNC_LPC_WDTBA)------------BEGIN\r
+#define R_QNC_LPC_WDT_WDTCR 0x10\r
+#define R_QNC_LPC_WDT_WDTLR 0x18\r
+// Watchdog Timer register offsets from WDTBASE (in R_QNC_LPC_WDTBA)--------------END\r
+\r
+#define R_QNC_LPC_FWH_BIOS_DEC 0xD4\r
+#define B_QNC_LPC_FWH_BIOS_DEC_F8 (BIT31)\r
+#define B_QNC_LPC_FWH_BIOS_DEC_F0 (BIT30)\r
+#define B_QNC_LPC_FWH_BIOS_DEC_E8 (BIT29)\r
+#define B_QNC_LPC_FWH_BIOS_DEC_E0 (BIT28)\r
+#define B_QNC_LPC_FWH_BIOS_DEC_D8 (BIT27)\r
+#define B_QNC_LPC_FWH_BIOS_DEC_D0 (BIT26)\r
+#define B_QNC_LPC_FWH_BIOS_DEC_C8 (BIT25)\r
+#define B_QNC_LPC_FWH_BIOS_DEC_C0 (BIT24)\r
+\r
+#define R_QNC_LPC_BIOS_CNTL 0xD8\r
+#define S_QNC_LPC_BIOS_CNTL 4\r
+#define B_QNC_LPC_BIOS_CNTL_PFE (BIT8)\r
+#define B_QNC_LPC_BIOS_CNTL_SMM_BWP (BIT5)\r
+#define B_QNC_LPC_BIOS_CNTL_BCD (BIT2)\r
+#define B_QNC_LPC_BIOS_CNTL_BLE (BIT1)\r
+#define B_QNC_LPC_BIOS_CNTL_BIOSWE (BIT0)\r
+#define N_QNC_LPC_BIOS_CNTL_BLE 1\r
+#define N_QNC_LPC_BIOS_CNTL_BIOSWE 0\r
+\r
+#define R_QNC_LPC_RCBA 0xF0\r
+#define B_QNC_LPC_RCBA_MASK 0xFFFFC000\r
+#define B_QNC_LPC_RCBA_EN (BIT0)\r
+\r
+//---------------------------------------------------------------------------\r
+// Fixed IO Decode on QuarkNcSocId\r
+//\r
+// 20h(2B) 24h(2B) 28h(2B) 2Ch(2B) 30h(2B) 34h(2B) 38h(2B) 3Ch(2B) : R/W 8259 master\r
+// 40h(3B): R/W 8254\r
+// 43h(1B): W 8254\r
+// 50h(3B): R/W 8254\r
+// 53h(1B): W 8254\r
+// 61h(1B): R/W NMI Controller\r
+// 63h(1B): R/W NMI Controller - can be disabled\r
+// 65h(1B): R/W NMI Controller - can be disabled\r
+// 67h(1B): R/W NMI Controller - can be disabled\r
+// 70h(1B): W NMI & RTC\r
+// 71h(1B): R/W RTC\r
+// 72h(1B): R RTC; W NMI&RTC\r
+// 73h(1B): R/W RTC\r
+// 74h(1B): R RTC; W NMI&RTC\r
+// 75h(1B): R/W RTC\r
+// 76h(1B): R RTC; W NMI&RTC\r
+// 77h(1B): R/W RTC\r
+// 84h(3B): R/W Internal/LPC\r
+// 88h(1B): R/W Internal/LPC\r
+// 8Ch(3B): R/W Internal/LPC\r
+// A0h(2B) A4h(2B) A8h(2B) ACh(2B) B0h(2B) B4h(2B) B8h(2B) BCh(2B): R/W 8259 slave\r
+// B2h(1B) B3h(1B): R/W Power management\r
+// 3B0h-3BBh: R/W VGA\r
+// 3C0h-3DFh: R/W VGA\r
+// CF8h(4B): R/W Internal\r
+// CF9h(1B): R/W LPC\r
+// CFCh(4B): R/W Internal\r
+//---------------------------------------------------------------------------\r
+\r
+#define R_APM_CNT 0xB2\r
+\r
+//\r
+// Reset Generator I/O Port\r
+//\r
+#define RST_CNT 0xCF9\r
+#define B_RST_CNT_COLD_RST (BIT3) // Cold reset\r
+#define B_RST_CNT_WARM_RST (BIT1) // Warm reset\r
+\r
+//\r
+// Processor interface registers (NMI)\r
+//\r
+\r
+#define PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0 20\r
+#define PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1 21\r
+#define PCI_FUNCTION_NUMBER_QNC_IOSF2AHB 0\r
+\r
+//\r
+// Pci Express Root Ports (D23:F0/F1)\r
+//\r
+#define PCI_DEVICE_NUMBER_PCIE_ROOTPORT 23\r
+#define PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 0\r
+#define PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1 1\r
+\r
+#define MAX_PCI_EXPRESS_ROOT_PORTS 2\r
+\r
+#define R_QNC_PCIE_BNUM 0x18\r
+#define R_QNC_PCIE_CAP_PTR 0x34\r
+\r
+#define PCIE_CAPID 0x10 //PCIE Capability ID\r
+#define PCIE_CAP_EXT_HEARDER_OFFSET 0x100 //PCIE Capability ID\r
+#define PCIE_DEV_CAP_OFFSET 0x04 //PCIE Device Capability reg offset\r
+#define PCIE_LINK_CAP_OFFSET 0x0C //PCIE Link Capability reg offset\r
+#define PCIE_LINK_CNT_OFFSET 0x10 //PCIE Link control reg offset\r
+#define PCIE_LINK_STS_OFFSET 0x12 //PCIE Link status reg offset\r
+#define PCIE_SLOT_CAP_OFFSET 0x14 //PCIE Link Capability reg offset\r
+\r
+#define R_QNC_PCIE_XCAP 0x42 //~ 43h\r
+#define B_QNC_PCIE_XCAP_SI (BIT8) //slot implemented\r
+#define R_QNC_PCIE_DCAP 0x44 //~ 47h\r
+#define B_QNC_PCIE_DCAP_E1AL (BIT11 | BIT10 | BIT9) // L1 Acceptable exit latency\r
+#define B_QNC_PCIE_DCAP_E0AL (BIT8 | BIT7 | BIT6) // L0 Acceptable exit latency\r
+#define R_QNC_PCIE_DCTL 0x48 //~ 49h\r
+#define B_QNC_PCIE_DCTL_URE (BIT3) //Unsupported Request Reporting Enable\r
+#define B_QNC_PCIE_DCTL_FEE (BIT2) //Fatal error Reporting Enable\r
+#define B_QNC_PCIE_DCTL_NFE (BIT1) //Non Fatal error Reporting Enable\r
+#define B_QNC_PCIE_DCTL_CEE (BIT0) //Correctable error Reporting Enable\r
+#define R_QNC_PCIE_LCAP 0x4C //~ 4Fh\r
+#define B_QNC_PCIE_LCAP_CPM (BIT18) //clock power management supported\r
+#define B_QNC_PCIE_LCAP_EL1_MASK (BIT17 | BIT16 | BIT15) //L1 Exit latency mask\r
+#define B_QNC_PCIE_LCAP_EL0_MASK (BIT14 | BIT13 | BIT12) //L0 Exit latency mask\r
+#define B_QNC_PCIE_LCAP_APMS_MASK (BIT11 | BIT10) //Active state link PM support mask\r
+#define V_QNC_PCIE_LCAP_APMS_OFFSET 10 //Active state link PM support mask\r
+#define R_QNC_PCIE_LCTL 0x50 //~ 51h\r
+#define B_QNC_PCIE_LCTL_CCC (BIT6) // Clock clock configuration\r
+#define B_QNC_PCIE_LCTL_RL (BIT5) // Retrain link\r
+#define R_QNC_PCIE_LSTS 0x52 //~ 53h\r
+#define B_QNC_PCIE_LSTS_SCC (BIT12) //Slot clock configuration\r
+#define B_QNC_PCIE_LSTS_LT (BIT11) //Link training\r
+#define R_QNC_PCIE_SLCAP 0x54 //~ 57h\r
+#define B_QNC_PCIE_SLCAP_MASK_RSV_VALUE 0x0006007F\r
+#define V_QNC_PCIE_SLCAP_SLV 0x0A //Slot power limit value [14:7]\r
+#define V_QNC_PCIE_SLCAP_SLV_OFFSET 7 //Slot power limit value offset is 7 [14:7]\r
+#define V_QNC_PCIE_SLCAP_PSN_OFFSET 19 //Slot number offset is 19 [31:19]\r
+#define R_QNC_PCIE_SLCTL 0x58 //~ 59h\r
+#define B_QNC_PCIE_SLCTL_HPE (BIT5) // Hot plug interrupt enable\r
+#define B_QNC_PCIE_SLCTL_PDE (BIT3) // Presense detect change enable\r
+#define B_QNC_PCIE_SLCTL_ABE (BIT0) // Attention Button Pressed Enable\r
+#define R_QNC_PCIE_SLSTS 0x5A //~ 5Bh\r
+#define B_QNC_PCIE_SLSTS_PDS (BIT6) // Present Detect State = 1b : has device connected\r
+#define B_QNC_PCIE_SLSTS_PDC (BIT3) // Present Detect changed = 1b : PDS state has changed\r
+#define B_QNC_PCIE_SLSTS_ABP (BIT0) // Attention Button Pressed\r
+#define R_QNC_PCIE_RCTL 0x5C //~ 5Dh\r
+#define B_QNC_PCIE_RCTL_PIE (BIT3) //Root PCI-E PME Interrupt Enable\r
+#define B_QNC_PCIE_RCTL_SFE (BIT2) //Root PCI-E System Error on Fatal Error Enable\r
+#define B_QNC_PCIE_RCTL_SNE (BIT1) //Root PCI-E System Error on Non-Fatal Error Enable\r
+#define B_QNC_PCIE_RCTL_SCE (BIT0) //Root PCI-E System Error on Correctable Error Enable\r
+#define R_QNC_PCIE_SVID 0x94 //~ 97h\r
+#define R_QNC_PCIE_CCFG 0xD0 //~ D3h\r
+#define B_QNC_PCIE_CCFG_UPSD (BIT24) // Upstream Posted Split Disable\r
+#define B_QNC_PCIE_CCFG_UNRS (BIT15) // Upstream Non-Posted Request Size\r
+#define B_QNC_PCIE_CCFG_UPRS (BIT14) // Upstream Posted Request Size\r
+#define R_QNC_PCIE_MPC2 0xD4 //~ D7h\r
+#define B_QNC_PCIE_MPC2_IPF (BIT11) // ISOF Packet Fast Transmit Mode\r
+#define R_QNC_PCIE_MPC 0xD8 //~ DBh\r
+#define B_QNC_PCIE_MPC_PMCE (BIT31) // PM SCI Enable\r
+#define B_QNC_PCIE_MPC_HPCE (BIT30) // Hot plug SCI enable\r
+\r
+#define B_QNC_PCIE_MPC_HPME (BIT1) // Hot plug SMI enable\r
+#define B_QNC_PCIE_MPC_PMME (BIT0) // PM SMI Enable\r
+#define R_QNC_PCIE_IOSFSBCTL 0xF6\r
+#define B_QNC_PCIE_IOSFSBCTL_SBIC_MASK (BIT1 | BIT0) // IOSF Sideband ISM Idle Counter.\r
+#define B_QNC_PCIE_IOSFSBCTL_SBIC_IDLE_NEVER (BIT1 | BIT0) // Never transition to IDLE.\r
+\r
+#define V_PCIE_MAX_TRY_TIMES 200\r
+\r
+//\r
+// Misc PCI register offsets and sizes\r
+//\r
+#define R_EFI_PCI_SVID 0x2C\r
+\r
+//\r
+// IO_APIC\r
+//\r
+#define IOAPIC_BASE 0xFEC00000\r
+#define IOAPIC_SIZE 0x1000\r
+\r
+//\r
+// Chipset configuration registers RCBA - "Root Complex Base Address" (D31:F0:RF0h)\r
+// Suggested Value for RCBA = 0xFED1C000\r
+//\r
+\r
+#define R_QNC_RCRB_SPIBASE 0x3020 // SPI (Serial Peripheral Interface) in RCRB\r
+#define R_QNC_RCRB_SPIS (R_QNC_RCRB_SPIBASE + 0x00) // SPI Status\r
+#define B_QNC_RCRB_SPIS_SCL (BIT15) // SPI Configuration Lockdown\r
+#define B_QNC_RCRB_SPIS_BAS (BIT3) // Blocked Access Status\r
+#define B_QNC_RCRB_SPIS_CDS (BIT2) // Cycle Done Status\r
+#define B_QNC_RCRB_SPIS_SCIP (BIT0) // SPI Cycle in Progress\r
+\r
+#define R_QNC_RCRB_SPIC (R_QNC_RCRB_SPIBASE + 0x02) // SPI Control\r
+#define B_QNC_RCRB_SPIC_DC (BIT14) // SPI Data Cycle Enable\r
+#define B_QNC_RCRB_SPIC_DBC 0x3F00 // SPI Data Byte Count (1..8,16,24,32,40,48,56,64)\r
+#define B_QNC_RCRB_SPIC_COP (BIT6+BIT5+BIT4) // SPI Cycle Opcode Pointer\r
+#define B_QNC_RCRB_SPIC_SPOP (BIT3) // Sequence Prefix Opcode Pointer\r
+#define B_QNC_RCRB_SPIC_ACS (BIT2) // SPI Atomic Cycle Sequence\r
+#define B_QNC_RCRB_SPIC_SCGO (BIT1) // SPI Cycle Go\r
+\r
+#define R_QNC_RCRB_SPIA (R_QNC_RCRB_SPIBASE + 0x04) // SPI Address\r
+#define B_QNC_RCRB_SPIA_MASK 0x00FFFFFF // SPI Address mask\r
+#define R_QNC_RCRB_SPID0 (R_QNC_RCRB_SPIBASE + 0x08) // SPI Data 0\r
+#define R_QNC_RCRB_SPIPREOP (R_QNC_RCRB_SPIBASE + 0x54) // Prefix Opcode Configuration\r
+#define R_QNC_RCRB_SPIOPTYPE (R_QNC_RCRB_SPIBASE + 0x56) // Opcode Type Configuration\r
+#define B_QNC_RCRB_SPIOPTYPE_NOADD_READ 0\r
+#define B_QNC_RCRB_SPIOPTYPE_NOADD_WRITE (BIT0)\r
+#define B_QNC_RCRB_SPIOPTYPE_ADD_READ (BIT1)\r
+#define B_QNC_RCRB_SPIOPTYPE_ADD_WRITE (BIT0 + BIT1)\r
+#define R_QNC_RCRB_SPIOPMENU (R_QNC_RCRB_SPIBASE + 0x58) // Opcode Menu Configuration //R_OPMENU\r
+\r
+#define R_QNC_RCRB_SPIPBR0 (R_QNC_RCRB_SPIBASE + 0x60) // Protected BIOS Range 0.\r
+#define R_QNC_RCRB_SPIPBR1 (R_QNC_RCRB_SPIBASE + 0x64) // Protected BIOS Range 1.\r
+#define R_QNC_RCRB_SPIPBR2 (R_QNC_RCRB_SPIBASE + 0x68) // Protected BIOS Range 2.\r
+#define B_QNC_RCRB_SPIPBRn_WPE (BIT31) // Write Protection Enable for above 3 registers.\r
+\r
+#define R_QNC_RCRB_AGENT0IR 0x3140 // AGENT0 interrupt route\r
+#define R_QNC_RCRB_AGENT1IR 0x3142 // AGENT1 interrupt route\r
+#define R_QNC_RCRB_AGENT2IR 0x3144 // AGENT2 interrupt route\r
+#define R_QNC_RCRB_AGENT3IR 0x3146 // AGENT3 interrupt route\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Common header file shared by all source files.\r
+\r
+This file includes package header files, library classes and protocol, PPI & GUID definitions.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef __COMMON_HEADER_H_\r
+#define __COMMON_HEADER_H_\r
+\r
+\r
+\r
+#include <PiPei.h>\r
+#include <IntelQNCBase.h>\r
+\r
+#include <Library/IntelQNCLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/CpuLib.h>\r
+#include <Library/PciCf8Lib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/QNCAccessLib.h>\r
+#include <IndustryStandard/Pci22.h>\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Lib function for Pei QNC.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "CommonHeader.h"\r
+\r
+/**\r
+ This function provides the necessary SOC initialization\r
+ before MRC running. It sets RCBA, GPIO, PMBASE\r
+ and some parts of SOC through SOC message method.\r
+ If the function cannot complete it'll ASSERT().\r
+**/\r
+VOID\r
+EFIAPI\r
+PeiQNCPreMemInit (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RegValue;\r
+\r
+ // QNCPortWrite(Port#, Offset, Value)\r
+\r
+ //\r
+ // Set the fixed PRI Status encodings config.\r
+ //\r
+ QNCPortWrite (\r
+ QUARK_NC_MEMORY_ARBITER_SB_PORT_ID,\r
+ QUARK_NC_MEMORY_ARBITER_REG_ASTATUS,\r
+ QNC_FIXED_CONFIG_ASTATUS\r
+ );\r
+\r
+ // Sideband register write to Remote Management Unit\r
+ QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QNC_MSG_TMPM_REG_PMBA, (BIT31 | PcdGet16 (PcdPmbaIoBaseAddress)));\r
+\r
+ // Configurable I/O address in iLB (legacy block)\r
+\r
+ LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) = BIT31 | PcdGet16 (PcdSmbaIoBaseAddress);\r
+ LpcPciCfg32 (R_QNC_LPC_GBA_BASE) = BIT31 | PcdGet16 (PcdGbaIoBaseAddress);\r
+ LpcPciCfg32 (R_QNC_LPC_PM1BLK) = BIT31 | PcdGet16 (PcdPm1blkIoBaseAddress);\r
+ LpcPciCfg32 (R_QNC_LPC_GPE0BLK) = BIT31 | PcdGet16 (PcdGpe0blkIoBaseAddress);\r
+ LpcPciCfg32 (R_QNC_LPC_WDTBA) = BIT31 | PcdGet16 (PcdWdtbaIoBaseAddress);\r
+\r
+ //\r
+ // Program RCBA Base Address\r
+ //\r
+ LpcPciCfg32AndThenOr (R_QNC_LPC_RCBA, (~B_QNC_LPC_RCBA_MASK), (((UINT32)(PcdGet64 (PcdRcbaMmioBaseAddress))) | B_QNC_LPC_RCBA_EN));\r
+\r
+ //\r
+ // Program Memory Manager fixed config values.\r
+ //\r
+\r
+ RegValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BTHCTRL);\r
+ RegValue &= ~(DRAM_NON_HOST_RQ_LIMIT_MASK);\r
+ RegValue |= (V_DRAM_NON_HOST_RQ_LIMIT << DRAM_NON_HOST_RQ_LIMIT_BP);\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BTHCTRL, RegValue);\r
+\r
+ //\r
+ // Program iCLK fixed config values.\r
+ //\r
+ QncIClkAndThenOr (\r
+ QUARK_ICLK_MUXTOP,\r
+ (UINT32) ~(B_MUXTOP_FLEX2_MASK | B_MUXTOP_FLEX1_MASK),\r
+ (V_MUXTOP_FLEX2 << B_MUXTOP_FLEX2_BP) | (V_MUXTOP_FLEX1 << B_MUXTOP_FLEX1_BP)\r
+ );\r
+ QncIClkAndThenOr (\r
+ QUARK_ICLK_REF2_DBUFF0,\r
+ (UINT32) ~(BIT0), // bit[0] cleared\r
+ 0\r
+ );\r
+ QncIClkOr (\r
+ QUARK_ICLK_SSC1,\r
+ BIT0 // bit[0] set\r
+ );\r
+ QncIClkOr (\r
+ QUARK_ICLK_SSC2,\r
+ BIT0 // bit[0] set\r
+ );\r
+ QncIClkOr (\r
+ QUARK_ICLK_SSC3,\r
+ BIT0 // bit[0] set\r
+ );\r
+\r
+ //\r
+ // Set RMU DMA disable bit post boot.\r
+ //\r
+ RegValue = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_OPTIONS_1);\r
+ RegValue |= OPTIONS_1_DMA_DISABLE;\r
+ QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_OPTIONS_1, RegValue);\r
+}\r
+\r
+/**\r
+ Do north cluster init which needs to be done AFTER MRC init.\r
+\r
+ @param VOID\r
+\r
+ @retval VOID\r
+**/\r
+\r
+VOID\r
+EFIAPI\r
+PeiQNCPostMemInit (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Program SVID/SID the same as VID/DID for all devices except root ports.\r
+ //\r
+ QNCMmPci32(0, MC_BUS, MC_DEV, MC_FUN, R_EFI_PCI_SVID) = QNCMmPci32(0, MC_BUS, MC_DEV, MC_FUN, PCI_VENDOR_ID_OFFSET);\r
+ 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);\r
+ 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);\r
+ 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);\r
+ return;\r
+}\r
+\r
+/**\r
+ Used to check QNC if it's S3 state. Clear the register state after query.\r
+\r
+ @retval TRUE if it's S3 state.\r
+ @retval FALSE if it's not S3 state.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QNCCheckS3AndClearState (\r
+ VOID\r
+ )\r
+{\r
+ BOOLEAN S3WakeEventFound;\r
+ UINT16 Pm1Sts;\r
+ UINT16 Pm1En;\r
+ UINT16 Pm1Cnt;\r
+ UINT32 Gpe0Sts;\r
+ UINT32 Gpe0En;\r
+ UINT32 NewValue;\r
+ CHAR8 *EventDescStr;\r
+\r
+ S3WakeEventFound = FALSE;\r
+ EventDescStr = NULL;\r
+\r
+ //\r
+ // Read the ACPI registers,\r
+ //\r
+ Pm1Sts = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S);\r
+ Pm1En = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E);\r
+ Pm1Cnt = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);\r
+ Gpe0Sts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S);\r
+ Gpe0En = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E);\r
+\r
+ //\r
+ // Clear Power Management 1 Enable Register and\r
+ // General Purpost Event 0 Enables Register\r
+ //\r
+ IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0);\r
+ IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0);\r
+\r
+ if ((Pm1Sts & B_QNC_PM1BLK_PM1S_WAKE) != 0 && (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) == V_S3) {\r
+\r
+ //\r
+ // Detect the actual WAKE event\r
+ //\r
+ if ((Pm1Sts & B_QNC_PM1BLK_PM1S_RTC) && (Pm1En & B_QNC_PM1BLK_PM1E_RTC)) {\r
+ EventDescStr = "RTC Alarm";\r
+ S3WakeEventFound = TRUE;\r
+ }\r
+ if ((Pm1Sts & B_QNC_PM1BLK_PM1S_PCIEWSTS) && !(Pm1En & B_QNC_PM1BLK_PM1E_PWAKED)) {\r
+ EventDescStr = "PCIe WAKE";\r
+ S3WakeEventFound = TRUE;\r
+ }\r
+ if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_PCIE) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_PCIE)) {\r
+ EventDescStr = "PCIe";\r
+ S3WakeEventFound = TRUE;\r
+ }\r
+ if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_GPIO) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_GPIO)) {\r
+ EventDescStr = "GPIO";\r
+ S3WakeEventFound = TRUE;\r
+ }\r
+ if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_EGPE) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_EGPE)) {\r
+ EventDescStr = "Ext. GPE";\r
+ S3WakeEventFound = TRUE;\r
+ }\r
+ if (S3WakeEventFound == FALSE) {\r
+ EventDescStr = "Unknown";\r
+ }\r
+ DEBUG ((EFI_D_INFO, "S3 Wake Event - %a\n", EventDescStr));\r
+\r
+ //\r
+ // If no Power Button Override event occurs and one enabled wake event occurs,\r
+ // just do S3 resume and clear the state.\r
+ //\r
+ IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, (Pm1Cnt & (~B_QNC_PM1BLK_PM1C_SLPTP)));\r
+\r
+ //\r
+ // Set EOS to de Assert SMI\r
+ //\r
+ IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS);\r
+\r
+ //\r
+ // Enable SMI globally\r
+ //\r
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
+ NewValue |= SMI_EN;\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Used to check QNC if system wakes up from power on reset. Clear the register state after query.\r
+\r
+ @retval TRUE if system wakes up from power on reset\r
+ @retval FALSE if system does not wake up from power on reset\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QNCCheckPowerOnResetAndClearState (\r
+ VOID\r
+ )\r
+{\r
+ UINT16 Pm1Sts;\r
+ UINT16 Pm1Cnt;\r
+\r
+ //\r
+ // Read the ACPI registers,\r
+ // PM1_STS information cannot be lost after power down, unless CMOS is cleared.\r
+ //\r
+ Pm1Sts = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S);\r
+ Pm1Cnt = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);\r
+\r
+ //\r
+ // If B_SLP_TYP is S5\r
+ //\r
+ if ((Pm1Sts & B_QNC_PM1BLK_PM1S_WAKE) != 0 && (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) == V_S5) {\r
+ IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, (Pm1Cnt & (~B_QNC_PM1BLK_PM1C_SLPTP)));\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ This function is used to clear SMI and wake status.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCClearSmiAndWake (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Gpe0Sts;\r
+ UINT32 SmiSts;\r
+\r
+ //\r
+ // Read the ACPI registers\r
+ //\r
+ Gpe0Sts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S);\r
+ SmiSts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);\r
+\r
+ //\r
+ // Clear any SMI or wake state from the boot\r
+ //\r
+ Gpe0Sts |= B_QNC_GPE0BLK_GPE0S_ALL;\r
+ SmiSts |= B_QNC_GPE0BLK_SMIS_ALL;\r
+\r
+ //\r
+ // Write them back\r
+ //\r
+ IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S, Gpe0Sts);\r
+ IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, SmiSts);\r
+}\r
+\r
+/** Send DRAM Ready opcode.\r
+\r
+ @param[in] OpcodeParam Parameter to DRAM ready opcode.\r
+\r
+ @retval VOID\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCSendOpcodeDramReady (\r
+ IN UINT32 OpcodeParam\r
+ )\r
+{\r
+\r
+ //\r
+ // Before sending DRAM ready place invalid value in Scrub Config.\r
+ //\r
+ QNCPortWrite (\r
+ QUARK_NC_RMU_SB_PORT_ID,\r
+ QUARK_NC_ECC_SCRUB_CONFIG_REG,\r
+ SCRUB_CFG_INVALID\r
+ );\r
+\r
+ //\r
+ // Send opcode and use param to notify HW of new RMU firmware location.\r
+ //\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = OpcodeParam;\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_SHADOW_DW (QUARK_NC_RMU_SB_PORT_ID, 0);\r
+\r
+ //\r
+ // HW completed tasks on DRAM ready when scrub config read back as zero.\r
+ //\r
+ while (QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG) != 0) {\r
+ MicroSecondDelay (10);\r
+ }\r
+}\r
+\r
+/**\r
+\r
+ Relocate RMU Main binary to memory after MRC to improve performance.\r
+\r
+ @param[in] DestBaseAddress - Specify the new memory address for the RMU Main binary.\r
+ @param[in] SrcBaseAddress - Specify the current memory address for the RMU Main binary.\r
+ @param[in] Size - Specify size of the RMU Main binary.\r
+\r
+ @retval VOID\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RmuMainRelocation (\r
+ IN CONST UINT32 DestBaseAddress,\r
+ IN CONST UINT32 SrcBaseAddress,\r
+ IN CONST UINTN Size\r
+ )\r
+{\r
+ //\r
+ // Shadow RMU Main binary into main memory.\r
+ //\r
+ CopyMem ((VOID *)(UINTN)DestBaseAddress,(VOID *)(UINTN) SrcBaseAddress, Size);\r
+}\r
+\r
+\r
+/**\r
+ Get the total memory size\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+QNCGetTotalMemorysize (\r
+ VOID\r
+ )\r
+{\r
+ return QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HMBOUND_REG) & HMBOUND_MASK;\r
+}\r
+\r
+\r
+/**\r
+ Get the memory range of TSEG.\r
+ The TSEG's memory is below TOLM.\r
+\r
+ @param[out] BaseAddress The base address of TSEG's memory range\r
+ @param[out] MemorySize The size of TSEG's memory range\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCGetTSEGMemoryRange (\r
+ OUT UINT64 *BaseAddress,\r
+ OUT UINT64 *MemorySize\r
+ )\r
+{\r
+ UINT64 Register = 0;\r
+ UINT64 SMMAddress = 0;\r
+\r
+ Register = QncHsmmcRead ();\r
+\r
+ //\r
+ // Get the SMRAM Base address\r
+ //\r
+ SMMAddress = Register & SMM_START_MASK;\r
+ *BaseAddress = LShift16 (SMMAddress);\r
+\r
+ //\r
+ // Get the SMRAM size\r
+ //\r
+ SMMAddress = ((Register & SMM_END_MASK) | (~SMM_END_MASK)) + 1;\r
+ *MemorySize = SMMAddress - (*BaseAddress);\r
+\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "TSEG's memory range: BaseAddress = 0x%x, Size = 0x%x\n",\r
+ (UINT32)*BaseAddress,\r
+ (UINT32)*MemorySize\r
+ ));\r
+}\r
+\r
+/**\r
+ Updates the PAM registers in the MCH for the requested range and mode.\r
+\r
+ @param Start The start address of the memory region\r
+ @param Length The length, in bytes, of the memory region\r
+ @param ReadEnable Pointer to the boolean variable on whether to enable read for legacy memory section.\r
+ If NULL, then read attribute will not be touched by this call.\r
+ @param ReadEnable Pointer to the boolean variable on whether to enable write for legacy memory section.\r
+ If NULL, then write attribute will not be touched by this call.\r
+ @param Granularity A pointer to granularity, in bytes, that the PAM registers support\r
+\r
+ @retval RETURN_SUCCESS The PAM registers in the MCH were updated\r
+ @retval RETURN_INVALID_PARAMETER The memory range is not valid in legacy region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+QNCLegacyRegionManipulation (\r
+ IN UINT32 Start,\r
+ IN UINT32 Length,\r
+ IN BOOLEAN *ReadEnable,\r
+ IN BOOLEAN *WriteEnable,\r
+ OUT UINT32 *Granularity\r
+ )\r
+{\r
+ //\r
+ // Do nothing cos no such support on QNC\r
+ //\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Determine if QNC is supported.\r
+\r
+ @retval FALSE QNC is not supported.\r
+ @retval TRUE QNC is supported.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsQncSupported (\r
+ VOID\r
+ )\r
+{\r
+ UINT16 SocVendorId;\r
+ UINT16 SocDeviceId;\r
+\r
+ SocVendorId = MmioRead16 (\r
+ PciDeviceMmBase (MC_BUS,\r
+ MC_DEV,\r
+ MC_FUN) + PCI_VENDOR_ID_OFFSET\r
+ );\r
+\r
+ SocDeviceId = QncGetSocDeviceId();\r
+\r
+ //\r
+ // Verify that this is a supported chipset\r
+ //\r
+ if ((SocVendorId != QUARK_MC_VENDOR_ID) || ((SocDeviceId != QUARK_MC_DEVICE_ID) && (SocDeviceId != QUARK2_MC_DEVICE_ID))) {\r
+ DEBUG ((DEBUG_ERROR, "QNC code doesn't support the Soc VendorId:0x%04x Soc DeviceId:0x%04x!\n", SocVendorId, SocDeviceId));\r
+ return FALSE;\r
+ }\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Get the DeviceId of the SoC\r
+\r
+ @retval PCI DeviceId of the SoC\r
+**/\r
+UINT16\r
+EFIAPI\r
+QncGetSocDeviceId (\r
+ VOID\r
+ )\r
+{\r
+ UINT16 SocDeviceId;\r
+\r
+ SocDeviceId = MmioRead16 (\r
+ PciDeviceMmBase (\r
+ MC_BUS,\r
+ MC_DEV,\r
+ MC_FUN\r
+ ) + PCI_DEVICE_ID_OFFSET\r
+ );\r
+\r
+ return SocDeviceId;\r
+}\r
+\r
+/**\r
+ Enable SMI detection of legacy flash access violations.\r
+**/\r
+VOID\r
+EFIAPI\r
+QncEnableLegacyFlashAccessViolationSmi (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 BcValue;\r
+\r
+ BcValue = LpcPciCfg32 (R_QNC_LPC_BIOS_CNTL);\r
+\r
+ //\r
+ // Clear BIOSWE & set BLE.\r
+ //\r
+ BcValue &= (~B_QNC_LPC_BIOS_CNTL_BIOSWE);\r
+ BcValue |= (B_QNC_LPC_BIOS_CNTL_BLE);\r
+\r
+ LpcPciCfg32 (R_QNC_LPC_BIOS_CNTL) = BcValue;\r
+\r
+ DEBUG ((EFI_D_INFO, "BIOS Control Lock Enabled!\n"));\r
+}\r
+\r
+/**\r
+ Setup RMU Thermal sensor registers for Vref mode.\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCThermalSensorSetVRefMode (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Tscgf1Config;\r
+ UINT32 Tscgf2Config;\r
+ UINT32 Tscgf2Config2;\r
+\r
+ Tscgf1Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG);\r
+ Tscgf2Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG);\r
+ Tscgf2Config2 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2);\r
+\r
+ Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK);\r
+ Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCURRENTSEL_VREF_MODE << B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP);\r
+\r
+ Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGEN);\r
+ Tscgf1Config |= (V_TSCGF1_CONFIG_IBGEN_VREF_MODE << B_TSCGF1_CONFIG_IBGEN_BP);\r
+\r
+ Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ISPARECTRL_MASK);\r
+ Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ISPARECTRL_VREF_MODE << B_TSCGF2_CONFIG2_ISPARECTRL_BP);\r
+\r
+ Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK);\r
+ Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCOARSETUNE_VREF_MODE << B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP);\r
+\r
+ Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSCONTROL_MASK);\r
+ Tscgf2Config |= (V_TSCGF2_CONFIG_IDSCONTROL_VREF_MODE << B_TSCGF2_CONFIG_IDSCONTROL_BP);\r
+\r
+ QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG, Tscgf1Config);\r
+ QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG, Tscgf2Config);\r
+ QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2, Tscgf2Config2);\r
+}\r
+\r
+/**\r
+ Setup RMU Thermal sensor registers for Ratiometric mode.\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCThermalSensorSetRatiometricMode (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Tscgf1Config;\r
+ UINT32 Tscgf2Config;\r
+ UINT32 Tscgf2Config2;\r
+ UINT32 Tscgf3Config;\r
+\r
+ Tscgf1Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG);\r
+ Tscgf2Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG);\r
+ Tscgf2Config2 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2);\r
+ Tscgf3Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG);\r
+\r
+ Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK);\r
+ Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCURRENTSEL_RATIO_MODE << B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP);\r
+\r
+ Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCHOPSEL_MASK);\r
+ Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCHOPSEL_RATIO_MODE << B_TSCGF1_CONFIG_ISNSCHOPSEL_BP);\r
+\r
+ Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSINTERNALVREFEN);\r
+ Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSINTERNALVREFEN_RATIO_MODE << B_TSCGF1_CONFIG_ISNSINTERNALVREFEN_BP);\r
+\r
+ Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGEN);\r
+ Tscgf1Config |= (V_TSCGF1_CONFIG_IBGEN_RATIO_MODE << B_TSCGF1_CONFIG_IBGEN_BP);\r
+\r
+ Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGCHOPEN);\r
+ Tscgf1Config |= (V_TSCGF1_CONFIG_IBGCHOPEN_RATIO_MODE << B_TSCGF1_CONFIG_IBGCHOPEN_BP);\r
+\r
+ Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCONFIGSEL_MASK);\r
+ Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCONFIGSEL_RATIO_MODE << B_TSCGF2_CONFIG2_ICALCONFIGSEL_BP);\r
+\r
+ Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ISPARECTRL_MASK);\r
+ Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ISPARECTRL_RATIO_MODE << B_TSCGF2_CONFIG2_ISPARECTRL_BP);\r
+\r
+ Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK);\r
+ Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCOARSETUNE_RATIO_MODE << B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP);\r
+\r
+ Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSCONTROL_MASK);\r
+ Tscgf2Config |= (V_TSCGF2_CONFIG_IDSCONTROL_RATIO_MODE << B_TSCGF2_CONFIG_IDSCONTROL_BP);\r
+\r
+ Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSTIMING_MASK);\r
+ Tscgf2Config |= (V_TSCGF2_CONFIG_IDSTIMING_RATIO_MODE << B_TSCGF2_CONFIG_IDSTIMING_BP);\r
+\r
+ Tscgf3Config &= ~(B_TSCGF3_CONFIG_ITSGAMMACOEFF_MASK);\r
+ Tscgf3Config |= (V_TSCGF3_CONFIG_ITSGAMMACOEFF_RATIO_MODE << B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP);\r
+\r
+ QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG, Tscgf1Config);\r
+ QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG, Tscgf2Config);\r
+ QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2, Tscgf2Config2);\r
+ QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG, Tscgf3Config);\r
+}\r
+\r
+/**\r
+ Setup RMU Thermal sensor trip point values.\r
+\r
+ @param[in] CatastrophicTripOnDegreesCelsius - Catastrophic set trip point threshold.\r
+ @param[in] HotTripOnDegreesCelsius - Hot set trip point threshold.\r
+ @param[in] HotTripOffDegreesCelsius - Hot clear trip point threshold.\r
+\r
+ @retval EFI_SUCCESS Trip points setup.\r
+ @retval EFI_INVALID_PARAMETER Invalid trip point value.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+QNCThermalSensorSetTripValues (\r
+ IN CONST UINTN CatastrophicTripOnDegreesCelsius,\r
+ IN CONST UINTN HotTripOnDegreesCelsius,\r
+ IN CONST UINTN HotTripOffDegreesCelsius\r
+ )\r
+{\r
+ UINT32 RegisterValue;\r
+\r
+ //\r
+ // Register fields are 8-bit temperature values of granularity 1 degree C\r
+ // where 0x00 corresponds to -50 degrees C\r
+ // and 0xFF corresponds to 205 degrees C.\r
+ //\r
+ // User passes unsigned values in degrees Celsius so trips < 0 not supported.\r
+ //\r
+ // Add 50 to user values to get values for register fields.\r
+ //\r
+\r
+ if ((CatastrophicTripOnDegreesCelsius > 205) || (HotTripOnDegreesCelsius > 205) || (HotTripOffDegreesCelsius > 205)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Set new values.\r
+ //\r
+ RegisterValue =\r
+ ((0 + 50) << TS_CAT_TRIP_CLEAR_THOLD_BP) | // Cat Trip Clear value must be less than Cat Trip Set Value.\r
+ ((CatastrophicTripOnDegreesCelsius + 50) << TS_CAT_TRIP_SET_THOLD_BP) |\r
+ ((HotTripOnDegreesCelsius + 50) << TS_HOT_TRIP_SET_THOLD_BP) |\r
+ ((HotTripOffDegreesCelsius + 50) << TS_HOT_TRIP_CLEAR_THOLD_BP)\r
+ ;\r
+\r
+ QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP, RegisterValue);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Enable RMU Thermal sensor with a Catastrophic Trip point.\r
+\r
+ @retval EFI_SUCCESS Trip points setup.\r
+ @retval EFI_INVALID_PARAMETER Invalid trip point value.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+QNCThermalSensorEnableWithCatastrophicTrip (\r
+ IN CONST UINTN CatastrophicTripOnDegreesCelsius\r
+ )\r
+{\r
+ UINT32 Tscgf3Config;\r
+ UINT32 TsModeReg;\r
+ UINT32 TsTripReg;\r
+\r
+ //\r
+ // Trip Register fields are 8-bit temperature values of granularity 1 degree C\r
+ // where 0x00 corresponds to -50 degrees C\r
+ // and 0xFF corresponds to 205 degrees C.\r
+ //\r
+ // User passes unsigned values in degrees Celsius so trips < 0 not supported.\r
+ //\r
+ // Add 50 to user values to get values for register fields.\r
+ //\r
+\r
+ if (CatastrophicTripOnDegreesCelsius > 205) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Tscgf3Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG);\r
+ TsModeReg = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_MODE);\r
+ TsTripReg = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP);\r
+\r
+ //\r
+ // Setup Catastrophic Trip point.\r
+ //\r
+ TsTripReg &= ~(TS_CAT_TRIP_SET_THOLD_MASK);\r
+ TsTripReg |= ((CatastrophicTripOnDegreesCelsius + 50) << TS_CAT_TRIP_SET_THOLD_BP);\r
+ TsTripReg &= ~(TS_CAT_TRIP_CLEAR_THOLD_MASK);\r
+ TsTripReg |= ((0 + 50) << TS_CAT_TRIP_CLEAR_THOLD_BP); // Cat Trip Clear value must be less than Cat Trip Set Value.\r
+ QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP, TsTripReg);\r
+\r
+ //\r
+ // To enable the TS do the following:\r
+ // 1) Take the TS out of reset by setting itsrst to 0x0.\r
+ // 2) Enable the TS using RMU Thermal sensor mode register.\r
+ //\r
+\r
+ Tscgf3Config &= ~(B_TSCGF3_CONFIG_ITSRST);\r
+ TsModeReg |= TS_ENABLE;\r
+\r
+ QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG, Tscgf3Config);\r
+ QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_MODE, TsModeReg);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Lock all RMU Thermal sensor control & trip point registers.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCThermalSensorLockAllRegisters (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RegValue;\r
+ UINT32 LockMask;\r
+\r
+ LockMask = TS_LOCK_THRM_CTRL_REGS_ENABLE | TS_LOCK_AUX_TRIP_PT_REGS_ENABLE;\r
+\r
+ RegValue = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG);\r
+ RegValue |= LockMask;\r
+ QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG, RegValue);\r
+\r
+ ASSERT ((LockMask == (QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG) & LockMask)));\r
+}\r
+\r
+/**\r
+ Set chipset policy for double bit ECC error.\r
+\r
+ @param[in] PolicyValue Policy to config on double bit ECC error.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCPolicyDblEccBitErr (\r
+ IN CONST UINT32 PolicyValue\r
+ )\r
+{\r
+ UINT32 Register;\r
+ Register = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_WDT_CONTROL);\r
+ Register &= ~(B_WDT_CONTROL_DBL_ECC_BIT_ERR_MASK);\r
+ Register |= PolicyValue;\r
+ QNCPortWrite (\r
+ QUARK_NC_RMU_SB_PORT_ID,\r
+ QUARK_NC_RMU_REG_WDT_CONTROL,\r
+ Register\r
+ );\r
+}\r
+\r
+/**\r
+ Determine if running on secure Quark hardware Sku.\r
+\r
+ @retval FALSE Base Quark Sku or unprovisioned Secure Sku running.\r
+ @retval TRUE Provisioned SecureSku hardware running.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QncIsSecureProvisionedSku (\r
+ VOID\r
+ )\r
+{\r
+ // Read QUARK Secure SKU Fuse\r
+ return ((QNCAltPortRead (QUARK_SCSS_FUSE_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_SPI_ROM_FUSE) & BIT6) == BIT6);\r
+}\r
--- /dev/null
+## @file\r
+# Intel QNC Library Instance\r
+#\r
+# Intel QNC Library Instance\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = IntelQNCLib\r
+ FILE_GUID = F5B2EA6C-8148-4a4e-88EA-38A4A51F389F\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = IntelQNCLib\r
+\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ PciExpress.c\r
+ IntelQNCLib.c\r
+ CommonHeader.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ TimerLib\r
+ DebugLib\r
+ PcdLib\r
+ PciLib\r
+ IoLib\r
+ PciCf8Lib\r
+ BaseLib\r
+ CpuLib\r
+ QNCAccessLib\r
+\r
+[Pcd]\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdWdtbaIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPcieRootPortConfiguration\r
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress\r
--- /dev/null
+/** @file\r
+QNC PCI Express initialization entry\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "CommonHeader.h"\r
+\r
+#define PCIEXP_ROOT_PORT_URE_ENABLE BIT0 // unsupported request reporting enable\r
+#define PCIEXP_ROOT_PORT_FEE_ENABLE BIT1 // Fatal Error Reporting Enable\r
+#define PCIEXP_ROOT_PORT_NFE_ENABLE BIT2 // Non-Fatal Error Reporting Enable\r
+#define PCIEXP_ROOT_PORT_CEE_ENABLE BIT3 // Correctable Error Reporting Enable\r
+#define PCIEXP_ROOT_PORT_SFE_ENABLE BIT4 // System Error on Fatal Error Enable\r
+#define PCIEXP_ROOT_PORT_SNE_ENABLE BIT5 // System Error on Non-Fatal Error Enable\r
+#define PCIEXP_ROOT_PORT_SCE_ENABLE BIT6 // System Error on Correctable Error Enable\r
+\r
+EFI_STATUS\r
+PcieStall (\r
+ IN UINTN Microseconds\r
+ )\r
+{\r
+ MicroSecondDelay (Microseconds);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Find the Offset to a given Capabilities ID\r
+ CAPID list:\r
+ 0x01 = PCI Power Management Interface\r
+ 0x04 = Slot Identification\r
+ 0x05 = MSI Capability\r
+ 0x10 = PCI Express Capability\r
+\r
+ @param[in] Bus Bus number of the interested device\r
+ @param[in] Device Device number of the interested device\r
+ @param[in] Function Function number of the interested device\r
+ @param[in] CapId Capability ID to be scanned\r
+\r
+ @retval Offset of desired CAPID\r
+\r
+**/\r
+UINT32\r
+PcieFindCapId (\r
+ UINT8 Bus,\r
+ UINT8 Device,\r
+ UINT8 Function,\r
+ UINT8 CapId\r
+ )\r
+{\r
+ UINT8 CapHeader;\r
+\r
+ //\r
+ // Always start at Offset 0x34\r
+ //\r
+ CapHeader = QNCMmPci8 (0, Bus, Device, Function, R_QNC_PCIE_CAP_PTR);\r
+\r
+ if (CapHeader == 0xFF) {\r
+ return 0;\r
+ }\r
+\r
+ while (CapHeader != 0) {\r
+ if (QNCMmPci8 (0, Bus, Device, Function, CapHeader) == CapId) {\r
+ return CapHeader;\r
+ }\r
+ CapHeader = QNCMmPci8 (0, Bus, Device, Function, CapHeader + 1);\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Search and return the offset of desired Pci Express Capability ID\r
+ CAPID list:\r
+ 0x0001 = Advanced Error Rreporting Capability\r
+ 0x0002 = Virtual Channel Capability\r
+ 0x0003 = Device Serial Number Capability\r
+ 0x0004 = Power Budgeting Capability\r
+\r
+ @param[in] Bus Bus number of the interested device\r
+ @param[in] Device Device number of the interested device\r
+ @param[in] Function Function number of the interested device\r
+ @param[in] CapId Capability ID to be scanned\r
+\r
+ @retval Offset of desired CAPID\r
+\r
+**/\r
+UINT32\r
+PcieFindExtendedCapId (\r
+ UINT8 Bus,\r
+ UINT8 Device,\r
+ UINT8 Function,\r
+ UINT16 CapId\r
+ )\r
+{\r
+ UINT16 CapHeaderOffset;\r
+ UINT16 CapHeaderId;\r
+\r
+ // Start to search at Offset 0x100\r
+ // Get Capability Header\r
+ CapHeaderId = 0;\r
+ CapHeaderOffset = PCIE_CAP_EXT_HEARDER_OFFSET;\r
+\r
+ while (CapHeaderOffset != 0 && CapHeaderId != 0xFFFF) {\r
+ CapHeaderId = QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset);\r
+ if (CapHeaderId == CapId) {\r
+ return CapHeaderOffset;\r
+ }\r
+ CapHeaderOffset = (QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset + 2) >> 4);\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Map Vc on both root port and downstream device\r
+\r
+ @param[in] Bus1 Bus number of the root port\r
+ @param[in] Device1 Device number of the root port\r
+ @param[in] Function1 Function number of the root port\r
+ @param[in] Bus2 Bus number of the downstream device\r
+ @param[in] Device2 Device number of the downstream device\r
+ @param[in] Function2 Function number of the downstream device\r
+\r
+ @retval EFI_SUCCESS Map Vc successful\r
+\r
+**/\r
+EFI_STATUS\r
+PcieInitTcxVc0 (\r
+ IN UINT8 Bus1,\r
+ IN UINT8 Device1,\r
+ IN UINT8 Function1,\r
+ IN UINT8 Bus2,\r
+ IN UINT8 Device2,\r
+ IN UINT8 Function2\r
+ )\r
+{\r
+ UINT32 Offset;\r
+\r
+ //\r
+ // Initialize TCx-VC0 value on the port to only use TC0\r
+ //\r
+ Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2);\r
+ if (Offset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ QNCMmPci8AndThenOr (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1);\r
+\r
+ // Set TCx-VC0 value on the Endpoint\r
+\r
+ Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2);\r
+ if (Offset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ QNCMmPci8AndThenOr (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Map Traffic Class x to Vc0 on both root port and downstream device\r
+\r
+ @param[in] Bus1 Bus number of the root port\r
+ @param[in] Device1 Device number of the root port\r
+ @param[in] Function1 Function number of the root port\r
+ @param[in] Bus2 Bus number of the downstream device\r
+ @param[in] Device2 Device number of the downstream device\r
+ @param[in] Function2 Function number of the downstream device\r
+ @param[in] TCx Traffic Class to be mapped to vc0\r
+\r
+ @retval EFI_SUCCESS Map Tcx to Vc0 successful\r
+\r
+**/\r
+EFI_STATUS\r
+PcieMapTcxVc0 (\r
+ IN UINT8 Bus1,\r
+ IN UINT8 Device1,\r
+ IN UINT8 Function1,\r
+ IN UINT8 Bus2,\r
+ IN UINT8 Device2,\r
+ IN UINT8 Function2,\r
+ IN UINT8 TCx\r
+ )\r
+{\r
+ UINT32 Offset;\r
+\r
+ //\r
+ // Set TCx-VC0 value on the port\r
+ //\r
+\r
+ Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2);\r
+ if (Offset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ QNCMmPci8 (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx);\r
+\r
+ // Set TCx-VC0 value on the Endpoint\r
+\r
+ Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2);\r
+ if (Offset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ QNCMmPci8 (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Set common clock for both root port and downstream device.\r
+\r
+ @param[in] Bus1 Bus number of the root port\r
+ @param[in] Device1 Device number of the root port\r
+ @param[in] Function1 Function number of the root port\r
+ @param[in] Bus2 Device number of the downstream device\r
+ @param[in] Device2 Function number of the downstream device\r
+\r
+ @retval EFI_SUCCESS Set common clock successful\r
+\r
+**/\r
+EFI_STATUS\r
+PcieSetCommonClock (\r
+ IN UINT8 Bus1,\r
+ IN UINT8 Device1,\r
+ IN UINT8 Function1,\r
+ IN UINT8 Bus2,\r
+ IN UINT8 Device2\r
+ )\r
+{\r
+ UINT32 CapOffset1;\r
+ UINT32 CapOffset2;\r
+ UINT8 Function2;\r
+ UINT8 CommonClock;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Get the pointer to the Port PCI Express Capability Structure.\r
+ //\r
+ CommonClock = 0;\r
+ CapOffset1 = PcieFindCapId (Bus1, Device1, Function1, PCIE_CAPID);\r
+ if (CapOffset1 == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Step 1\r
+ // Read the Slot Clock Configuration bit of the Link status register of the root port and the endpoint device connected to the port\r
+ // If both components have this bit set to 1, then System BIOS should set the "Common Clock Configuration" bit in the Link Control Registers\r
+ // for both components at both sides of the link to indicate that components at both ends\r
+ // of the link use a common clock source\r
+ //\r
+\r
+ //\r
+ // Check the Port Slot Clock Configuration Bit.\r
+ //\r
+ if ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ for (Function2 = 0; Function2 < 8; Function2++) {\r
+ //\r
+ // Check the Endpoint Slot Clock Configuration Bit.\r
+ //\r
+ CapOffset2 = PcieFindCapId (Bus2, Device2, Function2, PCIE_CAPID);\r
+ if ((CapOffset2 != 0) &&\r
+ ((QNCMmPci16 (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) != 0)) {\r
+\r
+ //\r
+ // Common clock is supported, set common clock bit on root port\r
+ // and the endpoint\r
+ //\r
+ if (CommonClock == 0) {\r
+ QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC);\r
+ CommonClock++;\r
+ }\r
+ QNCMmPci8Or (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Step 2 If the Common Clock Configuration bit was changed by BIOS in step 1,\r
+ // System BIOS should initiate a link training by setting the Retrain Link bit\r
+ // in the Link Control register of the root port (D28:F0/F1 offset\r
+ // 50h [5]) to "1b" and then poll the Link Training bit in the Link Status\r
+ // register of the root port (D28:F0/F1/F2/F3/F4/F5 offset 52h [11]) until it is\r
+ // "0b".\r
+ //\r
+ if (CommonClock == 0) {\r
+ Status = EFI_UNSUPPORTED;\r
+ } else {\r
+ //\r
+ // Retrain the Link per PCI Express Specification.\r
+ //\r
+ QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_RL);\r
+\r
+ //\r
+ // Wait until Re-Training has completed.\r
+ //\r
+ while ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_LT) != 0);\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Enables the CLKREQ# PM on all the end point functions\r
+\r
+ @param[in] Bus Bus number of the downstream device\r
+ @param[in] Device Device number of the downstream device\r
+\r
+ @retval None\r
+\r
+**/\r
+VOID\r
+PcieSetClkreq (\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device\r
+ )\r
+{\r
+ UINT8 Function;\r
+ UINT32 CapOffset;\r
+\r
+ //\r
+ // Parse thro all the functions of the endpoint and find the PCIe Cap ID (offset 10h) and if\r
+ // exists then enable the CLKREQ# bit (BIT8) on that function\r
+ //\r
+ for (Function = 0; Function < 8; Function++) {\r
+ //\r
+ // Find the PCIe Cap Id (offset 10h)\r
+ //\r
+ CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);\r
+ if (CapOffset == 0) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Check if CLKREQ# is supported by the endpoints\r
+ //\r
+ if ((QNCMmPci32 (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CAP_OFFSET))\r
+ & B_QNC_PCIE_LCAP_CPM) != B_QNC_PCIE_LCAP_CPM) {\r
+ //\r
+ // CLKREQ# is not supported so dont do anything\r
+ //\r
+ return;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Now enable the CLKREQ#\r
+ //\r
+ for (Function = 0; Function < 8; Function++) {\r
+ //\r
+ // Find the PCIe Cap Id (offset 10h)\r
+ //\r
+ CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);\r
+ if (CapOffset == 0) {\r
+ continue;\r
+ }\r
+\r
+ QNCMmPci16Or (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CNT_OFFSET), BIT8);\r
+ }\r
+}\r
+\r
+/**\r
+\r
+ Configure ASPM automatically for both root port and downstream device.\r
+\r
+ @param[in] RootBus Bus number of the root port\r
+ @param[in] RootDevice Device number of the root port\r
+ @param[in] RootFunction Function number of the root port\r
+ @param[in] EndpointBus Bus number of the downstream device\r
+ @param[in] EndpointDevice Device number of the downstream device\r
+ @param[in] EndpointFunction Function number of the downstream device\r
+ @param[in] LinkAspmVal Currently used ASPM setting\r
+\r
+ @retval EFI_SUCCESS Configure ASPM successful\r
+\r
+**/\r
+EFI_STATUS\r
+PcieSetAspmAuto (\r
+ IN UINT8 RootBus,\r
+ IN UINT8 RootDevice,\r
+ IN UINT8 RootFunction,\r
+ IN UINT8 EndpointBus,\r
+ IN UINT8 EndpointDevice,\r
+ IN UINT8 EndpointFunction,\r
+ OUT UINT16 *LinkAspmVal\r
+ )\r
+{\r
+ UINT32 RootPcieCapOffset;\r
+ UINT32 EndpointPcieCapOffset;\r
+ UINT16 RootPortAspm;\r
+ UINT16 EndPointAspm;\r
+ UINT16 EndPointVendorId;\r
+ UINT16 EndPointDeviceId;\r
+ UINT8 EndPointRevId;\r
+ UINT16 AspmVal;\r
+ UINT32 PortLxLat;\r
+ UINT32 EndPointLxLat;\r
+ UINT32 LxLat;\r
+\r
+ //\r
+ // Get the pointer to the Port PCI Express Capability Structure.\r
+ //\r
+ RootPcieCapOffset = PcieFindCapId (RootBus, RootDevice, RootFunction, PCIE_CAPID);\r
+ if (RootPcieCapOffset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Get the pointer to the Endpoint PCI Express Capability Structure.\r
+ //\r
+ EndpointPcieCapOffset = PcieFindCapId (EndpointBus, EndpointDevice, EndpointFunction, PCIE_CAPID);\r
+ if (EndpointPcieCapOffset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Obtain initial ASPM settings from respective port capability registers.\r
+ //\r
+ RootPortAspm = (QNCMmPci16 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;\r
+\r
+ //\r
+ // Configure downstream device if present.\r
+ //\r
+ EndPointAspm = (QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;\r
+\r
+ //\r
+ // Mask APMC with values from lookup table.\r
+ // RevID of 0xFF applies to all steppings.\r
+ //\r
+\r
+ EndPointVendorId = QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, 0);\r
+ EndPointDeviceId = QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, 2);\r
+ EndPointRevId = QNCMmPci8 (0, EndpointBus, EndpointDevice, EndpointFunction, 8);\r
+\r
+ // TODO: Mask with latency/acceptable latency comparison results.\r
+\r
+ AspmVal = RootPortAspm;\r
+ if (RootPortAspm > EndPointAspm) {\r
+ AspmVal = EndPointAspm;\r
+ }\r
+\r
+ //\r
+ // Check if L1 should be enabled based on port and endpoint L1 exit latency.\r
+ //\r
+ if(AspmVal & BIT1) {\r
+ PortLxLat = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;\r
+ EndPointLxLat = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;\r
+\r
+ LxLat = PortLxLat;\r
+ if(PortLxLat < EndPointLxLat) {\r
+ LxLat = EndPointLxLat;\r
+ }\r
+\r
+ //\r
+ // check if the value is bigger than endpoint L1 acceptable exit latency, if it is\r
+ // larger than accepted value, then we should disable L1\r
+ //\r
+ LxLat >>= 6;\r
+ if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E1AL)) {\r
+ AspmVal &= ~BIT1;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check if L0s should be enabled based on port and endpoint L0s exit latency.\r
+ //\r
+ if(AspmVal & BIT0) {\r
+ PortLxLat = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset+ PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;\r
+ EndPointLxLat = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;\r
+\r
+ LxLat = PortLxLat;\r
+ if(PortLxLat < EndPointLxLat) {\r
+ LxLat = EndPointLxLat;\r
+ }\r
+\r
+ //\r
+ // check if the value is bigger than endpoint L0s acceptable exit latency, if it is\r
+ // larger than accepted value, then we should disable L0s\r
+ //\r
+ LxLat >>= 6;\r
+ if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E0AL)) {\r
+ AspmVal &= ~BIT0;\r
+ }\r
+ }\r
+\r
+ RootPortAspm = AspmVal;\r
+\r
+ *LinkAspmVal = AspmVal;\r
+ //\r
+ // Set Endpoint Aspm\r
+ //\r
+ QNCMmPci16AndThenOr (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, AspmVal);\r
+\r
+\r
+ //\r
+ // Set Root Port Aspm\r
+ //\r
+ QNCMmPci16AndThenOr (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, RootPortAspm);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Configure ASPM based on the given setting for the interested device.\r
+\r
+ @param[in] Bus Bus number of the interested device\r
+ @param[in] Device Device number of the interested device\r
+ @param[in] Function Function number of the interested device\r
+ @param[in] AspmSetting Aspm setting\r
+ @param[in] LinkAspmVal Currently used ASPM setting\r
+\r
+ @retval EFI_SUCCESS Configure ASPM successful\r
+\r
+**/\r
+EFI_STATUS\r
+PcieSetAspmManual (\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Function,\r
+ IN UINT8 AspmSetting,\r
+ OUT UINT16 *LinkAspmVal\r
+ )\r
+{\r
+ UINT32 PcieCapOffset;\r
+ UINT16 PortAspm;\r
+\r
+ //\r
+ // Get the pointer to the Port PCI Express Capability Structure.\r
+ //\r
+ PcieCapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);\r
+ if (PcieCapOffset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ // Read the Link Capability register's ASPM setting\r
+ PortAspm = (QNCMmPci16 (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;\r
+ // Mask it with the Setup selection\r
+ PortAspm &= AspmSetting;\r
+\r
+ *LinkAspmVal = PortAspm;\r
+ // Write it to the Link Control register\r
+ QNCMmPci16AndThenOr (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, PortAspm);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Perform Initialization on one PCI Express root port.\r
+\r
+ @param[in] RootPortIndex Index of PCI Express root port\r
+ @param[in] RootPortConfig Pointer to the given pcie root port configuration\r
+ @param[in] PciExpressBar Base address of pcie space\r
+ @param[in] QNCRootComplexBar Base address of root complex\r
+ @param[in] QNCPmioBase Base address of PM IO space\r
+ @param[in] QNCGpeBase Base address of gpe IO space\r
+\r
+ @retval EFI_SUCCESS Initialization successful\r
+\r
+**/\r
+EFI_STATUS\r
+QNCRootPortInit (\r
+ IN UINT32 RootPortIndex,\r
+ IN PCIEXP_ROOT_PORT_CONFIGURATION *RootPortConfig,\r
+ IN UINT64 PciExpressBar,\r
+ IN UINT32 QNCRootComplexBar,\r
+ IN UINT32 QNCPmioBase,\r
+ IN UINT32 QNCGpeBase\r
+ )\r
+{\r
+ UINT64 RPBase;\r
+ UINT64 EndPointBase;\r
+ UINT64 LpcBase;\r
+ UINT16 AspmVal;\r
+ UINT16 SlotStatus;\r
+ UINTN Index;\r
+ UINT32 CapOffset;\r
+ UINT32 DwordReg;\r
+\r
+ RPBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + ((PCI_DEVICE_NUMBER_PCIE_ROOTPORT) << 3) + ((PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex) << 0)) << 12);\r
+ LpcBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + (31 << 3) + (0 << 0)) << 12);\r
+ CapOffset = PcieFindCapId (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), PCIE_CAPID);\r
+\r
+ if (CapOffset == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Initialize "Slot Implmemented Bit" for this root port\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.SlotImplemented) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_XCAP, B_QNC_PCIE_XCAP_SI);\r
+ }\r
+\r
+ //\r
+ // For Root Port Slots Numbering on the CRBs.\r
+ // Root Port 0 = Slot 1\r
+ // Root Port 1 = Slot 2\r
+ // Root Port 2 = Slot 3\r
+ // Root Port 3 = Slot 4\r
+ //\r
+ DwordReg = QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP);\r
+ DwordReg &= B_QNC_PCIE_SLCAP_MASK_RSV_VALUE;\r
+ DwordReg |= (V_QNC_PCIE_SLCAP_SLV << V_QNC_PCIE_SLCAP_SLV_OFFSET);\r
+ DwordReg |= ((RootPortConfig[RootPortIndex].Bits.PhysicalSlotNumber) << V_QNC_PCIE_SLCAP_PSN_OFFSET) ;\r
+ QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP) = DwordReg;\r
+\r
+ //\r
+ // Check for a Presence Detect Change.\r
+ //\r
+ SlotStatus = QNCMmio16 (RPBase, R_QNC_PCIE_SLSTS);\r
+ if ((SlotStatus & (B_QNC_PCIE_SLSTS_PDS + B_QNC_PCIE_SLSTS_PDC)) == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Temporarily Hardcode the Root Port Bridge Number to 2.\r
+ //\r
+ // This Endpoint check should immediately pass. Howerver, a 900ms delay\r
+ // has been added to match the timing requirements of the PCI Express Base\r
+ // Specification, Revision 1.0A, Section 6.6 ("...software must allow 1.0s\r
+ // after a reset of a device, before it may determine that a device which\r
+ // fails to return a Successful Completion status for a valid Configuration\r
+ // Request is a broken device"). Note that a 100ms delay was already added\r
+ // after the Root Ports were first taken out of reset.\r
+ //\r
+ QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF, 0x00020200);\r
+ //\r
+ // Only do this when a downstream device is present\r
+ //\r
+ EndPointBase = PciExpressBar + (((2 << 8) + (0 << 3) + (0 << 0)) << 12);\r
+ if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {\r
+ for (Index = 0; Index < V_PCIE_MAX_TRY_TIMES; Index++){\r
+ if (QNCMmio16 (EndPointBase, 0x0) != 0xFFFF) {\r
+ break;\r
+ }\r
+ PcieStall (15);\r
+ }\r
+ if (Index >= V_PCIE_MAX_TRY_TIMES) {\r
+ //\r
+ // Clear Bus Numbers.\r
+ //\r
+ QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ }\r
+\r
+ //\r
+ // PCI Express* Virtual Channels\r
+ // Clear TC1-7 Traffic classes.\r
+ // Map TC0-VC0\r
+ //\r
+ PcieInitTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0);\r
+ PcieMapTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, 0x0);\r
+\r
+ //\r
+ // Set Common Clock for inserted cards\r
+ //\r
+ if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {\r
+ PcieSetCommonClock (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0);\r
+ }\r
+\r
+ //\r
+ // Flow for Enabling ASPM\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.AspmEnable) {\r
+ if (RootPortConfig[RootPortIndex].Bits.AspmAutoEnable) {\r
+ PcieSetAspmAuto (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, &AspmVal);\r
+ } else {\r
+ //\r
+ // Set ASPM values according to setup selections, masked by capabilities\r
+ //\r
+ PcieSetAspmManual (\r
+ PCI_BUS_NUMBER_QNC,\r
+ (UINT8) (PCI_DEVICE_NUMBER_PCIE_ROOTPORT),\r
+ (UINT8) (PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex),\r
+ (UINT8) ((RootPortConfig[RootPortIndex].Bits.AspmL0sEnable & 0x01) | (RootPortConfig[RootPortIndex].Bits.AspmL1Enable << 1)),\r
+ &AspmVal\r
+ );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Enable the PCIe CLKREQ#\r
+ //\r
+ if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {\r
+ PcieSetClkreq (2, 0);\r
+ }\r
+\r
+ //\r
+ // Clear Bus Numbers\r
+ //\r
+ QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);\r
+\r
+ //\r
+ // Additional configurations\r
+ //\r
+\r
+ //\r
+ // PCI-E Unsupported Request Reporting Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_URE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_URE);\r
+ }\r
+\r
+ //\r
+ // Device Fatal Error Reporting Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_FEE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_FEE);\r
+ }\r
+\r
+ //\r
+ // Device Non Fatal Error Reporting Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_NFE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_NFE);\r
+ }\r
+\r
+ //\r
+ // Device Correctable Error Reporting Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_CEE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_CEE);\r
+ }\r
+ //\r
+ // Root PCI-E PME Interrupt Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PmeInterruptEnable) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_PIE);\r
+ }\r
+ //\r
+ // Root PCI-E System Error on Fatal Error Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SFE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SFE);\r
+ }\r
+\r
+ //\r
+ // Root PCI-E System Error on Non-Fatal Error Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SNE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SNE);\r
+ }\r
+\r
+ //\r
+ // Root PCI-E System Error on Correctable Error Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SCE_ENABLE) {\r
+ QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SCE);\r
+ }\r
+\r
+ //\r
+ // Root PCI-E Powermanagement SCI Enabled\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.PmSciEnable) {\r
+ //\r
+ // Make sure that PME Interrupt Enable bit of Root Control register\r
+ // of PCI Express Capability struceture is cleared\r
+ //\r
+ QNCMmio32And (RPBase, R_QNC_PCIE_RCTL, (~B_QNC_PCIE_RCTL_PIE));\r
+ QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_PMME), B_QNC_PCIE_MPC_PMCE);\r
+\r
+ //\r
+ // Make sure GPE0 Stutus RW1C Bit is clear.\r
+ //\r
+ DwordReg = IoRead32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S);\r
+ if ((DwordReg & B_QNC_GPE0BLK_GPE0S_PCIE) != 0) {\r
+ IoWrite32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S, B_QNC_GPE0BLK_GPE0S_PCIE);\r
+ }\r
+ }\r
+\r
+ //\r
+ // PCIe Hot Plug SCI Enable\r
+ //\r
+ if (RootPortConfig[RootPortIndex].Bits.HotplugSciEnable) {\r
+ //\r
+ // Write clear for :\r
+ // Attention Button Pressed (bit0)\r
+ // Presence Detect Changed (bit3)\r
+ //\r
+ QNCMmio32Or (RPBase, R_QNC_PCIE_SLSTS, (B_QNC_PCIE_SLSTS_PDC | B_QNC_PCIE_SLSTS_ABP));\r
+\r
+ //\r
+ // Sequence 2: Program the following bits in Slot Control register at offset 18h\r
+ // of PCI Express* Capability structure:\r
+ // Attention Button Pressed Enable (bit0) = 1b\r
+ // Presence Detect Changed Enable (bit3) = 1b\r
+ // Hot Plug Interrupt Enable (bit5) = 0b\r
+ //\r
+ QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_SLCTL, (~B_QNC_PCIE_SLCTL_HPE), (B_QNC_PCIE_SLCTL_PDE | B_QNC_PCIE_SLCTL_ABE));\r
+\r
+ //\r
+ // Sequence 3: Program Misc Port Config (MPC) register at PCI config space offset\r
+ // D8h as follows:\r
+ // Hot Plug SCI Enable (HPCE, bit30) = 1b\r
+ // Hot Plug SMI Enable (HPME, bit1) = 0b\r
+ //\r
+ QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_HPME), B_QNC_PCIE_MPC_HPCE);\r
+ }\r
+\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Perform Initialization of the Downstream Root Ports\r
+**/\r
+VOID\r
+QNCDownStreamPortsInit (\r
+ IN PCIEXP_ROOT_PORT_CONFIGURATION *RootPortConfig,\r
+ IN QNC_DEVICE_ENABLES *QNCDeviceEnables,\r
+ IN UINT64 PciExpressBar,\r
+ IN UINT32 QNCRootComplexBar,\r
+ IN UINT32 QNCPmioBase,\r
+ IN UINT32 QNCGpeBase,\r
+ OUT UINTN *RpEnableMask\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Index;\r
+\r
+ //\r
+ // Initialize every root port and downstream device\r
+ //\r
+ for (Index = 0;Index < MAX_PCI_EXPRESS_ROOT_PORTS;Index++) {\r
+ if ((QNCDeviceEnables->Uint32 & (1 << Index)) != 0) {\r
+ Status = QNCRootPortInit (\r
+ Index,\r
+ RootPortConfig,\r
+ PciExpressBar,\r
+ QNCRootComplexBar,\r
+ QNCPmioBase,\r
+ QNCGpeBase\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ (*RpEnableMask) |= LShiftU64(1, Index);\r
+ DEBUG ((EFI_D_INFO, " Root Port %x device found, enabled. RpEnableMask: 0x%x\n", Index + 1, *RpEnableMask));\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Do early init of pci express rootports on Soc.\r
+\r
+**/\r
+\r
+VOID\r
+EFIAPI\r
+PciExpressEarlyInit (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Setup Message Bus Idle Counter (SBIC) values.\r
+ //\r
+ 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);\r
+ 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);\r
+\r
+ //\r
+ // Program SVID/SID the same as VID/DID for Root ports.\r
+ //\r
+ 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);\r
+ 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);\r
+\r
+ //\r
+ // Set the IPF bit in MCR2\r
+ //\r
+ 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);\r
+ 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);\r
+\r
+ //\r
+ // Set up the Posted and Non Posted Request sizes for PCIe\r
+ //\r
+ 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));\r
+\r
+ return;\r
+}\r
+\r
+\r
+/**\r
+ Complete initialization all the pci express rootports on Soc.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PciExpressInit (\r
+ )\r
+{\r
+ UINT64 PciExpressBar;\r
+ UINT32 QNCRootComplexBar;\r
+ UINT32 QNCGpioBase;\r
+ UINT32 QNCPmioBase;\r
+ UINT32 QNCGpeBase;\r
+ UINTN RpEnableMask;\r
+ PCIEXP_ROOT_PORT_CONFIGURATION *mRootPortConfig;\r
+ QNC_DEVICE_ENABLES mQNCDeviceEnables;\r
+\r
+ //\r
+ // Get BAR registers\r
+ //\r
+ QNCRootComplexBar = QNC_RCRB_BASE;\r
+ QNCGpioBase = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK;\r
+ QNCPmioBase = LpcPciCfg32 (R_QNC_LPC_PM1BLK) & B_QNC_LPC_PM1BLK_MASK;\r
+ QNCGpeBase = LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & B_QNC_LPC_GPE0BLK_MASK;\r
+ RpEnableMask = 0; // assume all root ports are disabled\r
+\r
+ PciExpressBar = PcdGet64 (PcdPciExpressBaseAddress);\r
+\r
+ //\r
+ // Get platform information from PCD entries\r
+ //\r
+ mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables);\r
+ mRootPortConfig = (PCIEXP_ROOT_PORT_CONFIGURATION*) PcdGetPtr (PcdPcieRootPortConfiguration);\r
+\r
+ DEBUG ((EFI_D_INFO, " mRootPortConfig: 0x%x, value1: 0x%x, value2: 0x%x, value3: 0x%x, value4: 0x%x\n",\r
+ mRootPortConfig, mRootPortConfig[0].Uint32, mRootPortConfig[1].Uint32,\r
+ mRootPortConfig[2].Uint32, mRootPortConfig[3].Uint32));\r
+\r
+ QNCDownStreamPortsInit (\r
+ mRootPortConfig,\r
+ &mQNCDeviceEnables,\r
+ PciExpressBar,\r
+ QNCRootComplexBar,\r
+ QNCPmioBase,\r
+ QNCGpeBase,\r
+ &RpEnableMask\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+MTRR setting library\r
+\r
+Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+\r
+#include <Library/MtrrLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/CpuLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/QNCAccessLib.h>\r
+\r
+#define QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING 0x590\r
+\r
+//\r
+// Context to save and restore when MTRRs are programmed\r
+//\r
+typedef struct {\r
+ UINTN Cr4;\r
+ BOOLEAN InterruptState;\r
+} MTRR_CONTEXT;\r
+\r
+//\r
+// This table defines the offset, base and length of the fixed MTRRs\r
+//\r
+CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {\r
+ { QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000, 0, SIZE_64KB },\r
+ { QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_80000, 0x80000, SIZE_16KB },\r
+ { QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_A0000, 0xA0000, SIZE_16KB },\r
+ { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C0000, 0xC0000, SIZE_4KB },\r
+ { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C8000, 0xC8000, SIZE_4KB },\r
+ { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D0000, 0xD0000, SIZE_4KB },\r
+ { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D8000, 0xD8000, SIZE_4KB },\r
+ { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E0000, 0xE0000, SIZE_4KB },\r
+ { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E8000, 0xE8000, SIZE_4KB },\r
+ { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F0000, 0xF0000, SIZE_4KB },\r
+ { QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000, 0xF8000, SIZE_4KB }\r
+};\r
+\r
+//\r
+// Lookup table used to print MTRRs\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {\r
+ "UC", // CacheUncacheable\r
+ "WC", // CacheWriteCombining\r
+ "R*", // Invalid\r
+ "R*", // Invalid\r
+ "WT", // CacheWriteThrough\r
+ "WP", // CacheWriteProtected\r
+ "WB", // CacheWriteBack\r
+ "R*" // Invalid\r
+};\r
+\r
+UINT64\r
+MtrrRegisterRead (\r
+ IN UINT32 MtrrRegister\r
+ )\r
+{\r
+ UINT64 Result;\r
+\r
+ Result = (UINT64)QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister);\r
+ if (MtrrRegister >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 && MtrrRegister <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000) {\r
+ Result = Result | LShiftU64 ((UINT64)QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister + 1), 32);\r
+ }\r
+ return Result;\r
+}\r
+\r
+UINT64\r
+MtrrRegisterWrite (\r
+ IN UINT32 MtrrRegister,\r
+ IN UINT64 Value\r
+ )\r
+{\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister, (UINT32)Value);\r
+ if (MtrrRegister >= QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 && MtrrRegister <= QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000) {\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, MtrrRegister + 1, (UINT32)RShiftU64 (Value, 32));\r
+ }\r
+ return Value;\r
+}\r
+\r
+UINT64\r
+MtrrRegisterBitFieldWrite (\r
+ IN UINT32 MtrrRegister,\r
+ IN UINTN StartBit,\r
+ IN UINTN EndBit,\r
+ IN UINT64 Value\r
+ )\r
+{\r
+ return MtrrRegisterWrite (\r
+ MtrrRegister,\r
+ BitFieldWrite64 (\r
+ MtrrRegisterRead (MtrrRegister),\r
+ StartBit,\r
+ EndBit,\r
+ Value\r
+ )\r
+ );\r
+}\r
+\r
+/**\r
+ Worker function returns the variable MTRR count for the CPU.\r
+\r
+ @return Variable MTRR count\r
+\r
+**/\r
+UINT32\r
+GetVariableMtrrCountWorker (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 VariableMtrrCount;\r
+\r
+ VariableMtrrCount = (UINT32)(MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_CAP) & MTRR_LIB_IA32_MTRR_CAP_VCNT_MASK);\r
+ ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+ return VariableMtrrCount;\r
+}\r
+\r
+/**\r
+ Returns the variable MTRR count for the CPU.\r
+\r
+ @return Variable MTRR count\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetVariableMtrrCount (\r
+ VOID\r
+ )\r
+{\r
+ if (!IsMtrrSupported ()) {\r
+ return 0;\r
+ }\r
+ return GetVariableMtrrCountWorker ();\r
+}\r
+\r
+/**\r
+ Worker function returns the firmware usable variable MTRR count for the CPU.\r
+\r
+ @return Firmware usable variable MTRR count\r
+\r
+**/\r
+UINT32\r
+GetFirmwareVariableMtrrCountWorker (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 VariableMtrrCount;\r
+ UINT32 ReservedMtrrNumber;\r
+\r
+ VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+ ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);\r
+ if (VariableMtrrCount < ReservedMtrrNumber) {\r
+ return 0;\r
+ }\r
+\r
+ return VariableMtrrCount - ReservedMtrrNumber;\r
+}\r
+\r
+/**\r
+ Returns the firmware usable variable MTRR count for the CPU.\r
+\r
+ @return Firmware usable variable MTRR count\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetFirmwareVariableMtrrCount (\r
+ VOID\r
+ )\r
+{\r
+ if (!IsMtrrSupported ()) {\r
+ return 0;\r
+ }\r
+ return GetFirmwareVariableMtrrCountWorker ();\r
+}\r
+\r
+/**\r
+ Worker function returns the default MTRR cache type for the system.\r
+\r
+ If MtrrSetting is not NULL, returns the default MTRR cache type from input\r
+ MTRR settings buffer.\r
+ If MtrrSetting is NULL, returns the default MTRR cache type from MSR.\r
+\r
+ @param[in] MtrrSetting A buffer holding all MTRRs content.\r
+\r
+ @return The default MTRR cache type.\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+MtrrGetDefaultMemoryTypeWorker (\r
+ IN MTRR_SETTINGS *MtrrSetting\r
+ )\r
+{\r
+ if (MtrrSetting == NULL) {\r
+ return (MTRR_MEMORY_CACHE_TYPE) (MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE) & 0x7);\r
+ } else {\r
+ return (MTRR_MEMORY_CACHE_TYPE) (MtrrSetting->MtrrDefType & 0x7);\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Returns the default MTRR cache type for the system.\r
+\r
+ @return The default MTRR cache type.\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+EFIAPI\r
+MtrrGetDefaultMemoryType (\r
+ VOID\r
+ )\r
+{\r
+ if (!IsMtrrSupported ()) {\r
+ return CacheUncacheable;\r
+ }\r
+ return MtrrGetDefaultMemoryTypeWorker (NULL);\r
+}\r
+\r
+/**\r
+ Preparation before programming MTRR.\r
+\r
+ This function will do some preparation for programming MTRRs:\r
+ disable cache, invalid cache and disable MTRR caching functionality\r
+\r
+ @param[out] MtrrContext Pointer to context to save\r
+\r
+**/\r
+VOID\r
+PreMtrrChange (\r
+ OUT MTRR_CONTEXT *MtrrContext\r
+ )\r
+{\r
+ //\r
+ // Disable interrupts and save current interrupt state\r
+ //\r
+ MtrrContext->InterruptState = SaveAndDisableInterrupts();\r
+\r
+ //\r
+ // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)\r
+ //\r
+ AsmDisableCache ();\r
+\r
+ //\r
+ // Save original CR4 value and clear PGE flag (Bit 7)\r
+ //\r
+ MtrrContext->Cr4 = AsmReadCr4 ();\r
+ AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));\r
+\r
+ //\r
+ // Flush all TLBs\r
+ //\r
+ CpuFlushTlb ();\r
+\r
+ //\r
+ // Disable MTRRs\r
+ //\r
+ MtrrRegisterBitFieldWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, 10, 11, 0);\r
+}\r
+\r
+/**\r
+ Cleaning up after programming MTRRs.\r
+\r
+ This function will do some clean up after programming MTRRs:\r
+ Flush all TLBs, re-enable caching, restore CR4.\r
+\r
+ @param[in] MtrrContext Pointer to context to restore\r
+\r
+**/\r
+VOID\r
+PostMtrrChangeEnableCache (\r
+ IN MTRR_CONTEXT *MtrrContext\r
+ )\r
+{\r
+ //\r
+ // Flush all TLBs\r
+ //\r
+ CpuFlushTlb ();\r
+\r
+ //\r
+ // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)\r
+ //\r
+ AsmEnableCache ();\r
+\r
+ //\r
+ // Restore original CR4 value\r
+ //\r
+ AsmWriteCr4 (MtrrContext->Cr4);\r
+\r
+ //\r
+ // Restore original interrupt state\r
+ //\r
+ SetInterruptState (MtrrContext->InterruptState);\r
+}\r
+\r
+/**\r
+ Cleaning up after programming MTRRs.\r
+\r
+ This function will do some clean up after programming MTRRs:\r
+ enable MTRR caching functionality, and enable cache\r
+\r
+ @param[in] MtrrContext Pointer to context to restore\r
+\r
+**/\r
+VOID\r
+PostMtrrChange (\r
+ IN MTRR_CONTEXT *MtrrContext\r
+ )\r
+{\r
+ //\r
+ // Enable Cache MTRR\r
+ //\r
+ MtrrRegisterBitFieldWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, 10, 11, 3);\r
+\r
+ PostMtrrChangeEnableCache (MtrrContext);\r
+}\r
+\r
+/**\r
+ Worker function gets the content in fixed MTRRs\r
+\r
+ @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
+\r
+ @retval The pointer of FixedSettings\r
+\r
+**/\r
+MTRR_FIXED_SETTINGS*\r
+MtrrGetFixedMtrrWorker (\r
+ OUT MTRR_FIXED_SETTINGS *FixedSettings\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+ FixedSettings->Mtrr[Index] =\r
+ MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr);\r
+ }\r
+\r
+ return FixedSettings;\r
+}\r
+\r
+\r
+/**\r
+ This function gets the content in fixed MTRRs\r
+\r
+ @param[out] FixedSettings A buffer to hold fixed MTRRs content.\r
+\r
+ @retval The pointer of FixedSettings\r
+\r
+**/\r
+MTRR_FIXED_SETTINGS*\r
+EFIAPI\r
+MtrrGetFixedMtrr (\r
+ OUT MTRR_FIXED_SETTINGS *FixedSettings\r
+ )\r
+{\r
+ if (!IsMtrrSupported ()) {\r
+ return FixedSettings;\r
+ }\r
+\r
+ return MtrrGetFixedMtrrWorker (FixedSettings);\r
+}\r
+\r
+\r
+/**\r
+ Worker function will get the raw value in variable MTRRs\r
+\r
+ If MtrrSetting is not NULL, gets the variable MTRRs raw value from input\r
+ MTRR settings buffer.\r
+ If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.\r
+\r
+ @param[in] MtrrSetting A buffer holding all MTRRs content.\r
+ @param[in] VariableMtrrCount Number of variable MTRRs.\r
+ @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
+\r
+ @return The VariableSettings input pointer\r
+\r
+**/\r
+MTRR_VARIABLE_SETTINGS*\r
+MtrrGetVariableMtrrWorker (\r
+ IN MTRR_SETTINGS *MtrrSetting,\r
+ IN UINT32 VariableMtrrCount,\r
+ OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ if (MtrrSetting == NULL) {\r
+ VariableSettings->Mtrr[Index].Base =\r
+ MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1));\r
+ VariableSettings->Mtrr[Index].Mask =\r
+ MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1);\r
+ } else {\r
+ VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;\r
+ VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;\r
+ }\r
+ }\r
+\r
+ return VariableSettings;\r
+}\r
+\r
+/**\r
+ This function will get the raw value in variable MTRRs\r
+\r
+ @param[out] VariableSettings A buffer to hold variable MTRRs content.\r
+\r
+ @return The VariableSettings input pointer\r
+\r
+**/\r
+MTRR_VARIABLE_SETTINGS*\r
+EFIAPI\r
+MtrrGetVariableMtrr (\r
+ OUT MTRR_VARIABLE_SETTINGS *VariableSettings\r
+ )\r
+{\r
+ if (!IsMtrrSupported ()) {\r
+ return VariableSettings;\r
+ }\r
+\r
+ return MtrrGetVariableMtrrWorker (\r
+ NULL,\r
+ GetVariableMtrrCountWorker (),\r
+ VariableSettings\r
+ );\r
+}\r
+\r
+/**\r
+ Programs fixed MTRRs registers.\r
+\r
+ @param[in] MemoryCacheType The memory type to set.\r
+ @param[in, out] Base The base address of memory range.\r
+ @param[in, out] Length The length of memory range.\r
+ @param[out] ReturnMsrNum The index of the fixed MTRR MSR to program.\r
+ @param[out] ReturnClearMask The bits to clear in the fixed MTRR MSR.\r
+ @param[out] ReturnOrMask The bits to set in the fixed MTRR MSR.\r
+\r
+ @retval RETURN_SUCCESS The cache type was updated successfully\r
+ @retval RETURN_UNSUPPORTED The requested range or cache type was invalid\r
+ for the fixed MTRRs.\r
+\r
+**/\r
+RETURN_STATUS\r
+ProgramFixedMtrr (\r
+ IN UINT64 MemoryCacheType,\r
+ IN OUT UINT64 *Base,\r
+ IN OUT UINT64 *Length,\r
+ OUT UINT32 *ReturnMsrNum,\r
+ OUT UINT64 *ReturnClearMask,\r
+ OUT UINT64 *ReturnOrMask\r
+ )\r
+{\r
+ UINT32 MsrNum;\r
+ UINT32 ByteShift;\r
+ UINT64 TempQword;\r
+ UINT64 OrMask;\r
+ UINT64 ClearMask;\r
+\r
+ TempQword = 0;\r
+ OrMask = 0;\r
+ ClearMask = 0;\r
+\r
+ for (MsrNum = 0; MsrNum < MTRR_NUMBER_OF_FIXED_MTRR; MsrNum++) {\r
+ if ((*Base >= mMtrrLibFixedMtrrTable[MsrNum].BaseAddress) &&\r
+ (*Base <\r
+ (\r
+ mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
+ (8 * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
+ )\r
+ )\r
+ ) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (MsrNum == MTRR_NUMBER_OF_FIXED_MTRR) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // We found the fixed MTRR to be programmed\r
+ //\r
+ for (ByteShift = 0; ByteShift < 8; ByteShift++) {\r
+ if (*Base ==\r
+ (\r
+ mMtrrLibFixedMtrrTable[MsrNum].BaseAddress +\r
+ (ByteShift * mMtrrLibFixedMtrrTable[MsrNum].Length)\r
+ )\r
+ ) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (ByteShift == 8) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ for (\r
+ ;\r
+ ((ByteShift < 8) && (*Length >= mMtrrLibFixedMtrrTable[MsrNum].Length));\r
+ ByteShift++\r
+ ) {\r
+ OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));\r
+ ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));\r
+ *Length -= mMtrrLibFixedMtrrTable[MsrNum].Length;\r
+ *Base += mMtrrLibFixedMtrrTable[MsrNum].Length;\r
+ }\r
+\r
+ if (ByteShift < 8 && (*Length != 0)) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ *ReturnMsrNum = MsrNum;\r
+ *ReturnClearMask = ClearMask;\r
+ *ReturnOrMask = OrMask;\r
+\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Worker function gets the attribute of variable MTRRs.\r
+\r
+ This function shadows the content of variable MTRRs into an\r
+ internal array: VariableMtrr.\r
+\r
+ @param[in] VariableSettings The variable MTRR values to shadow\r
+ @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available to firmware\r
+ @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
+ @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
+ @param[out] VariableMtrr The array to shadow variable MTRRs content\r
+\r
+ @return The return value of this parameter indicates the\r
+ number of MTRRs which has been used.\r
+\r
+**/\r
+UINT32\r
+MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+ IN MTRR_VARIABLE_SETTINGS *VariableSettings,\r
+ IN UINTN FirmwareVariableMtrrCount,\r
+ IN UINT64 MtrrValidBitsMask,\r
+ IN UINT64 MtrrValidAddressMask,\r
+ OUT VARIABLE_MTRR *VariableMtrr\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINT32 UsedMtrr;\r
+\r
+ ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+ for (Index = 0, UsedMtrr = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
+ if ((VariableSettings->Mtrr[Index].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) != 0) {\r
+ VariableMtrr[Index].Msr = (UINT32)Index;\r
+ VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);\r
+ VariableMtrr[Index].Length = ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;\r
+ VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);\r
+ VariableMtrr[Index].Valid = TRUE;\r
+ VariableMtrr[Index].Used = TRUE;\r
+ UsedMtrr++;\r
+ }\r
+ }\r
+ return UsedMtrr;\r
+}\r
+\r
+\r
+/**\r
+ Gets the attribute of variable MTRRs.\r
+\r
+ This function shadows the content of variable MTRRs into an\r
+ internal array: VariableMtrr.\r
+\r
+ @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
+ @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
+ @param[out] VariableMtrr The array to shadow variable MTRRs content\r
+\r
+ @return The return value of this paramter indicates the\r
+ number of MTRRs which has been used.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+MtrrGetMemoryAttributeInVariableMtrr (\r
+ IN UINT64 MtrrValidBitsMask,\r
+ IN UINT64 MtrrValidAddressMask,\r
+ OUT VARIABLE_MTRR *VariableMtrr\r
+ )\r
+{\r
+ MTRR_VARIABLE_SETTINGS VariableSettings;\r
+\r
+ if (!IsMtrrSupported ()) {\r
+ return 0;\r
+ }\r
+\r
+ MtrrGetVariableMtrrWorker (\r
+ NULL,\r
+ GetVariableMtrrCountWorker (),\r
+ &VariableSettings\r
+ );\r
+\r
+ return MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+ &VariableSettings,\r
+ GetFirmwareVariableMtrrCountWorker (),\r
+ MtrrValidBitsMask,\r
+ MtrrValidAddressMask,\r
+ VariableMtrr\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Checks overlap between given memory range and MTRRs.\r
+\r
+ @param[in] FirmwareVariableMtrrCount The number of variable MTRRs available\r
+ to firmware.\r
+ @param[in] Start The start address of memory range.\r
+ @param[in] End The end address of memory range.\r
+ @param[in] VariableMtrr The array to shadow variable MTRRs content\r
+\r
+ @retval TRUE Overlap exists.\r
+ @retval FALSE No overlap.\r
+\r
+**/\r
+BOOLEAN\r
+CheckMemoryAttributeOverlap (\r
+ IN UINTN FirmwareVariableMtrrCount,\r
+ IN PHYSICAL_ADDRESS Start,\r
+ IN PHYSICAL_ADDRESS End,\r
+ IN VARIABLE_MTRR *VariableMtrr\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
+ if (\r
+ VariableMtrr[Index].Valid &&\r
+ !(\r
+ (Start > (VariableMtrr[Index].BaseAddress +\r
+ VariableMtrr[Index].Length - 1)\r
+ ) ||\r
+ (End < VariableMtrr[Index].BaseAddress)\r
+ )\r
+ ) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Marks a variable MTRR as non-valid.\r
+\r
+ @param[in] Index The index of the array VariableMtrr to be invalidated\r
+ @param[in] VariableMtrr The array to shadow variable MTRRs content\r
+ @param[out] UsedMtrr The number of MTRRs which has already been used\r
+\r
+**/\r
+VOID\r
+InvalidateShadowMtrr (\r
+ IN UINTN Index,\r
+ IN VARIABLE_MTRR *VariableMtrr,\r
+ OUT UINT32 *UsedMtrr\r
+ )\r
+{\r
+ VariableMtrr[Index].Valid = FALSE;\r
+ *UsedMtrr = *UsedMtrr - 1;\r
+}\r
+\r
+\r
+/**\r
+ Combines memory attributes.\r
+\r
+ If overlap exists between given memory range and MTRRs, try to combine them.\r
+\r
+ @param[in] FirmwareVariableMtrrCount The number of variable MTRRs\r
+ available to firmware.\r
+ @param[in] Attributes The memory type to set.\r
+ @param[in, out] Base The base address of memory range.\r
+ @param[in, out] Length The length of memory range.\r
+ @param[in] VariableMtrr The array to shadow variable MTRRs content\r
+ @param[in, out] UsedMtrr The number of MTRRs which has already been used\r
+ @param[out] OverwriteExistingMtrr Returns whether an existing MTRR was used\r
+\r
+ @retval EFI_SUCCESS Memory region successfully combined.\r
+ @retval EFI_ACCESS_DENIED Memory region cannot be combined.\r
+\r
+**/\r
+RETURN_STATUS\r
+CombineMemoryAttribute (\r
+ IN UINT32 FirmwareVariableMtrrCount,\r
+ IN UINT64 Attributes,\r
+ IN OUT UINT64 *Base,\r
+ IN OUT UINT64 *Length,\r
+ IN VARIABLE_MTRR *VariableMtrr,\r
+ IN OUT UINT32 *UsedMtrr,\r
+ OUT BOOLEAN *OverwriteExistingMtrr\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINT64 CombineStart;\r
+ UINT64 CombineEnd;\r
+ UINT64 MtrrEnd;\r
+ UINT64 EndAddress;\r
+ BOOLEAN CoveredByExistingMtrr;\r
+\r
+ *OverwriteExistingMtrr = FALSE;\r
+ CoveredByExistingMtrr = FALSE;\r
+ EndAddress = *Base +*Length - 1;\r
+\r
+ for (Index = 0; Index < FirmwareVariableMtrrCount; Index++) {\r
+\r
+ MtrrEnd = VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length - 1;\r
+ if (\r
+ !VariableMtrr[Index].Valid ||\r
+ (\r
+ *Base > (MtrrEnd) ||\r
+ (EndAddress < VariableMtrr[Index].BaseAddress)\r
+ )\r
+ ) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Combine same attribute MTRR range\r
+ //\r
+ if (Attributes == VariableMtrr[Index].Type) {\r
+ //\r
+ // if the MTRR range contain the request range, set a flag, then continue to\r
+ // invalidate any MTRR of the same request range with higher priority cache type.\r
+ //\r
+ if (VariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {\r
+ CoveredByExistingMtrr = TRUE;\r
+ continue;\r
+ }\r
+ //\r
+ // invalid this MTRR, and program the combine range\r
+ //\r
+ CombineStart =\r
+ (*Base) < VariableMtrr[Index].BaseAddress ?\r
+ (*Base) :\r
+ VariableMtrr[Index].BaseAddress;\r
+ CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;\r
+\r
+ //\r
+ // Record the MTRR usage status in VariableMtrr array.\r
+ //\r
+ InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
+ *Base = CombineStart;\r
+ *Length = CombineEnd - CombineStart + 1;\r
+ EndAddress = CombineEnd;\r
+ *OverwriteExistingMtrr = TRUE;\r
+ continue;\r
+ } else {\r
+ //\r
+ // The cache type is different, but the range is convered by one MTRR\r
+ //\r
+ if (VariableMtrr[Index].BaseAddress == *Base && MtrrEnd == EndAddress) {\r
+ InvalidateShadowMtrr (Index, VariableMtrr, UsedMtrr);\r
+ continue;\r
+ }\r
+\r
+ }\r
+\r
+ if ((Attributes== MTRR_CACHE_WRITE_THROUGH &&\r
+ VariableMtrr[Index].Type == MTRR_CACHE_WRITE_BACK) ||\r
+ (Attributes == MTRR_CACHE_WRITE_BACK &&\r
+ VariableMtrr[Index].Type == MTRR_CACHE_WRITE_THROUGH) ||\r
+ (Attributes == MTRR_CACHE_UNCACHEABLE) ||\r
+ (VariableMtrr[Index].Type == MTRR_CACHE_UNCACHEABLE)\r
+ ) {\r
+ *OverwriteExistingMtrr = TRUE;\r
+ continue;\r
+ }\r
+ //\r
+ // Other type memory overlap is invalid\r
+ //\r
+ return RETURN_ACCESS_DENIED;\r
+ }\r
+\r
+ if (CoveredByExistingMtrr) {\r
+ *Length = 0;\r
+ }\r
+\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Calculates the maximum value which is a power of 2, but less the MemoryLength.\r
+\r
+ @param[in] MemoryLength The number to pass in.\r
+\r
+ @return The maximum value which is align to power of 2 and less the MemoryLength\r
+\r
+**/\r
+UINT64\r
+Power2MaxMemory (\r
+ IN UINT64 MemoryLength\r
+ )\r
+{\r
+ UINT64 Result;\r
+\r
+ if (RShiftU64 (MemoryLength, 32) != 0) {\r
+ Result = LShiftU64 (\r
+ (UINT64) GetPowerOfTwo32 (\r
+ (UINT32) RShiftU64 (MemoryLength, 32)\r
+ ),\r
+ 32\r
+ );\r
+ } else {\r
+ Result = (UINT64) GetPowerOfTwo32 ((UINT32) MemoryLength);\r
+ }\r
+\r
+ return Result;\r
+}\r
+\r
+\r
+/**\r
+ Determines the MTRR numbers used to program a memory range.\r
+\r
+ This function first checks the alignment of the base address.\r
+ If the alignment of the base address <= Length, cover the memory range\r
+ (BaseAddress, alignment) by a MTRR, then BaseAddress += alignment and\r
+ Length -= alignment. Repeat the step until alignment > Length.\r
+\r
+ Then this function determines which direction of programming the variable\r
+ MTRRs for the remaining length will use fewer MTRRs.\r
+\r
+ @param[in] BaseAddress Length of Memory to program MTRR\r
+ @param[in] Length Length of Memory to program MTRR\r
+ @param[in] MtrrNumber Pointer to the number of necessary MTRRs\r
+\r
+ @retval TRUE Positive direction is better.\r
+ FALSE Negative direction is better.\r
+\r
+**/\r
+BOOLEAN\r
+GetMtrrNumberAndDirection (\r
+ IN UINT64 BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINTN *MtrrNumber\r
+ )\r
+{\r
+ UINT64 TempQword;\r
+ UINT64 Alignment;\r
+ UINT32 Positive;\r
+ UINT32 Subtractive;\r
+\r
+ *MtrrNumber = 0;\r
+\r
+ if (BaseAddress != 0) {\r
+ do {\r
+ //\r
+ // Calculate the alignment of the base address.\r
+ //\r
+ Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
+\r
+ if (Alignment > Length) {\r
+ break;\r
+ }\r
+\r
+ (*MtrrNumber)++;\r
+ BaseAddress += Alignment;\r
+ Length -= Alignment;\r
+ } while (TRUE);\r
+\r
+ if (Length == 0) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ TempQword = Length;\r
+ Positive = 0;\r
+ Subtractive = 0;\r
+\r
+ do {\r
+ TempQword -= Power2MaxMemory (TempQword);\r
+ Positive++;\r
+ } while (TempQword != 0);\r
+\r
+ TempQword = Power2MaxMemory (LShiftU64 (Length, 1)) - Length;\r
+ Subtractive++;\r
+ do {\r
+ TempQword -= Power2MaxMemory (TempQword);\r
+ Subtractive++;\r
+ } while (TempQword != 0);\r
+\r
+ if (Positive <= Subtractive) {\r
+ *MtrrNumber += Positive;\r
+ return TRUE;\r
+ } else {\r
+ *MtrrNumber += Subtractive;\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+/**\r
+ Invalid variable MTRRs according to the value in the shadow array.\r
+\r
+ This function programs MTRRs according to the values specified\r
+ in the shadow array.\r
+\r
+ @param[in, out] VariableSettings Variable MTRR settings\r
+ @param[in] VariableMtrrCount Number of variable MTRRs\r
+ @param[in, out] VariableMtrr Shadow of variable MTRR contents\r
+\r
+**/\r
+VOID\r
+InvalidateMtrr (\r
+ IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,\r
+ IN UINTN VariableMtrrCount,\r
+ IN OUT VARIABLE_MTRR *VariableMtrr\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ if (!VariableMtrr[Index].Valid && VariableMtrr[Index].Used) {\r
+ VariableSettings->Mtrr[Index].Base = 0;\r
+ VariableSettings->Mtrr[Index].Mask = 0;\r
+ VariableMtrr[Index].Used = FALSE;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Programs variable MTRRs\r
+\r
+ This function programs variable MTRRs\r
+\r
+ @param[in, out] VariableSettings Variable MTRR settings.\r
+ @param[in] MtrrNumber Index of MTRR to program.\r
+ @param[in] BaseAddress Base address of memory region.\r
+ @param[in] Length Length of memory region.\r
+ @param[in] MemoryCacheType Memory type to set.\r
+ @param[in] MtrrValidAddressMask The valid address mask for MTRR\r
+\r
+**/\r
+VOID\r
+ProgramVariableMtrr (\r
+ IN OUT MTRR_VARIABLE_SETTINGS *VariableSettings,\r
+ IN UINTN MtrrNumber,\r
+ IN PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINT64 MemoryCacheType,\r
+ IN UINT64 MtrrValidAddressMask\r
+ )\r
+{\r
+ UINT64 TempQword;\r
+\r
+ //\r
+ // MTRR Physical Base\r
+ //\r
+ TempQword = (BaseAddress & MtrrValidAddressMask) | MemoryCacheType;\r
+ VariableSettings->Mtrr[MtrrNumber].Base = TempQword;\r
+\r
+ //\r
+ // MTRR Physical Mask\r
+ //\r
+ TempQword = ~(Length - 1);\r
+ VariableSettings->Mtrr[MtrrNumber].Mask = (TempQword & MtrrValidAddressMask) | MTRR_LIB_CACHE_MTRR_ENABLED;\r
+}\r
+\r
+\r
+/**\r
+ Converts the Memory attribute value to MTRR_MEMORY_CACHE_TYPE.\r
+\r
+ If MtrrSetting is not NULL, gets the default memory attribute from input\r
+ MTRR settings buffer.\r
+ If MtrrSetting is NULL, gets the default memory attribute from MSR.\r
+\r
+ @param[in] MtrrSetting A buffer holding all MTRRs content.\r
+ @param[in] MtrrType MTRR memory type\r
+\r
+ @return The enum item in MTRR_MEMORY_CACHE_TYPE\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+GetMemoryCacheTypeFromMtrrType (\r
+ IN MTRR_SETTINGS *MtrrSetting,\r
+ IN UINT64 MtrrType\r
+ )\r
+{\r
+ switch (MtrrType) {\r
+ case MTRR_CACHE_UNCACHEABLE:\r
+ return CacheUncacheable;\r
+ case MTRR_CACHE_WRITE_COMBINING:\r
+ return CacheWriteCombining;\r
+ case MTRR_CACHE_WRITE_THROUGH:\r
+ return CacheWriteThrough;\r
+ case MTRR_CACHE_WRITE_PROTECTED:\r
+ return CacheWriteProtected;\r
+ case MTRR_CACHE_WRITE_BACK:\r
+ return CacheWriteBack;\r
+ default:\r
+ //\r
+ // MtrrType is MTRR_CACHE_INVALID_TYPE, that means\r
+ // no MTRR covers the range\r
+ //\r
+ return MtrrGetDefaultMemoryTypeWorker (MtrrSetting);\r
+ }\r
+}\r
+\r
+/**\r
+ Initializes the valid bits mask and valid address mask for MTRRs.\r
+\r
+ This function initializes the valid bits mask and valid address mask for MTRRs.\r
+\r
+ @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR\r
+ @param[out] MtrrValidAddressMask The valid address mask for the MTRR\r
+\r
+**/\r
+VOID\r
+MtrrLibInitializeMtrrMask (\r
+ OUT UINT64 *MtrrValidBitsMask,\r
+ OUT UINT64 *MtrrValidAddressMask\r
+ )\r
+{\r
+ UINT32 RegEax;\r
+ UINT8 PhysicalAddressBits;\r
+\r
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+\r
+ if (RegEax >= 0x80000008) {\r
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+\r
+ PhysicalAddressBits = (UINT8) RegEax;\r
+\r
+ *MtrrValidBitsMask = LShiftU64 (1, PhysicalAddressBits) - 1;\r
+ *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;\r
+ } else {\r
+ *MtrrValidBitsMask = MTRR_LIB_MSR_VALID_MASK;\r
+ *MtrrValidAddressMask = MTRR_LIB_CACHE_VALID_ADDRESS;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Determines the real attribute of a memory range.\r
+\r
+ This function is to arbitrate the real attribute of the memory when\r
+ there are 2 MTRRs covers the same memory range. For further details,\r
+ please refer the IA32 Software Developer's Manual, Volume 3,\r
+ Section 10.11.4.1.\r
+\r
+ @param[in] MtrrType1 The first kind of Memory type\r
+ @param[in] MtrrType2 The second kind of memory type\r
+\r
+**/\r
+UINT64\r
+MtrrPrecedence (\r
+ IN UINT64 MtrrType1,\r
+ IN UINT64 MtrrType2\r
+ )\r
+{\r
+ UINT64 MtrrType;\r
+\r
+ MtrrType = MTRR_CACHE_INVALID_TYPE;\r
+ switch (MtrrType1) {\r
+ case MTRR_CACHE_UNCACHEABLE:\r
+ MtrrType = MTRR_CACHE_UNCACHEABLE;\r
+ break;\r
+ case MTRR_CACHE_WRITE_COMBINING:\r
+ if (\r
+ MtrrType2==MTRR_CACHE_WRITE_COMBINING ||\r
+ MtrrType2==MTRR_CACHE_UNCACHEABLE\r
+ ) {\r
+ MtrrType = MtrrType2;\r
+ }\r
+ break;\r
+ case MTRR_CACHE_WRITE_THROUGH:\r
+ if (\r
+ MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
+ MtrrType2==MTRR_CACHE_WRITE_BACK\r
+ ) {\r
+ MtrrType = MTRR_CACHE_WRITE_THROUGH;\r
+ } else if(MtrrType2==MTRR_CACHE_UNCACHEABLE) {\r
+ MtrrType = MTRR_CACHE_UNCACHEABLE;\r
+ }\r
+ break;\r
+ case MTRR_CACHE_WRITE_PROTECTED:\r
+ if (MtrrType2 == MTRR_CACHE_WRITE_PROTECTED ||\r
+ MtrrType2 == MTRR_CACHE_UNCACHEABLE) {\r
+ MtrrType = MtrrType2;\r
+ }\r
+ break;\r
+ case MTRR_CACHE_WRITE_BACK:\r
+ if (\r
+ MtrrType2== MTRR_CACHE_UNCACHEABLE ||\r
+ MtrrType2==MTRR_CACHE_WRITE_THROUGH ||\r
+ MtrrType2== MTRR_CACHE_WRITE_BACK\r
+ ) {\r
+ MtrrType = MtrrType2;\r
+ }\r
+ break;\r
+ case MTRR_CACHE_INVALID_TYPE:\r
+ MtrrType = MtrrType2;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ if (MtrrType2 == MTRR_CACHE_INVALID_TYPE) {\r
+ MtrrType = MtrrType1;\r
+ }\r
+ return MtrrType;\r
+}\r
+\r
+/**\r
+ Worker function will get the memory cache type of the specific address.\r
+\r
+ If MtrrSetting is not NULL, gets the memory cache type from input\r
+ MTRR settings buffer.\r
+ If MtrrSetting is NULL, gets the memory cache type from MTRRs.\r
+\r
+ @param[in] MtrrSetting A buffer holding all MTRRs content.\r
+ @param[in] Address The specific address\r
+\r
+ @return Memory cache type of the specific address\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+MtrrGetMemoryAttributeByAddressWorker (\r
+ IN MTRR_SETTINGS *MtrrSetting,\r
+ IN PHYSICAL_ADDRESS Address\r
+ )\r
+{\r
+ UINT64 TempQword;\r
+ UINTN Index;\r
+ UINTN SubIndex;\r
+ UINT64 MtrrType;\r
+ UINT64 TempMtrrType;\r
+ MTRR_MEMORY_CACHE_TYPE CacheType;\r
+ VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+ UINT64 MtrrValidBitsMask;\r
+ UINT64 MtrrValidAddressMask;\r
+ UINTN VariableMtrrCount;\r
+ MTRR_VARIABLE_SETTINGS VariableSettings;\r
+\r
+ //\r
+ // Check if MTRR is enabled, if not, return UC as attribute\r
+ //\r
+ if (MtrrSetting == NULL) {\r
+ TempQword = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);\r
+ } else {\r
+ TempQword = MtrrSetting->MtrrDefType;\r
+ }\r
+ MtrrType = MTRR_CACHE_INVALID_TYPE;\r
+\r
+ if ((TempQword & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+ return CacheUncacheable;\r
+ }\r
+\r
+ //\r
+ // If address is less than 1M, then try to go through the fixed MTRR\r
+ //\r
+ if (Address < BASE_1MB) {\r
+ if ((TempQword & MTRR_LIB_CACHE_FIXED_MTRR_ENABLED) != 0) {\r
+ //\r
+ // Go through the fixed MTRR\r
+ //\r
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+ if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&\r
+ Address < (\r
+ mMtrrLibFixedMtrrTable[Index].BaseAddress +\r
+ (mMtrrLibFixedMtrrTable[Index].Length * 8)\r
+ )\r
+ ) {\r
+ SubIndex =\r
+ ((UINTN)Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /\r
+ mMtrrLibFixedMtrrTable[Index].Length;\r
+ if (MtrrSetting == NULL) {\r
+ TempQword = MtrrRegisterRead (mMtrrLibFixedMtrrTable[Index].Msr);\r
+ } else {\r
+ TempQword = MtrrSetting->Fixed.Mtrr[Index];\r
+ }\r
+ MtrrType = RShiftU64 (TempQword, SubIndex * 8) & 0xFF;\r
+ return GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ MtrrLibInitializeMtrrMask(&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+\r
+ MtrrGetVariableMtrrWorker (\r
+ MtrrSetting,\r
+ GetVariableMtrrCountWorker (),\r
+ &VariableSettings\r
+ );\r
+\r
+ MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+ &VariableSettings,\r
+ GetFirmwareVariableMtrrCountWorker (),\r
+ MtrrValidBitsMask,\r
+ MtrrValidAddressMask,\r
+ VariableMtrr\r
+ );\r
+\r
+ //\r
+ // Go through the variable MTRR\r
+ //\r
+ VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+ ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ if (VariableMtrr[Index].Valid) {\r
+ if (Address >= VariableMtrr[Index].BaseAddress &&\r
+ Address < VariableMtrr[Index].BaseAddress+VariableMtrr[Index].Length) {\r
+ TempMtrrType = VariableMtrr[Index].Type;\r
+ MtrrType = MtrrPrecedence (MtrrType, TempMtrrType);\r
+ }\r
+ }\r
+ }\r
+ CacheType = GetMemoryCacheTypeFromMtrrType (MtrrSetting, MtrrType);\r
+\r
+ return CacheType;\r
+}\r
+\r
+\r
+/**\r
+ This function will get the memory cache type of the specific address.\r
+\r
+ This function is mainly for debug purpose.\r
+\r
+ @param[in] Address The specific address\r
+\r
+ @return Memory cache type of the specific address\r
+\r
+**/\r
+MTRR_MEMORY_CACHE_TYPE\r
+EFIAPI\r
+MtrrGetMemoryAttribute (\r
+ IN PHYSICAL_ADDRESS Address\r
+ )\r
+{\r
+ if (!IsMtrrSupported ()) {\r
+ return CacheUncacheable;\r
+ }\r
+\r
+ return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);\r
+}\r
+\r
+/**\r
+ Worker function prints all MTRRs for debugging.\r
+\r
+ If MtrrSetting is not NULL, print MTRR settings from from input MTRR\r
+ settings buffer.\r
+ If MtrrSetting is NULL, print MTRR settings from MTRRs.\r
+\r
+ @param MtrrSetting A buffer holding all MTRRs content.\r
+**/\r
+VOID\r
+MtrrDebugPrintAllMtrrsWorker (\r
+ IN MTRR_SETTINGS *MtrrSetting\r
+ )\r
+{\r
+ DEBUG_CODE (\r
+ MTRR_SETTINGS LocalMtrrs;\r
+ MTRR_SETTINGS *Mtrrs;\r
+ UINTN Index;\r
+ UINTN Index1;\r
+ UINTN VariableMtrrCount;\r
+ UINT64 Base;\r
+ UINT64 Limit;\r
+ UINT64 MtrrBase;\r
+ UINT64 MtrrLimit;\r
+ UINT64 RangeBase;\r
+ UINT64 RangeLimit;\r
+ UINT64 NoRangeBase;\r
+ UINT64 NoRangeLimit;\r
+ UINT32 RegEax;\r
+ UINTN MemoryType;\r
+ UINTN PreviousMemoryType;\r
+ BOOLEAN Found;\r
+\r
+ if (!IsMtrrSupported ()) {\r
+ return;\r
+ }\r
+\r
+ DEBUG((DEBUG_CACHE, "MTRR Settings\n"));\r
+ DEBUG((DEBUG_CACHE, "=============\n"));\r
+\r
+ if (MtrrSetting != NULL) {\r
+ Mtrrs = MtrrSetting;\r
+ } else {\r
+ MtrrGetAllMtrrs (&LocalMtrrs);\r
+ Mtrrs = &LocalMtrrs;\r
+ }\r
+\r
+ DEBUG((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));\r
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+ DEBUG((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));\r
+ }\r
+\r
+ VariableMtrrCount = GetVariableMtrrCount ();\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ DEBUG((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",\r
+ Index,\r
+ Mtrrs->Variables.Mtrr[Index].Base,\r
+ Mtrrs->Variables.Mtrr[Index].Mask\r
+ ));\r
+ }\r
+ DEBUG((DEBUG_CACHE, "\n"));\r
+ DEBUG((DEBUG_CACHE, "MTRR Ranges\n"));\r
+ DEBUG((DEBUG_CACHE, "====================================\n"));\r
+\r
+ Base = 0;\r
+ PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+ Base = mMtrrLibFixedMtrrTable[Index].BaseAddress;\r
+ for (Index1 = 0; Index1 < 8; Index1++) {\r
+ MemoryType = (UINTN)(RShiftU64 (Mtrrs->Fixed.Mtrr[Index], Index1 * 8) & 0xff);\r
+ if (MemoryType > CacheWriteBack) {\r
+ MemoryType = MTRR_CACHE_INVALID_TYPE;\r
+ }\r
+ if (MemoryType != PreviousMemoryType) {\r
+ if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
+ DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+ }\r
+ PreviousMemoryType = MemoryType;\r
+ DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
+ }\r
+ Base += mMtrrLibFixedMtrrTable[Index].Length;\r
+ }\r
+ }\r
+ DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+\r
+ VariableMtrrCount = GetVariableMtrrCount ();\r
+\r
+ Limit = BIT36 - 1;\r
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+ if (RegEax >= 0x80000008) {\r
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+ Limit = LShiftU64 (1, RegEax & 0xff) - 1;\r
+ }\r
+ Base = BASE_1MB;\r
+ PreviousMemoryType = MTRR_CACHE_INVALID_TYPE;\r
+ do {\r
+ MemoryType = MtrrGetMemoryAttributeByAddressWorker (Mtrrs, Base);\r
+ if (MemoryType > CacheWriteBack) {\r
+ MemoryType = MTRR_CACHE_INVALID_TYPE;\r
+ }\r
+\r
+ if (MemoryType != PreviousMemoryType) {\r
+ if (PreviousMemoryType != MTRR_CACHE_INVALID_TYPE) {\r
+ DEBUG((DEBUG_CACHE, "%016lx\n", Base - 1));\r
+ }\r
+ PreviousMemoryType = MemoryType;\r
+ DEBUG((DEBUG_CACHE, "%a:%016lx-", mMtrrMemoryCacheTypeShortName[MemoryType], Base));\r
+ }\r
+\r
+ RangeBase = BASE_1MB;\r
+ NoRangeBase = BASE_1MB;\r
+ RangeLimit = Limit;\r
+ NoRangeLimit = Limit;\r
+\r
+ for (Index = 0, Found = FALSE; Index < VariableMtrrCount; Index++) {\r
+ if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {\r
+ //\r
+ // If mask is not valid, then do not display range\r
+ //\r
+ continue;\r
+ }\r
+ MtrrBase = (Mtrrs->Variables.Mtrr[Index].Base & (~(SIZE_4KB - 1)));\r
+ MtrrLimit = MtrrBase + ((~(Mtrrs->Variables.Mtrr[Index].Mask & (~(SIZE_4KB - 1)))) & Limit);\r
+\r
+ if (Base >= MtrrBase && Base < MtrrLimit) {\r
+ Found = TRUE;\r
+ }\r
+\r
+ if (Base >= MtrrBase && MtrrBase > RangeBase) {\r
+ RangeBase = MtrrBase;\r
+ }\r
+ if (Base > MtrrLimit && MtrrLimit > RangeBase) {\r
+ RangeBase = MtrrLimit + 1;\r
+ }\r
+ if (Base < MtrrBase && MtrrBase < RangeLimit) {\r
+ RangeLimit = MtrrBase - 1;\r
+ }\r
+ if (Base < MtrrLimit && MtrrLimit <= RangeLimit) {\r
+ RangeLimit = MtrrLimit;\r
+ }\r
+\r
+ if (Base > MtrrLimit && NoRangeBase < MtrrLimit) {\r
+ NoRangeBase = MtrrLimit + 1;\r
+ }\r
+ if (Base < MtrrBase && NoRangeLimit > MtrrBase) {\r
+ NoRangeLimit = MtrrBase - 1;\r
+ }\r
+ }\r
+\r
+ if (Found) {\r
+ Base = RangeLimit + 1;\r
+ } else {\r
+ Base = NoRangeLimit + 1;\r
+ }\r
+ } while (Base < Limit);\r
+ DEBUG((DEBUG_CACHE, "%016lx\n\n", Base - 1));\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ This function prints all MTRRs for debugging.\r
+**/\r
+VOID\r
+EFIAPI\r
+MtrrDebugPrintAllMtrrs (\r
+ VOID\r
+ )\r
+{\r
+ MtrrDebugPrintAllMtrrsWorker (NULL);\r
+}\r
+\r
+\r
+/**\r
+ Worker function attempts to set the attributes for a memory range.\r
+\r
+ If MtrrSettings is not NULL, set the attributes into the input MTRR\r
+ settings buffer.\r
+ If MtrrSettings is NULL, set the attributes into MTRRs registers.\r
+\r
+ @param[in, out] MtrrSetting A buffer holding all MTRRs content.\r
+ @param[in] BaseAddress The physical address that is the start\r
+ address of a memory region.\r
+ @param[in] Length The size in bytes of the memory region.\r
+ @param[in] Attribute The bit mask of attributes to set for the\r
+ memory region.\r
+\r
+ @retval RETURN_SUCCESS The attributes were set for the memory\r
+ region.\r
+ @retval RETURN_INVALID_PARAMETER Length is zero.\r
+ @retval RETURN_UNSUPPORTED The processor does not support one or\r
+ more bytes of the memory resource range\r
+ specified by BaseAddress and Length.\r
+ @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
+ for the memory resource range specified\r
+ by BaseAddress and Length.\r
+ @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
+ range specified by BaseAddress and Length\r
+ cannot be modified.\r
+ @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
+ modify the attributes of the memory\r
+ resource range.\r
+\r
+**/\r
+RETURN_STATUS\r
+MtrrSetMemoryAttributeWorker (\r
+ IN OUT MTRR_SETTINGS *MtrrSetting,\r
+ IN PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN MTRR_MEMORY_CACHE_TYPE Attribute\r
+ )\r
+{\r
+ UINT64 TempQword;\r
+ RETURN_STATUS Status;\r
+ UINT64 MemoryType;\r
+ UINT64 Alignment;\r
+ BOOLEAN OverLap;\r
+ BOOLEAN Positive;\r
+ UINT32 MsrNum;\r
+ UINTN MtrrNumber;\r
+ VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];\r
+ UINT32 UsedMtrr;\r
+ UINT64 MtrrValidBitsMask;\r
+ UINT64 MtrrValidAddressMask;\r
+ BOOLEAN OverwriteExistingMtrr;\r
+ UINT32 FirmwareVariableMtrrCount;\r
+ MTRR_CONTEXT MtrrContext;\r
+ BOOLEAN MtrrContextValid;\r
+ BOOLEAN FixedSettingsValid[MTRR_NUMBER_OF_FIXED_MTRR];\r
+ BOOLEAN FixedSettingsModified[MTRR_NUMBER_OF_FIXED_MTRR];\r
+ MTRR_FIXED_SETTINGS WorkingFixedSettings;\r
+ UINT32 VariableMtrrCount;\r
+ MTRR_VARIABLE_SETTINGS OriginalVariableSettings;\r
+ BOOLEAN ProgramVariableSettings;\r
+ MTRR_VARIABLE_SETTINGS WorkingVariableSettings;\r
+ UINT32 Index;\r
+ UINT64 ClearMask;\r
+ UINT64 OrMask;\r
+ UINT64 NewValue;\r
+ MTRR_VARIABLE_SETTINGS *VariableSettings;\r
+\r
+ MtrrContextValid = FALSE;\r
+ VariableMtrrCount = 0;\r
+ ZeroMem (&WorkingFixedSettings, sizeof (WorkingFixedSettings));\r
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+ FixedSettingsValid[Index] = FALSE;\r
+ FixedSettingsModified[Index] = FALSE;\r
+ }\r
+ ProgramVariableSettings = FALSE;\r
+\r
+ if (!IsMtrrSupported ()) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);\r
+\r
+ TempQword = 0;\r
+ MemoryType = (UINT64)Attribute;\r
+ OverwriteExistingMtrr = FALSE;\r
+\r
+ //\r
+ // Check for an invalid parameter\r
+ //\r
+ if (Length == 0) {\r
+ Status = RETURN_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ if (\r
+ (BaseAddress & ~MtrrValidAddressMask) != 0 ||\r
+ (Length & ~MtrrValidAddressMask) != 0\r
+ ) {\r
+ Status = RETURN_UNSUPPORTED;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Check if Fixed MTRR\r
+ //\r
+ Status = RETURN_SUCCESS;\r
+ if (BaseAddress < BASE_1MB) {\r
+ while ((BaseAddress < BASE_1MB) && (Length > 0) && Status == RETURN_SUCCESS) {\r
+ Status = ProgramFixedMtrr (MemoryType, &BaseAddress, &Length, &MsrNum, &ClearMask, &OrMask);\r
+ if (RETURN_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ if (MtrrSetting != NULL) {\r
+ MtrrSetting->Fixed.Mtrr[MsrNum] = (MtrrSetting->Fixed.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
+ MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_FIXED_MTRR_ENABLED;\r
+ } else {\r
+ if (!FixedSettingsValid[MsrNum]) {\r
+ WorkingFixedSettings.Mtrr[MsrNum] = MtrrRegisterRead (mMtrrLibFixedMtrrTable[MsrNum].Msr);\r
+ FixedSettingsValid[MsrNum] = TRUE;\r
+ }\r
+ NewValue = (WorkingFixedSettings.Mtrr[MsrNum] & ~ClearMask) | OrMask;\r
+ if (WorkingFixedSettings.Mtrr[MsrNum] != NewValue) {\r
+ WorkingFixedSettings.Mtrr[MsrNum] = NewValue;\r
+ FixedSettingsModified[MsrNum] = TRUE;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (Length == 0) {\r
+ //\r
+ // A Length of 0 can only make sense for fixed MTTR ranges.\r
+ // Since we just handled the fixed MTRRs, we can skip the\r
+ // variable MTRR section.\r
+ //\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Since memory ranges below 1MB will be overridden by the fixed MTRRs,\r
+ // we can set the base to 0 to save variable MTRRs.\r
+ //\r
+ if (BaseAddress == BASE_1MB) {\r
+ BaseAddress = 0;\r
+ Length += SIZE_1MB;\r
+ }\r
+\r
+ //\r
+ // Read all variable MTRRs\r
+ //\r
+ VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+ FirmwareVariableMtrrCount = GetFirmwareVariableMtrrCountWorker ();\r
+ if (MtrrSetting != NULL) {\r
+ VariableSettings = &MtrrSetting->Variables;\r
+ } else {\r
+ MtrrGetVariableMtrrWorker (NULL, VariableMtrrCount, &OriginalVariableSettings);\r
+ CopyMem (&WorkingVariableSettings, &OriginalVariableSettings, sizeof (WorkingVariableSettings));\r
+ ProgramVariableSettings = TRUE;\r
+ VariableSettings = &WorkingVariableSettings;\r
+ }\r
+\r
+ //\r
+ // Check for overlap\r
+ //\r
+ UsedMtrr = MtrrGetMemoryAttributeInVariableMtrrWorker (\r
+ VariableSettings,\r
+ FirmwareVariableMtrrCount,\r
+ MtrrValidBitsMask,\r
+ MtrrValidAddressMask,\r
+ VariableMtrr\r
+ );\r
+ OverLap = CheckMemoryAttributeOverlap (\r
+ FirmwareVariableMtrrCount,\r
+ BaseAddress,\r
+ BaseAddress + Length - 1,\r
+ VariableMtrr\r
+ );\r
+ if (OverLap) {\r
+ Status = CombineMemoryAttribute (\r
+ FirmwareVariableMtrrCount,\r
+ MemoryType,\r
+ &BaseAddress,\r
+ &Length,\r
+ VariableMtrr,\r
+ &UsedMtrr,\r
+ &OverwriteExistingMtrr\r
+ );\r
+ if (RETURN_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if (Length == 0) {\r
+ //\r
+ // Combined successfully, invalidate the now-unused MTRRs\r
+ //\r
+ InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
+ Status = RETURN_SUCCESS;\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ //\r
+ // The memory type is the same with the type specified by\r
+ // MTRR_LIB_IA32_MTRR_DEF_TYPE.\r
+ //\r
+ if ((!OverwriteExistingMtrr) && (Attribute == MtrrGetDefaultMemoryType ())) {\r
+ //\r
+ // Invalidate the now-unused MTRRs\r
+ //\r
+ InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
+ goto Done;\r
+ }\r
+\r
+ Positive = GetMtrrNumberAndDirection (BaseAddress, Length, &MtrrNumber);\r
+\r
+ if ((UsedMtrr + MtrrNumber) > FirmwareVariableMtrrCount) {\r
+ Status = RETURN_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Invalidate the now-unused MTRRs\r
+ //\r
+ InvalidateMtrr (VariableSettings, VariableMtrrCount, VariableMtrr);\r
+\r
+ //\r
+ // Find first unused MTRR\r
+ //\r
+ for (MsrNum = 0; MsrNum < VariableMtrrCount; MsrNum++) {\r
+ if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (BaseAddress != 0) {\r
+ do {\r
+ //\r
+ // Calculate the alignment of the base address.\r
+ //\r
+ Alignment = LShiftU64 (1, (UINTN)LowBitSet64 (BaseAddress));\r
+\r
+ if (Alignment > Length) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Find unused MTRR\r
+ //\r
+ for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+ if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ ProgramVariableMtrr (\r
+ VariableSettings,\r
+ MsrNum,\r
+ BaseAddress,\r
+ Alignment,\r
+ MemoryType,\r
+ MtrrValidAddressMask\r
+ );\r
+ BaseAddress += Alignment;\r
+ Length -= Alignment;\r
+ } while (TRUE);\r
+\r
+ if (Length == 0) {\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ TempQword = Length;\r
+\r
+ if (!Positive) {\r
+ Length = Power2MaxMemory (LShiftU64 (TempQword, 1));\r
+\r
+ //\r
+ // Find unused MTRR\r
+ //\r
+ for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+ if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ ProgramVariableMtrr (\r
+ VariableSettings,\r
+ MsrNum,\r
+ BaseAddress,\r
+ Length,\r
+ MemoryType,\r
+ MtrrValidAddressMask\r
+ );\r
+ BaseAddress += Length;\r
+ TempQword = Length - TempQword;\r
+ MemoryType = MTRR_CACHE_UNCACHEABLE;\r
+ }\r
+\r
+ do {\r
+ //\r
+ // Find unused MTRR\r
+ //\r
+ for (; MsrNum < VariableMtrrCount; MsrNum++) {\r
+ if ((VariableSettings->Mtrr[MsrNum].Mask & MTRR_LIB_CACHE_MTRR_ENABLED) == 0) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ Length = Power2MaxMemory (TempQword);\r
+ if (!Positive) {\r
+ BaseAddress -= Length;\r
+ }\r
+\r
+ ProgramVariableMtrr (\r
+ VariableSettings,\r
+ MsrNum,\r
+ BaseAddress,\r
+ Length,\r
+ MemoryType,\r
+ MtrrValidAddressMask\r
+ );\r
+\r
+ if (Positive) {\r
+ BaseAddress += Length;\r
+ }\r
+ TempQword -= Length;\r
+\r
+ } while (TempQword > 0);\r
+\r
+Done:\r
+\r
+ //\r
+ // Write fixed MTRRs that have been modified\r
+ //\r
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+ if (FixedSettingsModified[Index]) {\r
+ if (!MtrrContextValid) {\r
+ PreMtrrChange (&MtrrContext);\r
+ MtrrContextValid = TRUE;\r
+ }\r
+ MtrrRegisterWrite (\r
+ mMtrrLibFixedMtrrTable[Index].Msr,\r
+ WorkingFixedSettings.Mtrr[Index]\r
+ );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Write variable MTRRs\r
+ //\r
+ if (ProgramVariableSettings) {\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ if (WorkingVariableSettings.Mtrr[Index].Base != OriginalVariableSettings.Mtrr[Index].Base ||\r
+ WorkingVariableSettings.Mtrr[Index].Mask != OriginalVariableSettings.Mtrr[Index].Mask ) {\r
+ if (!MtrrContextValid) {\r
+ PreMtrrChange (&MtrrContext);\r
+ MtrrContextValid = TRUE;\r
+ }\r
+ MtrrRegisterWrite (\r
+ QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
+ WorkingVariableSettings.Mtrr[Index].Base\r
+ );\r
+ MtrrRegisterWrite (\r
+ QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,\r
+ WorkingVariableSettings.Mtrr[Index].Mask\r
+ );\r
+ }\r
+ }\r
+ }\r
+ if (MtrrContextValid) {\r
+ PostMtrrChange (&MtrrContext);\r
+ }\r
+\r
+ DEBUG((DEBUG_CACHE, " Status = %r\n", Status));\r
+ if (!RETURN_ERROR (Status)) {\r
+ if (MtrrSetting != NULL) {\r
+ MtrrSetting->MtrrDefType |= MTRR_LIB_CACHE_MTRR_ENABLED;\r
+ }\r
+ MtrrDebugPrintAllMtrrsWorker (MtrrSetting);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function attempts to set the attributes for a memory range.\r
+\r
+ @param[in] BaseAddress The physical address that is the start\r
+ address of a memory region.\r
+ @param[in] Length The size in bytes of the memory region.\r
+ @param[in] Attributes The bit mask of attributes to set for the\r
+ memory region.\r
+\r
+ @retval RETURN_SUCCESS The attributes were set for the memory\r
+ region.\r
+ @retval RETURN_INVALID_PARAMETER Length is zero.\r
+ @retval RETURN_UNSUPPORTED The processor does not support one or\r
+ more bytes of the memory resource range\r
+ specified by BaseAddress and Length.\r
+ @retval RETURN_UNSUPPORTED The bit mask of attributes is not support\r
+ for the memory resource range specified\r
+ by BaseAddress and Length.\r
+ @retval RETURN_ACCESS_DENIED The attributes for the memory resource\r
+ range specified by BaseAddress and Length\r
+ cannot be modified.\r
+ @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to\r
+ modify the attributes of the memory\r
+ resource range.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+MtrrSetMemoryAttribute (\r
+ IN PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN MTRR_MEMORY_CACHE_TYPE Attribute\r
+ )\r
+{\r
+ DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttribute() %a:%016lx-%016lx\n", mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
+ return MtrrSetMemoryAttributeWorker (\r
+ NULL,\r
+ BaseAddress,\r
+ Length,\r
+ Attribute\r
+ );\r
+}\r
+\r
+/**\r
+ This function attempts to set the attributes into MTRR setting buffer for a memory range.\r
+\r
+ @param[in, out] MtrrSetting MTRR setting buffer to be set.\r
+ @param[in] BaseAddress The physical address that is the start address\r
+ of a memory region.\r
+ @param[in] Length The size in bytes of the memory region.\r
+ @param[in] Attribute The bit mask of attributes to set for the\r
+ memory region.\r
+\r
+ @retval RETURN_SUCCESS The attributes were set for the memory region.\r
+ @retval RETURN_INVALID_PARAMETER Length is zero.\r
+ @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the\r
+ memory resource range specified by BaseAddress and Length.\r
+ @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource\r
+ range specified by BaseAddress and Length.\r
+ @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by\r
+ BaseAddress and Length cannot be modified.\r
+ @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of\r
+ the memory resource range.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+MtrrSetMemoryAttributeInMtrrSettings (\r
+ IN OUT MTRR_SETTINGS *MtrrSetting,\r
+ IN PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN MTRR_MEMORY_CACHE_TYPE Attribute\r
+ )\r
+{\r
+ DEBUG((DEBUG_CACHE, "MtrrSetMemoryAttributeMtrrSettings(%p) %a:%016lx-%016lx\n", MtrrSetting, mMtrrMemoryCacheTypeShortName[Attribute], BaseAddress, Length));\r
+ return MtrrSetMemoryAttributeWorker (\r
+ MtrrSetting,\r
+ BaseAddress,\r
+ Length,\r
+ Attribute\r
+ );\r
+}\r
+\r
+/**\r
+ Worker function setting variable MTRRs\r
+\r
+ @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
+\r
+**/\r
+VOID\r
+MtrrSetVariableMtrrWorker (\r
+ IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINT32 VariableMtrrCount;\r
+\r
+ VariableMtrrCount = GetVariableMtrrCountWorker ();\r
+ ASSERT (VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR);\r
+\r
+ for (Index = 0; Index < VariableMtrrCount; Index++) {\r
+ MtrrRegisterWrite (\r
+ QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1),\r
+ VariableSettings->Mtrr[Index].Base\r
+ );\r
+ MtrrRegisterWrite (\r
+ QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 + (Index << 1) + 1,\r
+ VariableSettings->Mtrr[Index].Mask\r
+ );\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function sets variable MTRRs\r
+\r
+ @param[in] VariableSettings A buffer to hold variable MTRRs content.\r
+\r
+ @return The pointer of VariableSettings\r
+\r
+**/\r
+MTRR_VARIABLE_SETTINGS*\r
+EFIAPI\r
+MtrrSetVariableMtrr (\r
+ IN MTRR_VARIABLE_SETTINGS *VariableSettings\r
+ )\r
+{\r
+ MTRR_CONTEXT MtrrContext;\r
+\r
+ if (!IsMtrrSupported ()) {\r
+ return VariableSettings;\r
+ }\r
+\r
+ PreMtrrChange (&MtrrContext);\r
+ MtrrSetVariableMtrrWorker (VariableSettings);\r
+ PostMtrrChange (&MtrrContext);\r
+ MtrrDebugPrintAllMtrrs ();\r
+\r
+ return VariableSettings;\r
+}\r
+\r
+/**\r
+ Worker function setting fixed MTRRs\r
+\r
+ @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
+\r
+**/\r
+VOID\r
+MtrrSetFixedMtrrWorker (\r
+ IN MTRR_FIXED_SETTINGS *FixedSettings\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {\r
+ MtrrRegisterWrite (\r
+ mMtrrLibFixedMtrrTable[Index].Msr,\r
+ FixedSettings->Mtrr[Index]\r
+ );\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function sets fixed MTRRs\r
+\r
+ @param[in] FixedSettings A buffer to hold fixed MTRRs content.\r
+\r
+ @retval The pointer of FixedSettings\r
+\r
+**/\r
+MTRR_FIXED_SETTINGS*\r
+EFIAPI\r
+MtrrSetFixedMtrr (\r
+ IN MTRR_FIXED_SETTINGS *FixedSettings\r
+ )\r
+{\r
+ MTRR_CONTEXT MtrrContext;\r
+\r
+ if (!IsMtrrSupported ()) {\r
+ return FixedSettings;\r
+ }\r
+\r
+ PreMtrrChange (&MtrrContext);\r
+ MtrrSetFixedMtrrWorker (FixedSettings);\r
+ PostMtrrChange (&MtrrContext);\r
+ MtrrDebugPrintAllMtrrs ();\r
+\r
+ return FixedSettings;\r
+}\r
+\r
+\r
+/**\r
+ This function gets the content in all MTRRs (variable and fixed)\r
+\r
+ @param[out] MtrrSetting A buffer to hold all MTRRs content.\r
+\r
+ @retval the pointer of MtrrSetting\r
+\r
+**/\r
+MTRR_SETTINGS *\r
+EFIAPI\r
+MtrrGetAllMtrrs (\r
+ OUT MTRR_SETTINGS *MtrrSetting\r
+ )\r
+{\r
+ if (!IsMtrrSupported ()) {\r
+ return MtrrSetting;\r
+ }\r
+\r
+ //\r
+ // Get fixed MTRRs\r
+ //\r
+ MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);\r
+\r
+ //\r
+ // Get variable MTRRs\r
+ //\r
+ MtrrGetVariableMtrrWorker (\r
+ NULL,\r
+ GetVariableMtrrCountWorker (),\r
+ &MtrrSetting->Variables\r
+ );\r
+\r
+ //\r
+ // Get MTRR_DEF_TYPE value\r
+ //\r
+ MtrrSetting->MtrrDefType = MtrrRegisterRead (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE);\r
+\r
+ return MtrrSetting;\r
+}\r
+\r
+\r
+/**\r
+ This function sets all MTRRs (variable and fixed)\r
+\r
+ @param[in] MtrrSetting A buffer holding all MTRRs content.\r
+\r
+ @retval The pointer of MtrrSetting\r
+\r
+**/\r
+MTRR_SETTINGS *\r
+EFIAPI\r
+MtrrSetAllMtrrs (\r
+ IN MTRR_SETTINGS *MtrrSetting\r
+ )\r
+{\r
+ MTRR_CONTEXT MtrrContext;\r
+\r
+ if (!IsMtrrSupported ()) {\r
+ return MtrrSetting;\r
+ }\r
+\r
+ PreMtrrChange (&MtrrContext);\r
+\r
+ //\r
+ // Set fixed MTRRs\r
+ //\r
+ MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);\r
+\r
+ //\r
+ // Set variable MTRRs\r
+ //\r
+ MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);\r
+\r
+ //\r
+ // Set MTRR_DEF_TYPE value\r
+ //\r
+ MtrrRegisterWrite (QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);\r
+\r
+ PostMtrrChangeEnableCache (&MtrrContext);\r
+\r
+ MtrrDebugPrintAllMtrrs ();\r
+\r
+ return MtrrSetting;\r
+}\r
+\r
+\r
+/**\r
+ Checks if MTRR is supported.\r
+\r
+ @retval TRUE MTRR is supported.\r
+ @retval FALSE MTRR is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsMtrrSupported (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RegEax;\r
+\r
+ //\r
+ // Check CPUID(1).EAX[0..11] for Quark SoC\r
+ //\r
+ AsmCpuid (1, &RegEax, NULL, NULL, NULL);\r
+ if ((RegEax & 0xfff) == QUARK_SOC_CPUID_FAMILY_MODEL_STEPPING) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
--- /dev/null
+## @file\r
+# MTRR library provides APIs for MTRR operation.\r
+#\r
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = MtrrLib\r
+ MODULE_UNI_FILE = MtrrLib.uni\r
+ FILE_GUID = 6826b408-f4f3-47ee-917f-af7047f9d937\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = MtrrLib\r
+\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+ MtrrLib.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ UefiCpuPkg/UefiCpuPkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseMemoryLib\r
+ BaseLib\r
+ CpuLib\r
+ DebugLib\r
+ QNCAccessLib\r
+\r
+[Pcd]\r
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs ## SOMETIMES_CONSUMES\r
+\r
--- /dev/null
+// /** @file\r
+// MtrrLib Module Localized Abstract and Description Content\r
+//\r
+// Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT\r
+#language en-US\r
+"MTRR library provides APIs for MTRR operation"\r
+\r
+#string STR_MODULE_DESCRIPTION\r
+#language en-US\r
+"MTRR library provides APIs for MTRR operation."\r
+\r
--- /dev/null
+/** @file\r
+Base Lib function for QNC internal network access.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <Uefi.h>\r
+\r
+/**\r
+ Gets the base address of PCI Express for Quark North Cluster.\r
+\r
+ @return The base address of PCI Express for Quark North Cluster.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+QncGetPciExpressBaseAddress (\r
+ VOID\r
+ )\r
+{\r
+ return (UINTN) PcdGet64(PcdPciExpressBaseAddress);\r
+}\r
--- /dev/null
+/** @file\r
+Common Lib function for QNC internal network access.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <Uefi.h>\r
+\r
+#include <IntelQNCRegs.h>\r
+#include <Library/QNCAccessLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <IndustryStandard/Pci22.h>\r
+\r
+UINT32\r
+EFIAPI\r
+QNCPortRead(\r
+ UINT8 Port,\r
+ UINT32 RegAddress\r
+ )\r
+{\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_READ_DW (Port, RegAddress);\r
+ return McD0PciCfg32 (QNC_ACCESS_PORT_MDR);\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+QNCPortWrite (\r
+ UINT8 Port,\r
+ UINT32 RegAddress,\r
+ UINT32 WriteValue\r
+ )\r
+{\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue;\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_WRITE_DW (Port, RegAddress);\r
+}\r
+\r
+UINT32\r
+EFIAPI\r
+QNCAltPortRead (\r
+ UINT8 Port,\r
+ UINT32 RegAddress\r
+ )\r
+{\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = ALT_MESSAGE_READ_DW (Port, RegAddress);\r
+ return McD0PciCfg32 (QNC_ACCESS_PORT_MDR);\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+QNCAltPortWrite (\r
+ UINT8 Port,\r
+ UINT32 RegAddress,\r
+ UINT32 WriteValue\r
+ )\r
+{\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue;\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = ALT_MESSAGE_WRITE_DW (Port, RegAddress);\r
+}\r
+\r
+UINT32\r
+EFIAPI\r
+QNCPortIORead(\r
+ UINT8 Port,\r
+ UINT32 RegAddress\r
+ )\r
+{\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_IO_READ_DW (Port, RegAddress);\r
+ return McD0PciCfg32 (QNC_ACCESS_PORT_MDR);\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+QNCPortIOWrite (\r
+ UINT8 Port,\r
+ UINT32 RegAddress,\r
+ UINT32 WriteValue\r
+ )\r
+{\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue;\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);\r
+ McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_IO_WRITE_DW (Port, RegAddress);\r
+}\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+QNCMmIoWrite (\r
+ UINT32 MmIoAddress,\r
+ QNC_MEM_IO_WIDTH Width,\r
+ UINT32 DataNumber,\r
+ VOID *pData\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This is for the special consideration for QNC MMIO write, as required by FWG, a reading must be performed after MMIO writing\r
+to ensure the expected write is processed and data is flushed into chipset\r
+\r
+Arguments:\r
+\r
+ Row -- row number to be cleared ( start from 1 )\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+ RETURN_STATUS Status;\r
+ UINTN Index;\r
+\r
+ Status = RETURN_SUCCESS;\r
+\r
+ for (Index =0; Index < DataNumber; Index++) {\r
+ switch (Width) {\r
+ case QNCMmioWidthUint8:\r
+ QNCMmio8 (MmIoAddress, 0) = ((UINT8 *)pData)[Index];\r
+ if (QNCMmio8 (MmIoAddress, 0) != ((UINT8*)pData)[Index]) {\r
+ Status = RETURN_DEVICE_ERROR;\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case QNCMmioWidthUint16:\r
+ QNCMmio16 (MmIoAddress, 0) = ((UINT16 *)pData)[Index];\r
+ if (QNCMmio16 (MmIoAddress, 0) != ((UINT16 *)pData)[Index]) {\r
+ Status = RETURN_DEVICE_ERROR;\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case QNCMmioWidthUint32:\r
+ QNCMmio32 (MmIoAddress, 0) = ((UINT32 *)pData)[Index];\r
+ if (QNCMmio32 (MmIoAddress, 0) != ((UINT32 *)pData)[Index]) {\r
+ Status = RETURN_DEVICE_ERROR;\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case QNCMmioWidthUint64:\r
+ QNCMmio64 (MmIoAddress, 0) = ((UINT64 *)pData)[Index];\r
+ if (QNCMmio64 (MmIoAddress, 0) != ((UINT64 *)pData)[Index]) {\r
+ Status = RETURN_DEVICE_ERROR;\r
+ break;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+UINT32\r
+EFIAPI\r
+QncHsmmcRead (\r
+ VOID\r
+ )\r
+{\r
+ return QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC);\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+QncHsmmcWrite (\r
+ UINT32 WriteValue\r
+ )\r
+{\r
+ UINT16 DeviceId;\r
+ UINT32 Data32;\r
+\r
+ //\r
+ // Check what Soc we are running on (read Host bridge DeviceId)\r
+ //\r
+ DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET);\r
+\r
+ if (DeviceId == QUARK2_MC_DEVICE_ID) {\r
+ //\r
+ // Disable HSMMC configuration\r
+ //\r
+ Data32 = QncHsmmcRead ();\r
+ Data32 &= ~SMM_CTL_EN;\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, Data32);\r
+\r
+ //\r
+ // Validate HSMMC configuration is disabled\r
+ //\r
+ Data32 = QncHsmmcRead ();\r
+ ASSERT((Data32 & SMM_CTL_EN) == 0);\r
+\r
+ //\r
+ // Enable HSMMC configuration\r
+ //\r
+ WriteValue |= SMM_CTL_EN;\r
+ }\r
+\r
+ //\r
+ // Write the register value\r
+ //\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, WriteValue);\r
+\r
+ if (DeviceId == QUARK2_MC_DEVICE_ID) {\r
+ //\r
+ // Validate HSMMC configuration is enabled\r
+ //\r
+ Data32 = QncHsmmcRead ();\r
+ ASSERT((Data32 & SMM_CTL_EN) != 0);\r
+ }\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+QncImrWrite (\r
+ UINT32 ImrBaseOffset,\r
+ UINT32 ImrLow,\r
+ UINT32 ImrHigh,\r
+ UINT32 ImrReadMask,\r
+ UINT32 ImrWriteMask\r
+ )\r
+{\r
+ UINT16 DeviceId;\r
+ UINT32 Data32;\r
+\r
+ //\r
+ // Check what Soc we are running on (read Host bridge DeviceId)\r
+ //\r
+ DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET);\r
+\r
+ //\r
+ // Disable IMR protection\r
+ //\r
+ if (DeviceId == QUARK2_MC_DEVICE_ID) {\r
+ //\r
+ // Disable IMR protection\r
+ //\r
+ Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL);\r
+ Data32 &= ~IMR_EN;\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, Data32);\r
+\r
+ //\r
+ // Validate IMR protection is disabled\r
+ //\r
+ Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL);\r
+ ASSERT((Data32 & IMR_EN) == 0);\r
+\r
+ //\r
+ // Update the IMR (IMRXL must be last as it may enable IMR violation checking)\r
+ //\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, ImrReadMask);\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, ImrWriteMask);\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXH, ImrHigh);\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, ImrLow);\r
+\r
+ //\r
+ // Validate IMR protection is enabled/disabled\r
+ //\r
+ Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL);\r
+ ASSERT((Data32 & IMR_EN) == (ImrLow & IMR_EN));\r
+ } else {\r
+ //\r
+ // Disable IMR protection (allow all access)\r
+ //\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, (UINT32)IMRX_ALL_ACCESS);\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, (UINT32)IMRX_ALL_ACCESS);\r
+\r
+ //\r
+ // Update the IMR (IMRXRM/IMRXWM must be last as they restrict IMR access)\r
+ //\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, (ImrLow & ~IMR_EN));\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXH, ImrHigh);\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, ImrReadMask);\r
+ QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, ImrWriteMask);\r
+ }\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+QncIClkAndThenOr (\r
+ UINT32 RegAddress,\r
+ UINT32 AndValue,\r
+ UINT32 OrValue\r
+ )\r
+{\r
+ UINT32 RegValue;\r
+ //\r
+ // Whenever an iCLK SB register (Endpoint 32h) is being programmed the access\r
+ // should always consist of a READ from the address followed by 2 identical\r
+ // WRITEs to that address.\r
+ //\r
+ RegValue = QNCAltPortRead (QUARK_ICLK_SB_PORT_ID, RegAddress);\r
+ RegValue &= AndValue;\r
+ RegValue |= OrValue;\r
+ QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);\r
+ QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+QncIClkOr (\r
+ UINT32 RegAddress,\r
+ UINT32 OrValue\r
+ )\r
+{\r
+ UINT32 RegValue;\r
+ //\r
+ // Whenever an iCLK SB register (Endpoint 32h) is being programmed the access\r
+ // should always consist of a READ from the address followed by 2 identical\r
+ // WRITEs to that address.\r
+ //\r
+ RegValue = QNCAltPortRead (QUARK_ICLK_SB_PORT_ID, RegAddress);\r
+ RegValue |= OrValue;\r
+ QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);\r
+ QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);\r
+}\r
--- /dev/null
+## @file\r
+# Base Intel QNC Library Instance\r
+#\r
+# Intel QNC internal network access Library Instance\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = QNCAccessLib\r
+ FILE_GUID = CC13B9FB-DAF5-4b42-907F-122216787C05\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = QNCAccessLib\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+ QNCAccessLib.c\r
+ BaseAccess.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ DebugLib\r
+\r
+[Pcd]\r
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress\r
--- /dev/null
+/** @file\r
+Runtime Lib function for QNC internal network access.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeLib.h>\r
+#include <Library/QNCAccessLib.h>\r
+\r
+///\r
+/// Set Virtual Address Map Event\r
+///\r
+EFI_EVENT mDxeRuntimeQncAccessLibVirtualNotifyEvent = NULL;\r
+\r
+///\r
+/// Module global that contains the base physical address of the PCI Express MMIO range.\r
+///\r
+UINTN mDxeRuntimeQncAccessLibPciExpressBaseAddress = 0;\r
+\r
+/**\r
+ Convert the physical PCI Express MMIO address to a virtual address.\r
+\r
+ @param[in] Event The event that is being processed.\r
+ @param[in] Context The Event Context.\r
+**/\r
+VOID\r
+EFIAPI\r
+DxeRuntimeQncAccessLibVirtualNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Convert the physical PCI Express MMIO address to a virtual address.\r
+ //\r
+ Status = EfiConvertPointer (0, (VOID **) &mDxeRuntimeQncAccessLibPciExpressBaseAddress);\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+ The constructor function to setup globals and goto virtual mode notify.\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The constructor completed successfully.\r
+ @retval Other value The constructor did not complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeRuntimeQncAccessLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Cache the physical address of the PCI Express MMIO range into a module global variable\r
+ //\r
+ mDxeRuntimeQncAccessLibPciExpressBaseAddress = (UINTN) PcdGet64(PcdPciExpressBaseAddress);\r
+\r
+ //\r
+ // Register SetVirtualAddressMap () notify function\r
+ //\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ DxeRuntimeQncAccessLibVirtualNotify,\r
+ NULL,\r
+ &gEfiEventVirtualAddressChangeGuid,\r
+ &mDxeRuntimeQncAccessLibVirtualNotifyEvent\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The destructor function frees any allocated buffers and closes the Set Virtual\r
+ Address Map event.\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The destructor completed successfully.\r
+ @retval Other value The destructor did not complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeRuntimeQncAccessLibDestructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Close the Set Virtual Address Map event\r
+ //\r
+ Status = gBS->CloseEvent (mDxeRuntimeQncAccessLibVirtualNotifyEvent);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Gets the base address of PCI Express for Quark North Cluster.\r
+\r
+ @return The base address of PCI Express for Quark North Cluster.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+QncGetPciExpressBaseAddress (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // If system goes to virtual mode then virtual notify callback will update\r
+ // mDxeRuntimeQncAccessLibPciExpressBaseAddress with virtual address of\r
+ // PCIe memory base.\r
+ //\r
+ return mDxeRuntimeQncAccessLibPciExpressBaseAddress;\r
+}\r
+\r
--- /dev/null
+## @file\r
+# DXE Runtime Intel QNC Library Instance\r
+#\r
+# Intel QNC internal network access Library Instance.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = RuntimeQNCAccessLib\r
+ FILE_GUID = E6B51D93-E4C8-4425-9FA9-9DED814220F9\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = QNCAccessLib|DXE_RUNTIME_DRIVER\r
+ CONSTRUCTOR = DxeRuntimeQncAccessLibConstructor\r
+ DESTRUCTOR = DxeRuntimeQncAccessLibDestructor\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32\r
+#\r
+\r
+[Sources]\r
+ QNCAccessLib.c\r
+ RuntimeAccess.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseLib\r
+ DebugLib\r
+ PcdLib\r
+ UefiBootServicesTableLib\r
+ UefiRuntimeLib\r
+\r
+[Pcd]\r
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress\r
--- /dev/null
+/** @file\r
+QNC Smm Library Services that implements SMM Region access, S/W SMI generation and detection.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include <Base.h>\r
+#include <IntelQNCRegs.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Uefi/UefiBaseType.h>\r
+#include <Library/QNCAccessLib.h>\r
+\r
+#define BOOT_SERVICE_SOFTWARE_SMI_DATA 0\r
+#define RUNTIME_SOFTWARE_SMI_DATA 1\r
+\r
+/**\r
+ Triggers a run time or boot time SMI.\r
+\r
+ This function triggers a software SMM interrupt and set the APMC status with an 8-bit Data.\r
+\r
+ @param Data The value to set the APMC status.\r
+\r
+**/\r
+VOID\r
+InternalTriggerSmi (\r
+ IN UINT8 Data\r
+ )\r
+{\r
+ UINT16 PM1BLK_Base;\r
+ UINT16 GPE0BLK_Base;\r
+ UINT32 NewValue;\r
+\r
+ //\r
+ // Get PM1BLK_Base & GPE0BLK_Base\r
+ //\r
+ PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);\r
+ GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);\r
+\r
+\r
+ //\r
+ // Enable APM SMI\r
+ //\r
+ IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), B_QNC_GPE0BLK_SMIE_APM);\r
+\r
+ //\r
+ // Enable SMI globally\r
+ //\r
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
+ NewValue |= SMI_EN;\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);\r
+\r
+ //\r
+ // Set APM_STS\r
+ //\r
+ IoWrite8 (PcdGet16 (PcdSmmDataPort), Data);\r
+\r
+ //\r
+ // Generate the APM SMI\r
+ //\r
+ IoWrite8 (PcdGet16 (PcdSmmActivationPort), PcdGet8 (PcdSmmActivationData));\r
+\r
+ //\r
+ // Clear the APM SMI Status Bit\r
+ //\r
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);\r
+\r
+ //\r
+ // Set the EOS Bit\r
+ //\r
+ IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);\r
+}\r
+\r
+\r
+/**\r
+ Triggers an SMI at boot time.\r
+\r
+ This function triggers a software SMM interrupt at boot time.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TriggerBootServiceSoftwareSmi (\r
+ VOID\r
+ )\r
+{\r
+ InternalTriggerSmi (BOOT_SERVICE_SOFTWARE_SMI_DATA);\r
+}\r
+\r
+\r
+/**\r
+ Triggers an SMI at run time.\r
+\r
+ This function triggers a software SMM interrupt at run time.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TriggerRuntimeSoftwareSmi (\r
+ VOID\r
+ )\r
+{\r
+ InternalTriggerSmi (RUNTIME_SOFTWARE_SMI_DATA);\r
+}\r
+\r
+\r
+/**\r
+ Gets the software SMI data.\r
+\r
+ This function tests if a software SMM interrupt happens. If a software SMI happens,\r
+ it retrieves the SMM data and returns it as a non-negative value; otherwise a negative\r
+ value is returned.\r
+\r
+ @return Data The data retrieved from SMM data port in case of a software SMI;\r
+ otherwise a negative value.\r
+\r
+**/\r
+INTN\r
+InternalGetSwSmiData (\r
+ VOID\r
+ )\r
+{\r
+ UINT8 SmiStatus;\r
+ UINT8 Data;\r
+\r
+ SmiStatus = IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);\r
+ if (((SmiStatus & B_QNC_GPE0BLK_SMIS_APM) != 0) &&\r
+ (IoRead8 (PcdGet16 (PcdSmmActivationPort)) == PcdGet8 (PcdSmmActivationData))) {\r
+ Data = IoRead8 (PcdGet16 (PcdSmmDataPort));\r
+ return (INTN)(UINTN)Data;\r
+ }\r
+\r
+ return -1;\r
+}\r
+\r
+\r
+/**\r
+ Test if a boot time software SMI happened.\r
+\r
+ This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and\r
+ it was triggered at boot time, it returns TRUE. Otherwise, it returns FALSE.\r
+\r
+ @retval TRUE A software SMI triggered at boot time happened.\r
+ @retval FLASE No software SMI happened or the software SMI was triggered at run time.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsBootServiceSoftwareSmi (\r
+ VOID\r
+ )\r
+{\r
+ return (BOOLEAN) (InternalGetSwSmiData () == BOOT_SERVICE_SOFTWARE_SMI_DATA);\r
+}\r
+\r
+\r
+/**\r
+ Test if a run time software SMI happened.\r
+\r
+ This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and\r
+ it was triggered at run time, it returns TRUE. Otherwise, it returns FALSE.\r
+\r
+ @retval TRUE A software SMI triggered at run time happened.\r
+ @retval FLASE No software SMI happened or the software SMI was triggered at boot time.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsRuntimeSoftwareSmi (\r
+ VOID\r
+ )\r
+{\r
+ return (BOOLEAN) (InternalGetSwSmiData () == RUNTIME_SOFTWARE_SMI_DATA);\r
+}\r
+\r
+\r
+\r
+/**\r
+\r
+ Clear APM SMI Status Bit; Set the EOS bit.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ClearSmi (\r
+ VOID\r
+ )\r
+{\r
+\r
+ UINT16 GPE0BLK_Base;\r
+\r
+ //\r
+ // Get GpeBase\r
+ //\r
+ GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);\r
+\r
+ //\r
+ // Clear the APM SMI Status Bit\r
+ //\r
+ IoOr16 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_APM);\r
+\r
+ //\r
+ // Set the EOS Bit\r
+ //\r
+ IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS);\r
+}\r
+\r
+/**\r
+ This routine is the chipset code that accepts a request to "open" a region of SMRAM.\r
+ The region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.\r
+ The use of "open" means that the memory is visible from all boot-service\r
+ and SMM agents.\r
+\r
+ @retval FALSE Cannot open a locked SMRAM region\r
+ @retval TRUE Success to open SMRAM region.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QNCOpenSmramRegion (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Smram;\r
+\r
+ // Read the SMRAM register\r
+ Smram = QncHsmmcRead ();\r
+\r
+ //\r
+ // Is the platform locked?\r
+ //\r
+ if (Smram & SMM_LOCKED) {\r
+ // Cannot Open a locked region\r
+ DEBUG ((EFI_D_WARN, "Cannot open a locked SMRAM region\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Open all SMRAM regions for Host access only\r
+ //\r
+ Smram |= (SMM_WRITE_OPEN | SMM_READ_OPEN); // Open for Host.\r
+ Smram &= ~(NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN); // Not for others.\r
+\r
+ //\r
+ // Write the SMRAM register\r
+ //\r
+ QncHsmmcWrite (Smram);\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ This routine is the chipset code that accepts a request to "close" a region of SMRAM.\r
+ The region could be legacy AB or TSEG near top of physical memory.\r
+ The use of "close" means that the memory is only visible from SMM agents,\r
+ not from BS or RT code.\r
+\r
+ @retval FALSE Cannot open a locked SMRAM region\r
+ @retval TRUE Success to open SMRAM region.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+QNCCloseSmramRegion (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Smram;\r
+\r
+ // Read the SMRAM register.\r
+ Smram = QncHsmmcRead ();\r
+\r
+ //\r
+ // Is the platform locked?\r
+ //\r
+ if(Smram & SMM_LOCKED) {\r
+ // Cannot Open a locked region\r
+ DEBUG ((EFI_D_WARN, "Cannot close a locked SMRAM region\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ Smram &= (~(SMM_WRITE_OPEN | SMM_READ_OPEN | NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN));\r
+\r
+ QncHsmmcWrite (Smram);\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ This routine is the chipset code that accepts a request to "lock" SMRAM.\r
+ The region could be legacy AB or TSEG near top of physical memory.\r
+ The use of "lock" means that the memory can no longer be opened\r
+ to BS state.\r
+**/\r
+VOID\r
+EFIAPI\r
+QNCLockSmramRegion (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 Smram;\r
+\r
+ // Read the SMRAM register.\r
+ Smram = QncHsmmcRead ();\r
+ if(Smram & SMM_LOCKED) {\r
+ DEBUG ((EFI_D_WARN, "SMRAM region already locked!\n"));\r
+ }\r
+ Smram |= SMM_LOCKED;\r
+\r
+ QncHsmmcWrite (Smram);\r
+\r
+ return;\r
+}\r
--- /dev/null
+## @file\r
+# Component description file for Intel QNC SMM Library.\r
+#\r
+# QNC SMM Library that layers on top of the I/O Library to directly\r
+# access SMM power management registers.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = QNCSmmLib\r
+ FILE_GUID = 8A9A62F5-758B-4965-A28B-0AAC292FBD89\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = SmmLib\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ QNCSmmLib.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ PcdLib\r
+ IoLib\r
+ DebugLib\r
+ QNCAccessLib\r
+\r
+[Pcd]\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationData\r
--- /dev/null
+/** @file\r
+System reset Library Services. This library class provides a set of\r
+methods to reset whole system with manipulate QNC.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Base.h>\r
+#include <IntelQNCBase.h>\r
+#include <QNCAccess.h>\r
+\r
+#include <Uefi/UefiBaseType.h>\r
+\r
+#include <Library/ResetSystemLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/CpuLib.h>\r
+#include <Library/QNCAccessLib.h>\r
+\r
+//\r
+// Amount of time (seconds) before RTC alarm fires\r
+// This must be < BCD_BASE\r
+//\r
+#define PLATFORM_WAKE_SECONDS_BUFFER 0x06\r
+\r
+//\r
+// RTC 'seconds' above which we will not read to avoid potential rollover\r
+//\r
+#define PLATFORM_RTC_ROLLOVER_LIMIT 0x47\r
+\r
+//\r
+// BCD is base 10\r
+//\r
+#define BCD_BASE 0x0A\r
+\r
+#define PCAT_RTC_ADDRESS_REGISTER 0x70\r
+#define PCAT_RTC_DATA_REGISTER 0x71\r
+\r
+//\r
+// Dallas DS12C887 Real Time Clock\r
+//\r
+#define RTC_ADDRESS_SECONDS 0 // R/W Range 0..59\r
+#define RTC_ADDRESS_SECONDS_ALARM 1 // R/W Range 0..59\r
+#define RTC_ADDRESS_MINUTES 2 // R/W Range 0..59\r
+#define RTC_ADDRESS_MINUTES_ALARM 3 // R/W Range 0..59\r
+#define RTC_ADDRESS_HOURS 4 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM\r
+#define RTC_ADDRESS_HOURS_ALARM 5 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM\r
+#define RTC_ADDRESS_DAY_OF_THE_WEEK 6 // R/W Range 1..7\r
+#define RTC_ADDRESS_DAY_OF_THE_MONTH 7 // R/W Range 1..31\r
+#define RTC_ADDRESS_MONTH 8 // R/W Range 1..12\r
+#define RTC_ADDRESS_YEAR 9 // R/W Range 0..99\r
+#define RTC_ADDRESS_REGISTER_A 10 // R/W[0..6] R0[7]\r
+#define RTC_ADDRESS_REGISTER_B 11 // R/W\r
+#define RTC_ADDRESS_REGISTER_C 12 // RO\r
+#define RTC_ADDRESS_REGISTER_D 13 // RO\r
+#define RTC_ADDRESS_CENTURY 50 // R/W Range 19..20 Bit 8 is R/W\r
+\r
+/**\r
+ Wait for an RTC update to happen\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+WaitForRTCUpdate (\r
+VOID\r
+)\r
+{\r
+ UINT8 Data8;\r
+\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);\r
+ Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);\r
+ if ((Data8 & BIT7) == BIT7) {\r
+ while ((Data8 & BIT7) == BIT7) {\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);\r
+ Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);\r
+ }\r
+\r
+ } else {\r
+ while ((Data8 & BIT7) == 0) {\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);\r
+ Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);\r
+ }\r
+\r
+ while ((Data8 & BIT7) == BIT7) {\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);\r
+ Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Calling this function causes a system-wide reset. This sets\r
+ all circuitry within the system to its initial state. This type of reset\r
+ is asynchronous to system operation and operates without regard to\r
+ cycle boundaries.\r
+\r
+ System reset should not return, if it returns, it means the system does\r
+ not support cold reset.\r
+**/\r
+VOID\r
+EFIAPI\r
+ResetCold (\r
+VOID\r
+)\r
+{\r
+ //\r
+ // Reference to QuarkNcSocId BWG\r
+ // Setting bit 1 will generate a warm reset, driving only RSTRDY# low\r
+ //\r
+ IoWrite8 (RST_CNT, B_RST_CNT_COLD_RST);\r
+}\r
+\r
+/**\r
+ Calling this function causes a system-wide initialization. The processors\r
+ are set to their initial state, and pending cycles are not corrupted.\r
+\r
+ System reset should not return, if it returns, it means the system does\r
+ not support warm reset.\r
+**/\r
+VOID\r
+EFIAPI\r
+ResetWarm (\r
+VOID\r
+)\r
+{\r
+ //\r
+ // Reference to QuarkNcSocId BWG\r
+ // Setting bit 1 will generate a warm reset, driving only RSTRDY# low\r
+ //\r
+ IoWrite8 (RST_CNT, B_RST_CNT_WARM_RST);\r
+}\r
+\r
+/**\r
+ Calling this function causes the system to enter a power state equivalent\r
+ to the ACPI G2/S5 or G3 states.\r
+\r
+ System shutdown should not return, if it returns, it means the system does\r
+ not support shut down reset.\r
+**/\r
+VOID\r
+EFIAPI\r
+ResetShutdown (\r
+VOID\r
+)\r
+{\r
+ //\r
+ // Reference to QuarkNcSocId BWG\r
+ // Disable RTC Alarm : (RTC Enable at PM1BLK + 02h[10]))\r
+ //\r
+ IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0);\r
+\r
+ //\r
+ // Firstly, GPE0_EN should be disabled to\r
+ // avoid any GPI waking up the system from S5\r
+ //\r
+ IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0);\r
+\r
+ //\r
+ // Reference to QuarkNcSocId BWG\r
+ // Disable Resume Well GPIO : (GPIO bits in GPIOBASE + 34h[8:0])\r
+ //\r
+ IoWrite32 (PcdGet16 (PcdGbaIoBaseAddress) + R_QNC_GPIO_RGGPE_RESUME_WELL, 0);\r
+\r
+ //\r
+ // No power button status bit to clear for our platform, go to next step.\r
+ //\r
+\r
+ //\r
+ // Finally, transform system into S5 sleep state\r
+ //\r
+ IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, 0xffffc3ff, B_QNC_PM1BLK_PM1C_SLPEN | V_S5);\r
+}\r
+\r
+/**\r
+ Calling this function causes the system to enter a power state for capsule\r
+ update.\r
+\r
+ Reset update should not return, if it returns, it means the system does\r
+ not support capsule update.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EnterS3WithImmediateWake (\r
+VOID\r
+)\r
+{\r
+ UINT8 Data8;\r
+ UINT16 Data16;\r
+ UINT32 Data32;\r
+ UINTN Eflags;\r
+ UINTN RegCr0;\r
+ EFI_TIME EfiTime;\r
+ UINT32 SmiEnSave;\r
+\r
+ Eflags = AsmReadEflags ();\r
+ if ( (Eflags & 0x200) ) {\r
+ DisableInterrupts ();\r
+ }\r
+\r
+ //\r
+ // Write all cache data to memory because processor will lost power\r
+ //\r
+ AsmWbinvd();\r
+ RegCr0 = AsmReadCr0();\r
+ AsmWriteCr0 (RegCr0 | 0x060000000);\r
+\r
+ SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));\r
+\r
+ //\r
+ // Pogram RTC alarm for immediate WAKE\r
+ //\r
+\r
+ //\r
+ // Disable SMI sources\r
+ //\r
+ IoWrite16 (PcdGet16 (PcdGpe0blkIoBaseAddress) + R_QNC_GPE0BLK_SMIE, 0);\r
+\r
+ //\r
+ // Disable RTC alarm interrupt\r
+ //\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);\r
+ Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);\r
+ IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 & ~BIT5));\r
+\r
+ //\r
+ // Clear RTC alarm if already set\r
+ //\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);\r
+ Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); // Read clears alarm status\r
+\r
+ //\r
+ // Disable all WAKE events\r
+ //\r
+ IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, B_QNC_PM1BLK_PM1E_PWAKED);\r
+\r
+ //\r
+ // Clear all WAKE status bits\r
+ //\r
+ IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S, B_QNC_PM1BLK_PM1S_ALL);\r
+\r
+ //\r
+ // Avoid RTC rollover\r
+ //\r
+ do {\r
+ WaitForRTCUpdate();\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);\r
+ EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);\r
+ } while (EfiTime.Second > PLATFORM_RTC_ROLLOVER_LIMIT);\r
+\r
+ //\r
+ // Read RTC time\r
+ //\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS);\r
+ EfiTime.Hour = IoRead8 (PCAT_RTC_DATA_REGISTER);\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES);\r
+ EfiTime.Minute = IoRead8 (PCAT_RTC_DATA_REGISTER);\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);\r
+ EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);\r
+\r
+ //\r
+ // Set RTC alarm\r
+ //\r
+\r
+ //\r
+ // Add PLATFORM_WAKE_SECONDS_BUFFER to current EfiTime.Second\r
+ // The maths is to allow for the fact we are adding to a BCD number and require the answer to be BCD (EfiTime.Second)\r
+ //\r
+ if ((BCD_BASE - (EfiTime.Second & 0x0F)) <= PLATFORM_WAKE_SECONDS_BUFFER) {\r
+ Data8 = (((EfiTime.Second & 0xF0) + 0x10) + (PLATFORM_WAKE_SECONDS_BUFFER - (BCD_BASE - (EfiTime.Second & 0x0F))));\r
+ } else {\r
+ Data8 = EfiTime.Second + PLATFORM_WAKE_SECONDS_BUFFER;\r
+ }\r
+\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS_ALARM);\r
+ IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Hour);\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES_ALARM);\r
+ IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Minute);\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS_ALARM);\r
+ IoWrite8 (PCAT_RTC_DATA_REGISTER, Data8);\r
+\r
+ //\r
+ // Enable RTC alarm interrupt\r
+ //\r
+ IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);\r
+ Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);\r
+ IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 | BIT5));\r
+\r
+ //\r
+ // Enable RTC alarm as WAKE event\r
+ //\r
+ Data16 = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E);\r
+ IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, (Data16 | B_QNC_PM1BLK_PM1E_RTC));\r
+\r
+ //\r
+ // Enter S3\r
+ //\r
+ Data32 = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);\r
+ Data32 = (UINT32) ((Data32 & 0xffffc3fe) | V_S3 | B_QNC_PM1BLK_PM1C_SCIEN);\r
+ IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);\r
+ Data32 = Data32 | B_QNC_PM1BLK_PM1C_SLPEN;\r
+ IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);\r
+\r
+ //\r
+ // Enable Interrupt if it's enabled before\r
+ //\r
+ if ( (Eflags & 0x200) ) {\r
+ EnableInterrupts ();\r
+ }\r
+}\r
+\r
--- /dev/null
+## @file\r
+# Component description file for Intel QuarkNcSocId Reset System Library.\r
+#\r
+# Reset System Library implementation that bases on QNC.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = ResetSystemLib\r
+ FILE_GUID = AD33A56E-3AAD-40ac-91B1-FA861E8D9D85\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = ResetSystemLib\r
+\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+ ResetSystemLib.c\r
+\r
+\r
+[Packages]\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+ PcdLib\r
+ IoLib\r
+ BaseLib\r
+ CpuLib\r
+ QNCAccessLib\r
+\r
+[Pcd]\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress\r
--- /dev/null
+/** @file\r
+Common header file shared by all source files.\r
+\r
+This file includes package header files, library classes and protocol, PPI & GUID definitions.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef __COMMON_HEADER_H_\r
+#define __COMMON_HEADER_H_\r
+\r
+\r
+#include <Uefi.h>\r
+#include <Base.h>\r
+\r
+#include <Library/SmbusLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/QNCAccessLib.h>\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Intel QNC SMBUS library implementation built upon I/O library.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+/**\r
+ Gets Io port base address of Smbus Host Controller.\r
+\r
+ This internal function depends on a feature flag named PcdIchSmbusFixedIoPortBaseAddress\r
+ to retrieve Smbus Io port base. If that feature flag is true, it will get Smbus Io port base\r
+ address from a preset Pcd entry named PcdIchSmbusIoPortBaseAddress; otherwise, it will always\r
+ read Pci configuration space to get that value in each Smbus bus transaction.\r
+\r
+ @return The Io port base address of Smbus host controller.\r
+\r
+**/\r
+UINTN\r
+InternalGetSmbusIoPortBaseAddress (\r
+ VOID\r
+ )\r
+{\r
+ UINTN IoPortBaseAddress;\r
+\r
+ if (FeaturePcdGet (PcdSmbaIoBaseAddressFixed)) {\r
+ IoPortBaseAddress = (UINTN) PcdGet16 (PcdSmbaIoBaseAddress);\r
+ } else {\r
+ IoPortBaseAddress = (UINTN) LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) & B_QNC_LPC_SMBUS_BASE_MASK;\r
+ }\r
+\r
+ //\r
+ // Make sure that the IO port base address has been properly set.\r
+ //\r
+ ASSERT (IoPortBaseAddress != 0);\r
+\r
+ return IoPortBaseAddress;\r
+}\r
+\r
+\r
+/**\r
+ Acquires the ownership of SMBUS.\r
+\r
+ This internal function reads the host state register.\r
+ If the SMBUS is not available, RETURN_TIMEOUT is returned;\r
+ Otherwise, it performs some basic initializations and returns\r
+ RETURN_SUCCESS.\r
+\r
+ @param IoPortBaseAddress The Io port base address of Smbus Host controller.\r
+\r
+ @retval RETURN_SUCCESS The SMBUS command was executed successfully.\r
+ @retval RETURN_TIMEOUT A timeout occurred while executing the SMBUS command.\r
+\r
+**/\r
+RETURN_STATUS\r
+InternalSmBusAcquire (\r
+ UINTN IoPortBaseAddress\r
+ )\r
+{\r
+\r
+ //\r
+ // Clear host status register and exit.\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL, 0);\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, 0);\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD1, 0);\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);\r
+\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Starts the SMBUS transaction and waits until the end.\r
+\r
+ This internal function start the SMBUS transaction and waits until the transaction\r
+ of SMBUS is over by polling the INTR bit of Host status register.\r
+ If the SMBUS is not available, RETURN_TIMEOUT is returned;\r
+ Otherwise, it performs some basic initializations and returns\r
+ RETURN_SUCCESS.\r
+\r
+ @param IoPortBaseAddress The Io port base address of Smbus Host controller.\r
+ @param HostControl The Host control command to start SMBUS transaction.\r
+\r
+ @retval RETURN_SUCCESS The SMBUS command was executed successfully.\r
+ @retval RETURN_CRC_ERROR The checksum is not correct (PEC is incorrect).\r
+ @retval RETURN_DEVICE_ERROR The request was not completed because a failure reflected\r
+ in the Host Status Register bit. Device errors are\r
+ a result of a transaction collision, illegal command field,\r
+ unclaimed cycle (host initiated), or bus errors (collisions).\r
+\r
+**/\r
+RETURN_STATUS\r
+InternalSmBusStart (\r
+ IN UINTN IoPortBaseAddress,\r
+ IN UINT8 HostControl\r
+ )\r
+{\r
+ UINT8 HostStatus;\r
+\r
+ //\r
+ // Set Host Control Register (Initiate Operation, Interrupt disabled).\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL, HostControl + B_QNC_SMBUS_START);\r
+\r
+ do {\r
+ //\r
+ // Poll INTR bit of Host Status Register.\r
+ //\r
+ HostStatus = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS);\r
+ } while ((HostStatus & (B_QNC_SMBUS_BYTE_DONE_STS | B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR)) == 0);\r
+\r
+ if ((HostStatus & (B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR)) == 0) {\r
+ return RETURN_SUCCESS;\r
+ }\r
+ //\r
+ // Clear error bits of Host Status Register.\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, (B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR));\r
+\r
+ return RETURN_DEVICE_ERROR;\r
+}\r
+\r
+/**\r
+ Executes an SMBUS quick, byte or word command.\r
+\r
+ This internal function executes an SMBUS quick, byte or word commond.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+\r
+ @param HostControl The value of Host Control Register to set.\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Value The byte/word write to the SMBUS.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @return The byte/word read from the SMBUS.\r
+\r
+**/\r
+UINT16\r
+InternalSmBusNonBlock (\r
+ IN UINT8 HostControl,\r
+ IN UINTN SmBusAddress,\r
+ IN UINT16 Value,\r
+ OUT RETURN_STATUS *Status\r
+ )\r
+{\r
+ RETURN_STATUS ReturnStatus;\r
+ UINTN IoPortBaseAddress;\r
+\r
+ IoPortBaseAddress = InternalGetSmbusIoPortBaseAddress ();\r
+\r
+ //\r
+ // Try to acquire the ownership of QNC SMBUS.\r
+ //\r
+ ReturnStatus = InternalSmBusAcquire (IoPortBaseAddress);\r
+ if (RETURN_ERROR (ReturnStatus)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Set Host Commond Register.\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCMD, (UINT8) SMBUS_LIB_COMMAND (SmBusAddress));\r
+ //\r
+ // Write value to Host Data 0 and Host Data 1 Registers.\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, (UINT8) Value);\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD1, (UINT8) (Value >> 8));\r
+\r
+\r
+ //\r
+ // Set SMBUS slave address for the device to send/receive from.\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_TSA, (UINT8) SmBusAddress);\r
+ //\r
+ // Start the SMBUS transaction and wait for the end.\r
+ //\r
+ ReturnStatus = InternalSmBusStart (IoPortBaseAddress, HostControl);\r
+ //\r
+ // Read value from Host Data 0 and Host Data 1 Registers.\r
+ //\r
+ Value = (UINT16)(IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD1) << 8);\r
+ Value = (UINT16)(Value | IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD0));\r
+\r
+ //\r
+ // Clear Host Status Register and Auxiliary Status Register.\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);\r
+\r
+Done:\r
+ if (Status != NULL) {\r
+ *Status = ReturnStatus;\r
+ }\r
+\r
+ return Value;\r
+}\r
+\r
+/**\r
+ Executes an SMBUS quick read command.\r
+\r
+ Executes an SMBUS quick read command on the SMBUS device specified by SmBusAddress.\r
+ Only the SMBUS slave address field of SmBusAddress is required.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ If PEC is set in SmBusAddress, then ASSERT().\r
+ If Command in SmBusAddress is not zero, then ASSERT().\r
+ If Length in SmBusAddress is not zero, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmBusQuickRead (\r
+ IN UINTN SmBusAddress,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (!SMBUS_LIB_PEC (SmBusAddress));\r
+ ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0);\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+\r
+ InternalSmBusNonBlock (\r
+ V_QNC_SMBUS_HCTL_CMD_QUICK,\r
+ SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,\r
+ 0,\r
+ Status\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ Executes an SMBUS quick write command.\r
+\r
+ Executes an SMBUS quick write command on the SMBUS device specified by SmBusAddress.\r
+ Only the SMBUS slave address field of SmBusAddress is required.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ If PEC is set in SmBusAddress, then ASSERT().\r
+ If Command in SmBusAddress is not zero, then ASSERT().\r
+ If Length in SmBusAddress is not zero, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmBusQuickWrite (\r
+ IN UINTN SmBusAddress,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (!SMBUS_LIB_PEC (SmBusAddress));\r
+ ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0);\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+\r
+ InternalSmBusNonBlock (\r
+ V_QNC_SMBUS_HCTL_CMD_QUICK,\r
+ SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE,\r
+ 0,\r
+ Status\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ Executes an SMBUS receive byte command.\r
+\r
+ Executes an SMBUS receive byte command on the SMBUS device specified by SmBusAddress.\r
+ Only the SMBUS slave address field of SmBusAddress is required.\r
+ The byte received from the SMBUS is returned.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ If Command in SmBusAddress is not zero, then ASSERT().\r
+ If Length in SmBusAddress is not zero, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @return The byte received from the SMBUS.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+SmBusReceiveByte (\r
+ IN UINTN SmBusAddress,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0);\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+\r
+ return (UINT8) InternalSmBusNonBlock (\r
+ V_QNC_SMBUS_HCTL_CMD_BYTE,\r
+ SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,\r
+ 0,\r
+ Status\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ Executes an SMBUS send byte command.\r
+\r
+ Executes an SMBUS send byte command on the SMBUS device specified by SmBusAddress.\r
+ The byte specified by Value is sent.\r
+ Only the SMBUS slave address field of SmBusAddress is required. Value is returned.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ If Command in SmBusAddress is not zero, then ASSERT().\r
+ If Length in SmBusAddress is not zero, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Value The 8-bit value to send.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @return The parameter of Value.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+SmBusSendByte (\r
+ IN UINTN SmBusAddress,\r
+ IN UINT8 Value,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0);\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+\r
+ return (UINT8) InternalSmBusNonBlock (\r
+ V_QNC_SMBUS_HCTL_CMD_BYTE,\r
+ SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE,\r
+ Value,\r
+ Status\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ Executes an SMBUS read data byte command.\r
+\r
+ Executes an SMBUS read data byte command on the SMBUS device specified by SmBusAddress.\r
+ Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.\r
+ The 8-bit value read from the SMBUS is returned.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ If Length in SmBusAddress is not zero, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @return The byte read from the SMBUS.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+SmBusReadDataByte (\r
+ IN UINTN SmBusAddress,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+\r
+ return (UINT8) InternalSmBusNonBlock (\r
+ V_QNC_SMBUS_HCTL_CMD_BYTE_DATA,\r
+ SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,\r
+ 0,\r
+ Status\r
+ );\r
+}\r
+\r
+/**\r
+ Executes an SMBUS write data byte command.\r
+\r
+ Executes an SMBUS write data byte command on the SMBUS device specified by SmBusAddress.\r
+ The 8-bit value specified by Value is written.\r
+ Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.\r
+ Value is returned.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ If Length in SmBusAddress is not zero, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Value The 8-bit value to write.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @return The parameter of Value.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+SmBusWriteDataByte (\r
+ IN UINTN SmBusAddress,\r
+ IN UINT8 Value,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+\r
+ return (UINT8) InternalSmBusNonBlock (\r
+ V_QNC_SMBUS_HCTL_CMD_BYTE_DATA,\r
+ SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE,\r
+ Value,\r
+ Status\r
+ );\r
+}\r
+\r
+/**\r
+ Executes an SMBUS read data word command.\r
+\r
+ Executes an SMBUS read data word command on the SMBUS device specified by SmBusAddress.\r
+ Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.\r
+ The 16-bit value read from the SMBUS is returned.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ If Length in SmBusAddress is not zero, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @return The byte read from the SMBUS.\r
+\r
+**/\r
+UINT16\r
+EFIAPI\r
+SmBusReadDataWord (\r
+ IN UINTN SmBusAddress,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 2);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+\r
+ return InternalSmBusNonBlock (\r
+ V_QNC_SMBUS_HCTL_CMD_WORD_DATA,\r
+ SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,\r
+ 0,\r
+ Status\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ Executes an SMBUS write data word command.\r
+\r
+ Executes an SMBUS write data word command on the SMBUS device specified by SmBusAddress.\r
+ The 16-bit value specified by Value is written.\r
+ Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.\r
+ Value is returned.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ If Length in SmBusAddress is not zero, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Value The 16-bit value to write.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @return The parameter of Value.\r
+\r
+**/\r
+UINT16\r
+EFIAPI\r
+SmBusWriteDataWord (\r
+ IN UINTN SmBusAddress,\r
+ IN UINT16 Value,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 2);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+\r
+ return InternalSmBusNonBlock (\r
+ V_QNC_SMBUS_HCTL_CMD_WORD_DATA,\r
+ SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE,\r
+ Value,\r
+ Status\r
+ );\r
+}\r
+\r
+/**\r
+ Executes an SMBUS process call command.\r
+\r
+ Executes an SMBUS process call command on the SMBUS device specified by SmBusAddress.\r
+ The 16-bit value specified by Value is written.\r
+ Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.\r
+ The 16-bit value returned by the process call command is returned.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ If Length in SmBusAddress is not zero, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Value The 16-bit value to write.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @return The 16-bit value returned by the process call command.\r
+\r
+**/\r
+UINT16\r
+EFIAPI\r
+SmBusProcessCall (\r
+ IN UINTN SmBusAddress,\r
+ IN UINT16 Value,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+\r
+ return InternalSmBusNonBlock (\r
+ V_QNC_SMBUS_HCTL_CMD_PROCESS_CALL,\r
+ SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE,\r
+ Value,\r
+ Status\r
+ );\r
+\r
+}\r
+\r
+/**\r
+ Executes an SMBUS block command.\r
+\r
+ Executes an SMBUS block read, block write and block write-block read command\r
+ on the SMBUS device specified by SmBusAddress.\r
+ Bytes are read from the SMBUS and stored in Buffer.\r
+ The number of bytes read is returned, and will never return a value larger than 32-bytes.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.\r
+ SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes.\r
+\r
+ @param HostControl The value of Host Control Register to set.\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param WriteBuffer Pointer to the buffer of bytes to write to the SMBUS.\r
+ @param ReadBuffer Pointer to the buffer of bytes to read from the SMBUS.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @return The number of bytes read from the SMBUS.\r
+\r
+**/\r
+UINTN\r
+InternalSmBusBlock (\r
+ IN UINT8 HostControl,\r
+ IN UINTN SmBusAddress,\r
+ IN UINT8 *WriteBuffer,\r
+ OUT UINT8 *ReadBuffer,\r
+ OUT RETURN_STATUS *Status\r
+ )\r
+{\r
+ RETURN_STATUS ReturnStatus;\r
+ UINTN Index;\r
+ UINTN BytesCount;\r
+ UINTN IoPortBaseAddress;\r
+\r
+ IoPortBaseAddress = InternalGetSmbusIoPortBaseAddress ();\r
+\r
+ BytesCount = SMBUS_LIB_LENGTH (SmBusAddress);\r
+\r
+ //\r
+ // Try to acquire the ownership of ICH SMBUS.\r
+ //\r
+ ReturnStatus = InternalSmBusAcquire (IoPortBaseAddress);\r
+ if (RETURN_ERROR (ReturnStatus)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Set Host Command Register.\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCMD, (UINT8) SMBUS_LIB_COMMAND (SmBusAddress));\r
+\r
+ //\r
+ // Clear byte pointer of 32-byte buffer.\r
+ //\r
+ IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL);\r
+\r
+ if (WriteBuffer != NULL) {\r
+ //\r
+ // Write the number of block to Host Block Data Byte Register.\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, (UINT8) BytesCount);\r
+ //\r
+ // Write data block to Host Block Data Register.\r
+ //\r
+ for (Index = 0; Index < BytesCount; Index++) {\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HBD + (UINT8)Index, WriteBuffer[Index]);\r
+ }\r
+ }\r
+ //\r
+ // Set SMBUS slave address for the device to send/receive from.\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_TSA, (UINT8) SmBusAddress);\r
+ //\r
+ // Start the SMBUS transaction and wait for the end.\r
+ //\r
+ ReturnStatus = InternalSmBusStart (IoPortBaseAddress, HostControl);\r
+ if (RETURN_ERROR (ReturnStatus)) {\r
+ goto Done;\r
+ }\r
+\r
+ if (ReadBuffer != NULL) {\r
+ //\r
+ // Read the number of block from host block data byte register.\r
+ //\r
+ BytesCount = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD0);\r
+ //\r
+ // Write data block from Host Block Data Register.\r
+ //\r
+ for (Index = 0; Index < BytesCount; Index++) {\r
+ ReadBuffer[Index] = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HBD + (UINT8)Index);\r
+ }\r
+ }\r
+\r
+Done:\r
+ //\r
+ // Clear Host Status Register and Auxiliary Status Register.\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);\r
+\r
+ if (Status != NULL) {\r
+ *Status = ReturnStatus;\r
+ }\r
+\r
+ return BytesCount;\r
+}\r
+\r
+/**\r
+ Executes an SMBUS read block command.\r
+\r
+ Executes an SMBUS read block command on the SMBUS device specified by SmBusAddress.\r
+ Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.\r
+ Bytes are read from the SMBUS and stored in Buffer.\r
+ The number of bytes read is returned, and will never return a value larger than 32-bytes.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.\r
+ SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes.\r
+ If Length in SmBusAddress is not zero, then ASSERT().\r
+ If Buffer is NULL, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Buffer Pointer to the buffer to store the bytes read from the SMBUS.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @return The number of bytes read.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+SmBusReadBlock (\r
+ IN UINTN SmBusAddress,\r
+ OUT VOID *Buffer,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (Buffer != NULL);\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1);\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+\r
+ return InternalSmBusBlock (\r
+ V_QNC_SMBUS_HCTL_CMD_BLOCK,\r
+ SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,\r
+ NULL,\r
+ Buffer,\r
+ Status\r
+ );\r
+}\r
+\r
+/**\r
+ Executes an SMBUS write block command.\r
+\r
+ Executes an SMBUS write block command on the SMBUS device specified by SmBusAddress.\r
+ The SMBUS slave address, SMBUS command, and SMBUS length fields of SmBusAddress are required.\r
+ Bytes are written to the SMBUS from Buffer.\r
+ The number of bytes written is returned, and will never return a value larger than 32-bytes.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ If Length in SmBusAddress is zero or greater than 32, then ASSERT().\r
+ If Buffer is NULL, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param Buffer Pointer to the buffer to store the bytes read from the SMBUS.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @return The number of bytes written.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+SmBusWriteBlock (\r
+ IN UINTN SmBusAddress,\r
+ OUT VOID *Buffer,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (Buffer != NULL);\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1);\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+\r
+ return InternalSmBusBlock (\r
+ V_QNC_SMBUS_HCTL_CMD_BLOCK,\r
+ SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE,\r
+ Buffer,\r
+ NULL,\r
+ Status\r
+ );\r
+}\r
+\r
+/**\r
+ Executes an SMBUS block process call command.\r
+\r
+ Executes an SMBUS block process call command on the SMBUS device specified by SmBusAddress.\r
+ The SMBUS slave address, SMBUS command, and SMBUS length fields of SmBusAddress are required.\r
+ Bytes are written to the SMBUS from WriteBuffer. Bytes are then read from the SMBUS into ReadBuffer.\r
+ If Status is not NULL, then the status of the executed command is returned in Status.\r
+ It is the caller's responsibility to make sure ReadBuffer is large enough for the total number of bytes read.\r
+ SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes.\r
+ If Length in SmBusAddress is zero or greater than 32, then ASSERT().\r
+ If WriteBuffer is NULL, then ASSERT().\r
+ If ReadBuffer is NULL, then ASSERT().\r
+ If any reserved bits of SmBusAddress are set, then ASSERT().\r
+\r
+ @param SmBusAddress Address that encodes the SMBUS Slave Address,\r
+ SMBUS Command, SMBUS Data Length, and PEC.\r
+ @param WriteBuffer Pointer to the buffer of bytes to write to the SMBUS.\r
+ @param ReadBuffer Pointer to the buffer of bytes to read from the SMBUS.\r
+ @param Status Return status for the executed command.\r
+ This is an optional parameter and may be NULL.\r
+ RETURN_TIMEOUT A timeout occurred while executing the SMBUS command.\r
+ RETURN_DEVICE_ERROR The request was not completed because a failure\r
+ reflected in the Host Status Register bit. Device errors are a result\r
+ of a transaction collision, illegal command field, unclaimed cycle\r
+ (host initiated), or bus errors (collisions).\r
+ RETURN_CRC_ERROR The checksum is not correct (PEC is incorrect)\r
+ RETURN_UNSUPPORTED The SMBus operation is not supported.\r
+\r
+ @return The number of bytes written.\r
+\r
+**/\r
+UINTN\r
+EFIAPI\r
+SmBusBlockProcessCall (\r
+ IN UINTN SmBusAddress,\r
+ IN VOID *WriteBuffer,\r
+ OUT VOID *ReadBuffer,\r
+ OUT RETURN_STATUS *Status OPTIONAL\r
+ )\r
+{\r
+ ASSERT (WriteBuffer != NULL);\r
+ ASSERT (ReadBuffer != NULL);\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1);\r
+ ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32);\r
+ ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);\r
+ if (Status != NULL) {\r
+ *Status = RETURN_UNSUPPORTED;\r
+ }\r
+ return 0;\r
+}\r
--- /dev/null
+## @file\r
+# Component description file for Intel QNC Smbus Library.\r
+#\r
+# SMBUS Library that layers on top of the I/O Library to directly\r
+# access a standard SMBUS host controller.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SmbusLib\r
+ FILE_GUID = 6F2F36B3-936B-4eb2-83C7-2987B4F9D4EB\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = SmbusLib\r
+\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ SmbusLib.c\r
+ CommonHeader.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ PcdLib\r
+ DebugLib\r
+ PciLib\r
+ IoLib\r
+ QNCAccessLib\r
+\r
+[FeaturePcd]\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed\r
+\r
+[Pcd]\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress\r
--- /dev/null
+/** @file\r
+The Quark CPU specific programming for PiSmmCpuDxeSmm module.\r
+\r
+Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiSmm.h>\r
+#include <Library/SmmCpuFeaturesLib.h>\r
+#include <Register/SmramSaveStateMap.h>\r
+#include <Library/QNCAccessLib.h>\r
+\r
+#define EFI_MSR_SMRR_PHYS_MASK_VALID BIT11\r
+#define EFI_MSR_SMRR_MASK 0xFFFFF000\r
+\r
+/**\r
+ Called during the very first SMI into System Management Mode to initialize\r
+ CPU features, including SMBASE, for the currently executing CPU. Since this\r
+ is the first SMI, the SMRAM Save State Map is at the default address of\r
+ SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing\r
+ CPU is specified by CpuIndex and CpuIndex can be used to access information\r
+ about the currently executing CPU in the ProcessorInfo array and the\r
+ HotPlugCpuData data structure.\r
+\r
+ @param[in] CpuIndex The index of the CPU to initialize. The value\r
+ must be between 0 and the NumberOfCpus field in\r
+ the System Management System Table (SMST).\r
+ @param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that\r
+ was elected as monarch during System Management\r
+ Mode initialization.\r
+ FALSE if the CpuIndex is not the index of the CPU\r
+ that was elected as monarch during System\r
+ Management Mode initialization.\r
+ @param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION\r
+ structures. ProcessorInfo[CpuIndex] contains the\r
+ information for the currently executing CPU.\r
+ @param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that\r
+ contains the ApidId and SmBase arrays.\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmCpuFeaturesInitializeProcessor (\r
+ IN UINTN CpuIndex,\r
+ IN BOOLEAN IsMonarch,\r
+ IN EFI_PROCESSOR_INFORMATION *ProcessorInfo,\r
+ IN CPU_HOT_PLUG_DATA *CpuHotPlugData\r
+ )\r
+{\r
+ SMRAM_SAVE_STATE_MAP *CpuState;\r
+\r
+ //\r
+ // Configure SMBASE.\r
+ //\r
+ CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);\r
+ CpuState->x86.SMBASE = CpuHotPlugData->SmBase[CpuIndex];\r
+\r
+ //\r
+ // Use QNC to initialize SMRR on Quark\r
+ //\r
+ QNCPortWrite(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSBASE, CpuHotPlugData->SmrrBase);\r
+ 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);\r
+}\r
+\r
+/**\r
+ This function updates the SMRAM save state on the currently executing CPU\r
+ to resume execution at a specific address after an RSM instruction. This\r
+ function must evaluate the SMRAM save state to determine the execution mode\r
+ the RSM instruction resumes and update the resume execution address with\r
+ either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart\r
+ flag in the SMRAM save state must always be cleared. This function returns\r
+ the value of the instruction pointer from the SMRAM save state that was\r
+ replaced. If this function returns 0, then the SMRAM save state was not\r
+ modified.\r
+\r
+ This function is called during the very first SMI on each CPU after\r
+ SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode\r
+ to signal that the SMBASE of each CPU has been updated before the default\r
+ SMBASE address is used for the first SMI to the next CPU.\r
+\r
+ @param[in] CpuIndex The index of the CPU to hook. The value\r
+ must be between 0 and the NumberOfCpus\r
+ field in the System Management System Table\r
+ (SMST).\r
+ @param[in] CpuState Pointer to SMRAM Save State Map for the\r
+ currently executing CPU.\r
+ @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to\r
+ 32-bit execution mode from 64-bit SMM.\r
+ @param[in] NewInstructionPointer Instruction pointer to use if resuming to\r
+ same execution mode as SMM.\r
+\r
+ @retval 0 This function did modify the SMRAM save state.\r
+ @retval > 0 The original instruction pointer value from the SMRAM save state\r
+ before it was replaced.\r
+**/\r
+UINT64\r
+EFIAPI\r
+SmmCpuFeaturesHookReturnFromSmm (\r
+ IN UINTN CpuIndex,\r
+ IN SMRAM_SAVE_STATE_MAP *CpuState,\r
+ IN UINT64 NewInstructionPointer32,\r
+ IN UINT64 NewInstructionPointer\r
+ )\r
+{\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Hook point in normal execution mode that allows the one CPU that was elected\r
+ as monarch during System Management Mode initialization to perform additional\r
+ initialization actions immediately after all of the CPUs have processed their\r
+ first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE\r
+ into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmCpuFeaturesSmmRelocationComplete (\r
+ VOID\r
+ )\r
+{\r
+}\r
+\r
+/**\r
+ Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is\r
+ returned, then a custom SMI handler is not provided by this library,\r
+ and the default SMI handler must be used.\r
+\r
+ @retval 0 Use the default SMI handler.\r
+ @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()\r
+ The caller is required to allocate enough SMRAM for each CPU to\r
+ support the size of the custom SMI handler.\r
+**/\r
+UINTN\r
+EFIAPI\r
+SmmCpuFeaturesGetSmiHandlerSize (\r
+ VOID\r
+ )\r
+{\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Install a custom SMI handler for the CPU specified by CpuIndex. This function\r
+ is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater\r
+ than zero and is called by the CPU that was elected as monarch during System\r
+ Management Mode initialization.\r
+\r
+ @param[in] CpuIndex The index of the CPU to install the custom SMI handler.\r
+ The value must be between 0 and the NumberOfCpus field\r
+ in the System Management System Table (SMST).\r
+ @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.\r
+ @param[in] SmiStack The stack to use when an SMI is processed by the\r
+ the CPU specified by CpuIndex.\r
+ @param[in] StackSize The size, in bytes, if the stack used when an SMI is\r
+ processed by the CPU specified by CpuIndex.\r
+ @param[in] GdtBase The base address of the GDT to use when an SMI is\r
+ processed by the CPU specified by CpuIndex.\r
+ @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is\r
+ processed by the CPU specified by CpuIndex.\r
+ @param[in] IdtBase The base address of the IDT to use when an SMI is\r
+ processed by the CPU specified by CpuIndex.\r
+ @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is\r
+ processed by the CPU specified by CpuIndex.\r
+ @param[in] Cr3 The base address of the page tables to use when an SMI\r
+ is processed by the CPU specified by CpuIndex.\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmCpuFeaturesInstallSmiHandler (\r
+ IN UINTN CpuIndex,\r
+ IN UINT32 SmBase,\r
+ IN VOID *SmiStack,\r
+ IN UINTN StackSize,\r
+ IN UINTN GdtBase,\r
+ IN UINTN GdtSize,\r
+ IN UINTN IdtBase,\r
+ IN UINTN IdtSize,\r
+ IN UINT32 Cr3\r
+ )\r
+{\r
+}\r
+\r
+/**\r
+ Determines if MTRR registers must be configured to set SMRAM cache-ability\r
+ when executing in System Management Mode.\r
+\r
+ @retval TRUE MTRR registers must be configured to set SMRAM cache-ability.\r
+ @retval FALSE MTRR registers do not need to be configured to set SMRAM\r
+ cache-ability.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+SmmCpuFeaturesNeedConfigureMtrrs (\r
+ VOID\r
+ )\r
+{\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()\r
+ returns TRUE.\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmCpuFeaturesDisableSmrr (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Use QNC to disable SMRR on Quark\r
+ //\r
+ QNCPortWrite(\r
+ QUARK_NC_HOST_BRIDGE_SB_PORT_ID,\r
+ QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK,\r
+ QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK) & ~EFI_MSR_SMRR_PHYS_MASK_VALID\r
+ );\r
+}\r
+\r
+/**\r
+ Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()\r
+ returns TRUE.\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmCpuFeaturesReenableSmrr (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Use QNC to enable SMRR on Quark\r
+ //\r
+ QNCPortWrite(\r
+ QUARK_NC_HOST_BRIDGE_SB_PORT_ID,\r
+ QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK,\r
+ QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK) | EFI_MSR_SMRR_PHYS_MASK_VALID\r
+ );\r
+}\r
+\r
+/**\r
+ Processor specific hook point each time a CPU enters System Management Mode.\r
+\r
+ @param[in] CpuIndex The index of the CPU that has entered SMM. The value\r
+ must be between 0 and the NumberOfCpus field in the\r
+ System Management System Table (SMST).\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmCpuFeaturesRendezvousEntry (\r
+ IN UINTN CpuIndex\r
+ )\r
+{\r
+}\r
+\r
+/**\r
+ Processor specific hook point each time a CPU exits System Management Mode.\r
+\r
+ @param[in] CpuIndex The index of the CPU that is exiting SMM. The value must\r
+ be between 0 and the NumberOfCpus field in the System\r
+ Management System Table (SMST).\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmCpuFeaturesRendezvousExit (\r
+ IN UINTN CpuIndex\r
+ )\r
+{\r
+}\r
+\r
+/**\r
+ Check to see if an SMM register is supported by a specified CPU.\r
+\r
+ @param[in] CpuIndex The index of the CPU to check for SMM register support.\r
+ The value must be between 0 and the NumberOfCpus field\r
+ in the System Management System Table (SMST).\r
+ @param[in] RegName Identifies the SMM register to check for support.\r
+\r
+ @retval TRUE The SMM register specified by RegName is supported by the CPU\r
+ specified by CpuIndex.\r
+ @retval FALSE The SMM register specified by RegName is not supported by the\r
+ CPU specified by CpuIndex.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+SmmCpuFeaturesIsSmmRegisterSupported (\r
+ IN UINTN CpuIndex,\r
+ IN SMM_REG_NAME RegName\r
+ )\r
+{\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Returns the current value of the SMM register for the specified CPU.\r
+ If the SMM register is not supported, then 0 is returned.\r
+\r
+ @param[in] CpuIndex The index of the CPU to read the SMM register. The\r
+ value must be between 0 and the NumberOfCpus field in\r
+ the System Management System Table (SMST).\r
+ @param[in] RegName Identifies the SMM register to read.\r
+\r
+ @return The value of the SMM register specified by RegName from the CPU\r
+ specified by CpuIndex.\r
+**/\r
+UINT64\r
+EFIAPI\r
+SmmCpuFeaturesGetSmmRegister (\r
+ IN UINTN CpuIndex,\r
+ IN SMM_REG_NAME RegName\r
+ )\r
+{\r
+ return 0;\r
+}\r
+\r
+/**\r
+ Sets the value of an SMM register on a specified CPU.\r
+ If the SMM register is not supported, then no action is performed.\r
+\r
+ @param[in] CpuIndex The index of the CPU to write the SMM register. The\r
+ value must be between 0 and the NumberOfCpus field in\r
+ the System Management System Table (SMST).\r
+ @param[in] RegName Identifies the SMM register to write.\r
+ registers are read-only.\r
+ @param[in] Value The value to write to the SMM register.\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmCpuFeaturesSetSmmRegister (\r
+ IN UINTN CpuIndex,\r
+ IN SMM_REG_NAME RegName,\r
+ IN UINT64 Value\r
+ )\r
+{\r
+}\r
+\r
+/**\r
+ Read an SMM Save State register on the target processor. If this function\r
+ returns EFI_UNSUPPORTED, then the caller is responsible for reading the\r
+ SMM Save Sate register.\r
+\r
+ @param[in] CpuIndex The index of the CPU to read the SMM Save State. The\r
+ value must be between 0 and the NumberOfCpus field in\r
+ the System Management System Table (SMST).\r
+ @param[in] Register The SMM Save State register to read.\r
+ @param[in] Width The number of bytes to read from the CPU save state.\r
+ @param[out] Buffer Upon return, this holds the CPU register value read\r
+ from the save state.\r
+\r
+ @retval EFI_SUCCESS The register was read from Save State.\r
+ @retval EFI_INVALID_PARAMTER Buffer is NULL.\r
+ @retval EFI_UNSUPPORTED This function does not support reading Register.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCpuFeaturesReadSaveStateRegister (\r
+ IN UINTN CpuIndex,\r
+ IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
+ IN UINTN Width,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Writes an SMM Save State register on the target processor. If this function\r
+ returns EFI_UNSUPPORTED, then the caller is responsible for writing the\r
+ SMM Save Sate register.\r
+\r
+ @param[in] CpuIndex The index of the CPU to write the SMM Save State. The\r
+ value must be between 0 and the NumberOfCpus field in\r
+ the System Management System Table (SMST).\r
+ @param[in] Register The SMM Save State register to write.\r
+ @param[in] Width The number of bytes to write to the CPU save state.\r
+ @param[in] Buffer Upon entry, this holds the new CPU register value.\r
+\r
+ @retval EFI_SUCCESS The register was written to Save State.\r
+ @retval EFI_INVALID_PARAMTER Buffer is NULL.\r
+ @retval EFI_UNSUPPORTED This function does not support writing Register.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCpuFeaturesWriteSaveStateRegister (\r
+ IN UINTN CpuIndex,\r
+ IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
+ IN UINTN Width,\r
+ IN CONST VOID *Buffer\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ This function is hook point called after the gEfiSmmReadyToLockProtocolGuid\r
+ notification is completely processed.\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmCpuFeaturesCompleteSmmReadyToLock (\r
+ VOID\r
+ )\r
+{\r
+}\r
+\r
+/**\r
+ This API provides a method for a CPU to allocate a specific region for storing page tables.\r
+\r
+ This API can be called more once to allocate memory for page tables.\r
+\r
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the\r
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL\r
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is\r
+ returned.\r
+\r
+ This function can also return NULL if there is no preference on where the page tables are allocated in SMRAM.\r
+\r
+ @param Pages The number of 4 KB pages to allocate.\r
+\r
+ @return A pointer to the allocated buffer for page tables.\r
+ @retval NULL Fail to allocate a specific region for storing page tables,\r
+ Or there is no preference on where the page tables are allocated in SMRAM.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+SmmCpuFeaturesAllocatePageTableMemory (\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ return NULL;\r
+}\r
--- /dev/null
+## @file\r
+# The CPU specific programming for PiSmmCpuDxeSmm module.\r
+#\r
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SmmCpuFeaturesLib\r
+ MODULE_UNI_FILE = SmmCpuFeaturesLib.uni\r
+ FILE_GUID = 34001BF4-1E93-4e08-B90E-52F2418A5026\r
+ MODULE_TYPE = DXE_SMM_DRIVER\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = SmmCpuFeaturesLib\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ UefiCpuPkg/UefiCpuPkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[Sources]\r
+ SmmCpuFeaturesLib.c\r
+\r
+[LibraryClasses]\r
+ QNCAccessLib\r
+\r
--- /dev/null
+// /** @file\r
+// The CPU specific programming for PiSmmCpuDxeSmm module.\r
+//\r
+// Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "The CPU specific programming for PiSmmCpuDxeSmm module."\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "The CPU specific programming for PiSmmCpuDxeSmm module."\r
--- /dev/null
+/** @file\r
+Framework PEIM to initialize memory on a QuarkNcSocId Memory Controller.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "MemoryInit.h"\r
+\r
+static PEI_QNC_MEMORY_INIT_PPI mPeiQNCMemoryInitPpi =\r
+{ MrcStart };\r
+\r
+static EFI_PEI_PPI_DESCRIPTOR PpiListPeiQNCMemoryInit =\r
+{\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gQNCMemoryInitPpiGuid,\r
+ &mPeiQNCMemoryInitPpi\r
+};\r
+\r
+void Mrc( MRCParams_t *MrcData);\r
+\r
+/**\r
+\r
+ Do memory initialization for QuarkNcSocId DDR3 SDRAM Controller\r
+\r
+ @param FfsHeader Not used.\r
+ @param PeiServices General purpose services available to every PEIM.\r
+\r
+ @return EFI_SUCCESS Memory initialization completed successfully.\r
+ All other error conditions encountered result in an ASSERT.\r
+\r
+ **/\r
+EFI_STATUS\r
+PeimMemoryInit(\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = (**PeiServices).InstallPpi(PeiServices, &PpiListPeiQNCMemoryInit);\r
+\r
+ return Status;\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+MrcStart(\r
+ IN OUT MRCParams_t *MrcData\r
+ )\r
+{\r
+\r
+ Mrc(MrcData);\r
+}\r
--- /dev/null
+/** @file\r
+Framework PEIM to initialize memory on an DDR2 SDRAM Memory Controller.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#ifndef _PEI_QNC_MEMORY_INIT_H_\r
+#define _PEI_QNC_MEMORY_INIT_H_\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiPei.h>\r
+#include <IntelQNCPeim.h>\r
+//\r
+// The protocols, PPI and GUID defintions for this module\r
+//\r
+#include <Ppi/QNCMemoryInit.h>\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+\r
+VOID\r
+EFIAPI\r
+MrcStart (\r
+ IN OUT MRCParams_t *MrcData\r
+ );\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# This is the Memory Initialization Driver for Quark\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+################################################################################\r
+#\r
+# Defines Section - statements that will be processed to create a Makefile.\r
+#\r
+################################################################################\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = MemoryInitPei\r
+ FILE_GUID = D2C69B26-82E1-4a1b-AD35-ED0261B9F347\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = PeimMemoryInit\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[BuildOptions]\r
+ GCC:DEBUG_*_*_CC_FLAGS = -DGCC -Wno-unused-function\r
+ GCC:RELEASE_*_*_CC_FLAGS = -DNDEBUG -DGCC -Wno-unused-function\r
+ INTEL:RELEASE_*_*_CC_FLAGS = /D NDEBUG\r
+ MSFT:RELEASE_*_*_CC_FLAGS = /D NDEBUG\r
+\r
+[Sources]\r
+ memory_options.h\r
+ platform.c\r
+ lprint.c\r
+ meminit.h\r
+ meminit.c\r
+ meminit_utils.h\r
+ meminit_utils.c\r
+ gen5_iosf_sb_definitions.h\r
+ general_definitions.h\r
+ io.h\r
+ core_types.h\r
+ prememinit.h\r
+ prememinit.c\r
+ mrc.h\r
+ mrc.c\r
+ hte.c\r
+ hte.h\r
+ MemoryInit.h\r
+ MemoryInit.c\r
+\r
+[Packages]\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+ MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+ PeimEntryPoint\r
+ DebugLib\r
+ BaseMemoryLib\r
+\r
+[Ppis]\r
+ gQNCMemoryInitPpiGuid # PPI ALWAYS_PRODUCED\r
+\r
+[Depex]\r
+ TRUE\r
--- /dev/null
+/** @file\r
+Core types used in Mrc.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#ifndef __MRC_CORE_TYPES_H\r
+#define __MRC_CORE_TYPES_H\r
+\r
+typedef char char_t;\r
+typedef unsigned char uint8_t;\r
+typedef short int16_t;\r
+typedef unsigned short uint16_t;\r
+typedef int int32_t;\r
+typedef unsigned int uint32_t;\r
+typedef unsigned char bool;\r
+typedef unsigned int size_t;\r
+\r
+#ifdef ASM_INC\r
+// Unfortunately h2inc has issue with long long\r
+typedef struct uint64_s\r
+{\r
+ uint32_t lo;\r
+ uint32_t hi;\r
+}uint64_t;\r
+#else\r
+typedef unsigned long long uint64_t;\r
+#endif\r
+\r
+#ifdef SIM\r
+// Native word length is 64bit in simulation environment\r
+typedef uint64_t uintn_t;\r
+#else\r
+// Quark is 32bit\r
+typedef uint32_t uintn_t;\r
+#endif\r
+\r
+#define PTR32(a) ((volatile uint32_t*)(uintn_t)(a))\r
+\r
+#endif\r
+\r
--- /dev/null
+/************************************************************************\r
+ *\r
+ * Copyright (c) 2013-2015 Intel Corporation.\r
+ *\r
+* This program and the accompanying materials\r
+* are licensed and made available under the terms and conditions of the BSD License\r
+* which accompanies this distribution. The full text of the license may be found at\r
+* http://opensource.org/licenses/bsd-license.php\r
+*\r
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ *\r
+ * MCU register definition\r
+ *\r
+ ************************************************************************/\r
+#ifndef __IOSF_DEFINITIONS_H\r
+#define __IOSF_DEFINITIONS_H\r
+\r
+// Define each of the IOSF-SB register offsets used by MRC.\r
+\r
+\r
+// MCU registers (DUNIT):\r
+// ====\r
+#define DRP 0x0000\r
+#define DTR0 0x0001\r
+#define DTR1 0x0002\r
+#define DTR2 0x0003\r
+#define DTR3 0x0004\r
+#define DTR4 0x0005\r
+#define DPMC0 0x0006\r
+#define DPMC1 0x0007\r
+#define DRFC 0x0008\r
+#define DSCH 0x0009\r
+#define DCAL 0x000A\r
+#define DRMC 0x000B\r
+#define PMSTS 0x000C\r
+#define DCO 0x000F\r
+#define DSTAT 0x0020\r
+#define DECCCTRL 0x0060\r
+#define DFUSESTAT 0x0070\r
+#define SCRMSEED 0x0080\r
+#define SCRMLO 0x0081\r
+#define SCRMHI 0x0082\r
+\r
+#define MCU_CH_OFFSET 0x0040\r
+#define MCU_RK_OFFSET 0x0020\r
+\r
+////\r
+//\r
+// BEGIN DUnit register definition\r
+//\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t rank0Enabled :1; /**< BIT [0] Rank 0 Enable */\r
+ uint32_t rank1Enabled :1; /**< BIT [1] Rank 1 Enable */\r
+ uint32_t reserved0 :2;\r
+ uint32_t dimm0DevWidth :2; /**< BIT [5:4] DIMM 0 Device Width (Rank0&1) */\r
+ uint32_t dimm0DevDensity :2; /**< BIT [7:6] DIMM 0 Device Density */\r
+ uint32_t reserved1 :1;\r
+ uint32_t dimm1DevWidth :2; /**< BIT [10:9] DIMM 1 Device Width (Rank2&3) */\r
+ uint32_t dimm1DevDensity :2; /**< BIT [12:11] DIMM 1 Device Density */\r
+ uint32_t split64 :1; /**< BIT [13] split 64B transactions */\r
+ uint32_t addressMap :2; /**< BIT [15:14] Address Map select */\r
+ uint32_t reserved3 :14;\r
+ uint32_t mode32 :1; /**< BIT [30] Select 32bit data interface*/\r
+ uint32_t reserved4 :1;\r
+ } field;\r
+} RegDRP; /**< DRAM Rank Population and Interface Register */\r
+#pragma pack()\r
+\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t dramFrequency :2; /**< DRAM Frequency (000=800,001=1033,010=1333) */\r
+ uint32_t reserved1 :2;\r
+ uint32_t tRP :4; /**< bit [7:4] Precharge to Activate Delay */\r
+ uint32_t tRCD :4; /**< bit [11:8] Activate to CAS Delay */\r
+ uint32_t tCL :3; /**< bit [14:12] CAS Latency */\r
+ uint32_t reserved4 :1;\r
+ uint32_t tXS :1; /**< SRX Delay */\r
+ uint32_t reserved5 :1;\r
+ uint32_t tXSDLL :1; /**< SRX To DLL Delay */\r
+ uint32_t reserved6 :1;\r
+ uint32_t tZQCS :1; /**< bit [20] ZQTS recovery Latncy */\r
+ uint32_t reserved7 :1;\r
+ uint32_t tZQCL :1; /**< bit [22] ZQCL recovery Latncy */\r
+ uint32_t reserved8 :1;\r
+ uint32_t pmeDelay :2; /**< bit [25:24] Power mode entry delay */\r
+ uint32_t reserved9 :2;\r
+ uint32_t CKEDLY :4; /**< bit [31:28] */\r
+ } field;\r
+} RegDTR0; /**< DRAM Timing Register 0 */\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t tWCL :3; /**< bit [2:0] CAS Write Latency */\r
+ uint32_t reserved1 :1;\r
+ uint32_t tCMD :2; /**< bit [5:4] Command transport duration */\r
+ uint32_t reserved2 :2;\r
+ uint32_t tWTP :4; /**< Write to Precharge */\r
+ uint32_t tCCD :2; /**< CAS to CAS delay */\r
+ uint32_t reserved4 :2;\r
+ uint32_t tFAW :4; /**< Four bank Activation Window*/\r
+ uint32_t tRAS :4; /**< Row Activation Period: */\r
+ uint32_t tRRD :2; /**<Row activation to Row activation Delay */\r
+ uint32_t reserved5 :2;\r
+ uint32_t tRTP :3; /**<Read to Precharge Delay */\r
+ uint32_t reserved6 :1;\r
+ } field;\r
+} RegDTR1; /**< DRAM Timing Register 1 */\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t tRRDR :3; /**< RD to RD from different ranks, same DIMM */\r
+ uint32_t reserved1 :5;\r
+ uint32_t tWWDR :3; /**< WR to WR from different ranks, same DIMM. */\r
+ uint32_t reserved3 :5;\r
+ uint32_t tRWDR :4; /**< bit [19:16] RD to WR from different ranks, same DIMM. */\r
+ uint32_t reserved5 :12;\r
+ } field;\r
+} RegDTR2; /**< DRAM Timing Register 2 */\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t tWRDR :3; /**< WR to RD from different ranks, same DIMM. */\r
+ uint32_t reserved1 :1;\r
+ uint32_t tWRDD :3; /**< WR to RD from different DIMM. */\r
+ uint32_t reserved2 :1;\r
+ uint32_t tRWSR :4; /**< RD to WR Same Rank. */\r
+ uint32_t reserved3 :1;\r
+ uint32_t tWRSR :4; /**< WR to RD Same Rank. */\r
+ uint32_t reserved4 :5;\r
+ uint32_t tXP :2; /**< Time from CKE set on to any command. */\r
+ uint32_t PWD_DLY :4; /**< Extended Power-Down Delay. */\r
+ uint32_t EnDeRate :1;\r
+ uint32_t DeRateOvr :1;\r
+ uint32_t DeRateStat :1;\r
+ uint32_t reserved5 :1;\r
+ } field;\r
+} RegDTR3; /**< DRAM Timing Register 3 */\r
+#pragma pack()\r
+\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t WRODTSTRT :2; /**< WR command to ODT assert delay */\r
+ uint32_t reserved1 :2;\r
+ uint32_t WRODTSTOP :3; /**< Write command to ODT de-assert delay. */\r
+ uint32_t reserved2 :1;\r
+ uint32_t RDODTSTRT :3; /**< Read command to ODT assert delay */\r
+ uint32_t reserved3 :1;\r
+ uint32_t RDODTSTOP :3; /**< Read command to ODT de-assert delay */\r
+ uint32_t ODTDIS :1; /**< ODT disable */\r
+ uint32_t TRGSTRDIS :1; /**< Write target rank is not stretched */\r
+ uint32_t RDODTDIS :1; /**< Disable Read ODT */\r
+ uint32_t WRBODTDIS :1; /**< Disable Write ODT */\r
+ uint32_t reserved5 :13;\r
+ } field;\r
+} RegDTR4; /**< DRAM Timing Register 3 */\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t SREntryDelay :8; /**< Self-Refresh Entry Delay: */\r
+ uint32_t powerModeOpCode :5; /**< SPID Power Mode Opcode */\r
+ uint32_t reserved1 :3;\r
+ uint32_t PCLSTO :3; /**< Page Close Timeout Period */\r
+ uint32_t reserved2 :1;\r
+ uint32_t PCLSWKOK :1; /**< Wake Allowed For Page Close Timeout */\r
+ uint32_t PREAPWDEN :1; /**< Send Precharge All to rank before entering Power-Down mode. */\r
+ uint32_t reserved3 :1;\r
+ uint32_t DYNSREN :1; /**< Dynamic Self-Refresh */\r
+ uint32_t CLKGTDIS :1; /**< Clock Gating Disabled*/\r
+ uint32_t DISPWRDN :1; /**< Disable Power Down*/\r
+ uint32_t reserved4 :2;\r
+ uint32_t REUTCLKGTDIS :1;\r
+ uint32_t ENPHYCLKGATE :1;\r
+ uint32_t reserved5 :2;\r
+ } field;\r
+} RegDPMC0; /**< DRAM Power Management Control Register 0 */\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t REFWMLO :4; /**< Refresh Opportunistic Watermark */\r
+ uint32_t REFWMHI :4; /**< Refresh High Watermark*/\r
+ uint32_t REFWMPNC :4; /**< Refresh Panic Watermark */\r
+ uint32_t tREFI :3; /**< bit [14:12] Refresh Period */\r
+ uint32_t reserved1 :1;\r
+ uint32_t REFCNTMAX :2; /**< Refresh Max tREFI Interval */\r
+ uint32_t reserved2 :2;\r
+ uint32_t REFSKEWDIS :1; /**< tREFI counters */\r
+ uint32_t REFDBTCLR :1;\r
+ uint32_t reserved3 :2;\r
+ uint32_t CuRefRate :3;\r
+ uint32_t DisRefBW :1;\r
+ uint32_t reserved4 :4;\r
+ } field;\r
+} RegDRCF; /**< DRAM Refresh Control Register*/\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t reserved1 :8;\r
+ uint32_t ZQCINT :3; /**< ZQ Calibration Short Interval: */\r
+ uint32_t reserved2 :1;\r
+ uint32_t SRXZQCL :2; /** < ZQ Calibration Length */\r
+ uint32_t ZQCalType :1;\r
+ uint32_t ZQCalStart :1;\r
+ uint32_t TQPollStart :1;\r
+ uint32_t TQPollRS :2;\r
+ uint32_t reserved3 :5;\r
+ uint32_t MRRData :8; /**< bit[31:24] */\r
+ } field;\r
+} RegDCAL; /**< DRAM Calibration Control*/\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t OOOAGETRH :5; /**< Out-of-Order Aging Threshold */\r
+ uint32_t reserved1 :3;\r
+ uint32_t OOODIS :1; /**< Out-of-Order Disable */\r
+ uint32_t OOOST3DIS :1; /**< Out-of-Order Disabled when RequestBD_Status is 3. */\r
+ uint32_t reserved2 :2;\r
+ uint32_t NEWBYPDIS :1;\r
+ uint32_t reserved3 :3;\r
+ uint32_t IPREQMAX :3; /** < Max In-Progress Requests stored in MC */\r
+ uint32_t reserved4 :13;\r
+ } field;\r
+} RegDSCH; /**< DRAM Scheduler Control Register */\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t DRPLOCK :1; /**< DRP lock bit */\r
+ uint32_t reserved1 :7;\r
+ uint32_t REUTLOCK :1; /**< REUT lock bit */\r
+ uint32_t reserved2 :19;\r
+ uint32_t PMICTL :1; /**< PRI Control Select: 0-memory_manager, 1-hte */\r
+ uint32_t PMIDIS :1; /**< PMIDIS Should be set is using IOSF-SB RW */\r
+ uint32_t DIOIC :1; /**< DDRIO initialization is complete */\r
+ uint32_t IC :1; /**< D-unit Initialization Complete */\r
+ } field;\r
+} RegDCO; /**< DRAM Controller Operation Register*/\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t SBEEN :1; /**< Enable Single Bit Error Detection and Correction */\r
+ uint32_t DBEEN :1; /**< Enable Double Bit Error Detection */\r
+ uint32_t CBOEN :3; /**< Enable ECC Check Bits Override */\r
+ uint32_t SYNSEL :2; /**< ECC Syndrome Bits Select for Observation */\r
+ uint32_t CLRSBECNT :1; /**< Clear ECC Single Bit Error Count */\r
+ uint32_t CBOV :8; /**< ECC Check Bits Override Value */\r
+ uint32_t reserved1 :1; /**< */\r
+ uint32_t ENCBGEN :1; /**< Enable Generation of ECC Check Bits */\r
+ uint32_t ENCBGESWIZ :1; /**< Enable Same Chip ECC Byte Lane Swizzle */\r
+\r
+ } field;\r
+} RegDECCCTRL; /**< DRAM ECC Control Register */\r
+#pragma pack()\r
+\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t FUS_DUN_ECC_DIS :1;\r
+ uint32_t FUS_DUN_MAX_SUPPORTED_MEMORY :3;\r
+ uint32_t FUS_DUN_MAX_DEVDEN :2;\r
+ uint32_t RESERVED1 :1;\r
+ uint32_t FUS_DUN_RANK2_DIS :1;\r
+ uint32_t FUS_DUN_OOO_DIS :1;\r
+ uint32_t FUS_DUN_MEMX8_DIS :1;\r
+ uint32_t FUS_DUN_MEMX16_DIS :1;\r
+ uint32_t RESERVED2 :1;\r
+ uint32_t FUS_DUN_1N_DIS :1;\r
+ uint32_t FUS_DUN_DQ_SCRAMBLER_DIS :1;\r
+ uint32_t RESERVED3 :1;\r
+ uint32_t FUS_DUN_32BIT_DRAM_IFC :1;\r
+ } field;\r
+} RegDFUSESTAT;\r
+#pragma pack()\r
+\r
+//\r
+// END DUnit register definition\r
+//\r
+////\r
+\r
+\r
+\r
+////\r
+//\r
+// DRAM Initialization Structures used in JEDEC Message Bus Commands\r
+//\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ unsigned command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */\r
+ unsigned bankAddress :3; /**< Bank Address (BA[2:0]) */\r
+ unsigned BL :2; /**< Burst Length, CDV:1*/\r
+ unsigned CL :1; /**< CL Reserved CDV:0 */\r
+ unsigned RBT :1; /**< Read Burst Type */\r
+ unsigned casLatency :3; /**< cas Latency */\r
+ unsigned TM :1; /**< Test mode */\r
+ unsigned dllReset :1; /**< DLL Reset */\r
+ unsigned writeRecovery :3; /**< Write Recovery for Auto Pre-Charge: 001=2,010=3,011=4,100=5,101=6 */\r
+ unsigned PPD :1; /**< DLL Control for Precharge Power-Down CDV:1 */\r
+ unsigned reserved1 :3;\r
+ unsigned rankSelect :4; /**< Rank Select */\r
+ unsigned reserved2 :6;\r
+ } field;\r
+} DramInitDDR3MRS0; /**< DDR3 Mode Register Set (MRS) Command */\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ unsigned command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */\r
+ unsigned bankAddress :3; /**< Bank Address (BA[2:0]) */\r
+ unsigned dllEnabled :1; /**< CDV=0 */\r
+ unsigned DIC0 :1; /**< Output Driver Impedance Control */\r
+ unsigned rttNom0 :1; /**< RTT_nom[0] */\r
+ unsigned MRC_AL :2; /**< Additive Latency = 0 */\r
+ unsigned DIC1 :1; /**< Reserved */\r
+ unsigned rttNom1 :1; /**< RTT_nom[1] */\r
+ unsigned wlEnabled :1; /**< Write Leveling Enable */\r
+ unsigned reserved1 :1;\r
+ unsigned rttNom2 :1; /** < RTT_nom[2] */\r
+ unsigned reserved2 :1;\r
+ unsigned TDQS :1; /**< TDQS Enable */\r
+ unsigned Qoff :1; /**< Output Buffers Disabled */\r
+ unsigned reserved3 :3;\r
+ unsigned rankSelect :4; /**< Rank Select */\r
+ unsigned reserved4 :6;\r
+ } field;\r
+} DramInitDDR3EMR1; /**< DDR3 Extended Mode Register 1 Set (EMRS1) Command */\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */\r
+ uint32_t bankAddress :3; /**< Bank Address (BA[2:0]) */\r
+ uint32_t PASR :3; /**< Partial Array Self-Refresh */\r
+ uint32_t CWL :3; /**< CAS Write Latency */\r
+ uint32_t ASR :1; /**< Auto Self-Refresh */\r
+ uint32_t SRT :1; /**< SR Temperature Range = 0*/\r
+ uint32_t reserved1 :1;\r
+ uint32_t rtt_WR :2; /**< Rtt_WR */\r
+ uint32_t reserved2 :5;\r
+ uint32_t rankSelect :4; /**< Rank Select */\r
+ uint32_t reserved3 :6;\r
+ } field;\r
+} DramInitDDR3EMR2; /**< DDR3 Extended Mode Register 2 Set (EMRS2) Command */\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */\r
+ uint32_t bankAddress :3; /**< Bank Address (BA[2:0]) */\r
+ uint32_t MPR_Location :2; /**< MPR Location */\r
+ uint32_t MPR :1; /**< MPR: Multi Purpose Register */\r
+ uint32_t reserved1 :13;\r
+ uint32_t rankSelect :4; /**< Rank Select */\r
+ uint32_t reserved2 :6;\r
+ } field;\r
+} DramInitDDR3EMR3; /**< DDR3 Extended Mode Register 2 Set (EMRS2) Command */\r
+#pragma pack()\r
+\r
+#pragma pack(1)\r
+typedef union {\r
+ uint32_t raw;\r
+ struct {\r
+ uint32_t command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110 - ZQ Calibration,111-NOP */\r
+ uint32_t bankAddress :3; /**< Bank Address (BA[2:0]) */\r
+ uint32_t multAddress :16; /**< Multiplexed Address (MA[14:0]) */\r
+ uint32_t rankSelect :2; /**< Rank Select */\r
+ uint32_t reserved3 :8;\r
+ } field;\r
+} DramInitMisc; /**< Miscellaneous DDRx Initialization Command */\r
+#pragma pack()\r
+\r
+//\r
+// Construct DRAM init command using DramInitXxxx pattern\r
+//\r
+#define DCMD_MRS1(rnk,dat) (0 | ((rnk)<<22) | (1<<3) | ((dat)<<6))\r
+#define DCMD_REF(rnk) (1 | ((rnk)<<22))\r
+#define DCMD_PRE(rnk) (2 | ((rnk)<<22))\r
+#define DCMD_PREA(rnk) (2 | ((rnk)<<22) | (BIT10<<6))\r
+#define DCMD_ACT(rnk,row) (3 | ((rnk)<<22) | ((row)<<6))\r
+#define DCMD_WR(rnk,col) (4 | ((rnk)<<22) | ((col)<<6))\r
+#define DCMD_RD(rnk,col) (5 | ((rnk)<<22) | ((col)<<6))\r
+#define DCMD_ZQCS(rnk) (6 | ((rnk)<<22))\r
+#define DCMD_ZQCL(rnk) (6 | ((rnk)<<22) | (BIT10<<6))\r
+#define DCMD_NOP(rnk) (7 | ((rnk)<<22))\r
+\r
+\r
+\r
+\r
+#define DDR3_EMRS1_DIC_40 (0)\r
+#define DDR3_EMRS1_DIC_34 (1)\r
+\r
+#define DDR3_EMRS2_RTTWR_60 (BIT9)\r
+#define DDR3_EMRS2_RTTWR_120 (BIT10)\r
+\r
+#define DDR3_EMRS1_RTTNOM_0 (0)\r
+#define DDR3_EMRS1_RTTNOM_60 (BIT2)\r
+#define DDR3_EMRS1_RTTNOM_120 (BIT6)\r
+#define DDR3_EMRS1_RTTNOM_40 (BIT6|BIT2)\r
+#define DDR3_EMRS1_RTTNOM_20 (BIT9)\r
+#define DDR3_EMRS1_RTTNOM_30 (BIT9|BIT2)\r
+\r
+\r
+//\r
+// END DRAM Init...\r
+//\r
+////\r
+\r
+\r
+// HOST_BRIDGE registers:\r
+#define HMBOUND 0x0020 //ok\r
+\r
+// MEMORY_MANAGER registers:\r
+#define BCTRL 0x0004\r
+#define BWFLUSH 0x0008\r
+#define BDEBUG1 0x00C4\r
+\r
+////\r
+//\r
+// BEGIN DDRIO registers\r
+//\r
+\r
+// DDR IOs & COMPs:\r
+#define DDRIODQ_BL_OFFSET 0x0800\r
+#define DDRIODQ_CH_OFFSET ((NUM_BYTE_LANES/2) * DDRIODQ_BL_OFFSET)\r
+#define DDRIOCCC_CH_OFFSET 0x0800\r
+#define DDRCOMP_CH_OFFSET 0x0100\r
+\r
+// CH0-BL01-DQ\r
+#define DQOBSCKEBBCTL 0x0000\r
+#define DQDLLTXCTL 0x0004\r
+#define DQDLLRXCTL 0x0008\r
+#define DQMDLLCTL 0x000C\r
+#define B0RXIOBUFCTL 0x0010\r
+#define B0VREFCTL 0x0014\r
+#define B0RXOFFSET1 0x0018\r
+#define B0RXOFFSET0 0x001C\r
+#define B1RXIOBUFCTL 0x0020\r
+#define B1VREFCTL 0x0024\r
+#define B1RXOFFSET1 0x0028\r
+#define B1RXOFFSET0 0x002C\r
+#define DQDFTCTL 0x0030\r
+#define DQTRAINSTS 0x0034\r
+#define B1DLLPICODER0 0x0038\r
+#define B0DLLPICODER0 0x003C\r
+#define B1DLLPICODER1 0x0040\r
+#define B0DLLPICODER1 0x0044\r
+#define B1DLLPICODER2 0x0048\r
+#define B0DLLPICODER2 0x004C\r
+#define B1DLLPICODER3 0x0050\r
+#define B0DLLPICODER3 0x0054\r
+#define B1RXDQSPICODE 0x0058\r
+#define B0RXDQSPICODE 0x005C\r
+#define B1RXDQPICODER32 0x0060\r
+#define B1RXDQPICODER10 0x0064\r
+#define B0RXDQPICODER32 0x0068\r
+#define B0RXDQPICODER10 0x006C\r
+#define B01PTRCTL0 0x0070\r
+#define B01PTRCTL1 0x0074\r
+#define B01DBCTL0 0x0078\r
+#define B01DBCTL1 0x007C\r
+#define B0LATCTL0 0x0080\r
+#define B1LATCTL0 0x0084\r
+#define B01LATCTL1 0x0088\r
+#define B0ONDURCTL 0x008C\r
+#define B1ONDURCTL 0x0090\r
+#define B0OVRCTL 0x0094\r
+#define B1OVRCTL 0x0098\r
+#define DQCTL 0x009C\r
+#define B0RK2RKCHGPTRCTRL 0x00A0\r
+#define B1RK2RKCHGPTRCTRL 0x00A4\r
+#define DQRK2RKCTL 0x00A8\r
+#define DQRK2RKPTRCTL 0x00AC\r
+#define B0RK2RKLAT 0x00B0\r
+#define B1RK2RKLAT 0x00B4\r
+#define DQCLKALIGNREG0 0x00B8\r
+#define DQCLKALIGNREG1 0x00BC\r
+#define DQCLKALIGNREG2 0x00C0\r
+#define DQCLKALIGNSTS0 0x00C4\r
+#define DQCLKALIGNSTS1 0x00C8\r
+#define DQCLKGATE 0x00CC\r
+#define B0COMPSLV1 0x00D0\r
+#define B1COMPSLV1 0x00D4\r
+#define B0COMPSLV2 0x00D8\r
+#define B1COMPSLV2 0x00DC\r
+#define B0COMPSLV3 0x00E0\r
+#define B1COMPSLV3 0x00E4\r
+#define DQVISALANECR0TOP 0x00E8\r
+#define DQVISALANECR1TOP 0x00EC\r
+#define DQVISACONTROLCRTOP 0x00F0\r
+#define DQVISALANECR0BL 0x00F4\r
+#define DQVISALANECR1BL 0x00F8\r
+#define DQVISACONTROLCRBL 0x00FC\r
+#define DQTIMINGCTRL 0x010C\r
+// CH0-ECC\r
+#define ECCDLLTXCTL 0x2004\r
+#define ECCDLLRXCTL 0x2008\r
+#define ECCMDLLCTL 0x200C\r
+#define ECCB1DLLPICODER0 0x2038\r
+#define ECCB1DLLPICODER1 0x2040\r
+#define ECCB1DLLPICODER2 0x2048\r
+#define ECCB1DLLPICODER3 0x2050\r
+#define ECCB01DBCTL0 0x2078\r
+#define ECCB01DBCTL1 0x207C\r
+#define ECCCLKALIGNREG0 0x20B8\r
+#define ECCCLKALIGNREG1 0x20BC\r
+#define ECCCLKALIGNREG2 0x20C0\r
+// CH0-CMD\r
+#define CMDOBSCKEBBCTL 0x4800\r
+#define CMDDLLTXCTL 0x4808\r
+#define CMDDLLRXCTL 0x480C\r
+#define CMDMDLLCTL 0x4810\r
+#define CMDRCOMPODT 0x4814\r
+#define CMDDLLPICODER0 0x4820\r
+#define CMDDLLPICODER1 0x4824\r
+#define CMDCFGREG0 0x4840\r
+#define CMDPTRREG 0x4844\r
+#define CMDCLKALIGNREG0 0x4850\r
+#define CMDCLKALIGNREG1 0x4854\r
+#define CMDCLKALIGNREG2 0x4858\r
+#define CMDPMCONFIG0 0x485C\r
+#define CMDPMDLYREG0 0x4860\r
+#define CMDPMDLYREG1 0x4864\r
+#define CMDPMDLYREG2 0x4868\r
+#define CMDPMDLYREG3 0x486C\r
+#define CMDPMDLYREG4 0x4870\r
+#define CMDCLKALIGNSTS0 0x4874\r
+#define CMDCLKALIGNSTS1 0x4878\r
+#define CMDPMSTS0 0x487C\r
+#define CMDPMSTS1 0x4880\r
+#define CMDCOMPSLV 0x4884\r
+#define CMDBONUS0 0x488C\r
+#define CMDBONUS1 0x4890\r
+#define CMDVISALANECR0 0x4894\r
+#define CMDVISALANECR1 0x4898\r
+#define CMDVISACONTROLCR 0x489C\r
+#define CMDCLKGATE 0x48A0\r
+#define CMDTIMINGCTRL 0x48A4\r
+// CH0-CLK-CTL\r
+#define CCOBSCKEBBCTL 0x5800\r
+#define CCRCOMPIO 0x5804\r
+#define CCDLLTXCTL 0x5808\r
+#define CCDLLRXCTL 0x580C\r
+#define CCMDLLCTL 0x5810\r
+#define CCRCOMPODT 0x5814\r
+#define CCDLLPICODER0 0x5820\r
+#define CCDLLPICODER1 0x5824\r
+#define CCDDR3RESETCTL 0x5830\r
+#define CCCFGREG0 0x5838\r
+#define CCCFGREG1 0x5840\r
+#define CCPTRREG 0x5844\r
+#define CCCLKALIGNREG0 0x5850\r
+#define CCCLKALIGNREG1 0x5854\r
+#define CCCLKALIGNREG2 0x5858\r
+#define CCPMCONFIG0 0x585C\r
+#define CCPMDLYREG0 0x5860\r
+#define CCPMDLYREG1 0x5864\r
+#define CCPMDLYREG2 0x5868\r
+#define CCPMDLYREG3 0x586C\r
+#define CCPMDLYREG4 0x5870\r
+#define CCCLKALIGNSTS0 0x5874\r
+#define CCCLKALIGNSTS1 0x5878\r
+#define CCPMSTS0 0x587C\r
+#define CCPMSTS1 0x5880\r
+#define CCCOMPSLV1 0x5884\r
+#define CCCOMPSLV2 0x5888\r
+#define CCCOMPSLV3 0x588C\r
+#define CCBONUS0 0x5894\r
+#define CCBONUS1 0x5898\r
+#define CCVISALANECR0 0x589C\r
+#define CCVISALANECR1 0x58A0\r
+#define CCVISACONTROLCR 0x58A4\r
+#define CCCLKGATE 0x58A8\r
+#define CCTIMINGCTL 0x58AC\r
+// COMP\r
+#define CMPCTRL 0x6800\r
+#define SOFTRSTCNTL 0x6804\r
+#define MSCNTR 0x6808\r
+#define NMSCNTRL 0x680C\r
+#define LATCH1CTL 0x6814\r
+#define COMPVISALANECR0 0x681C\r
+#define COMPVISALANECR1 0x6820\r
+#define COMPVISACONTROLCR 0x6824\r
+#define COMPBONUS0 0x6830\r
+#define TCOCNTCTRL 0x683C\r
+#define DQANAODTPUCTL 0x6840\r
+#define DQANAODTPDCTL 0x6844\r
+#define DQANADRVPUCTL 0x6848\r
+#define DQANADRVPDCTL 0x684C\r
+#define DQANADLYPUCTL 0x6850\r
+#define DQANADLYPDCTL 0x6854\r
+#define DQANATCOPUCTL 0x6858\r
+#define DQANATCOPDCTL 0x685C\r
+#define CMDANADRVPUCTL 0x6868\r
+#define CMDANADRVPDCTL 0x686C\r
+#define CMDANADLYPUCTL 0x6870\r
+#define CMDANADLYPDCTL 0x6874\r
+#define CLKANAODTPUCTL 0x6880\r
+#define CLKANAODTPDCTL 0x6884\r
+#define CLKANADRVPUCTL 0x6888\r
+#define CLKANADRVPDCTL 0x688C\r
+#define CLKANADLYPUCTL 0x6890\r
+#define CLKANADLYPDCTL 0x6894\r
+#define CLKANATCOPUCTL 0x6898\r
+#define CLKANATCOPDCTL 0x689C\r
+#define DQSANAODTPUCTL 0x68A0\r
+#define DQSANAODTPDCTL 0x68A4\r
+#define DQSANADRVPUCTL 0x68A8\r
+#define DQSANADRVPDCTL 0x68AC\r
+#define DQSANADLYPUCTL 0x68B0\r
+#define DQSANADLYPDCTL 0x68B4\r
+#define DQSANATCOPUCTL 0x68B8\r
+#define DQSANATCOPDCTL 0x68BC\r
+#define CTLANADRVPUCTL 0x68C8\r
+#define CTLANADRVPDCTL 0x68CC\r
+#define CTLANADLYPUCTL 0x68D0\r
+#define CTLANADLYPDCTL 0x68D4\r
+#define CHNLBUFSTATIC 0x68F0\r
+#define COMPOBSCNTRL 0x68F4\r
+#define COMPBUFFDBG0 0x68F8\r
+#define COMPBUFFDBG1 0x68FC\r
+#define CFGMISCCH0 0x6900\r
+#define COMPEN0CH0 0x6904\r
+#define COMPEN1CH0 0x6908\r
+#define COMPEN2CH0 0x690C\r
+#define STATLEGEN0CH0 0x6910\r
+#define STATLEGEN1CH0 0x6914\r
+#define DQVREFCH0 0x6918\r
+#define CMDVREFCH0 0x691C\r
+#define CLKVREFCH0 0x6920\r
+#define DQSVREFCH0 0x6924\r
+#define CTLVREFCH0 0x6928\r
+#define TCOVREFCH0 0x692C\r
+#define DLYSELCH0 0x6930\r
+#define TCODRAMBUFODTCH0 0x6934\r
+#define CCBUFODTCH0 0x6938\r
+#define RXOFFSETCH0 0x693C\r
+#define DQODTPUCTLCH0 0x6940\r
+#define DQODTPDCTLCH0 0x6944\r
+#define DQDRVPUCTLCH0 0x6948\r
+#define DQDRVPDCTLCH0 0x694C\r
+#define DQDLYPUCTLCH0 0x6950\r
+#define DQDLYPDCTLCH0 0x6954\r
+#define DQTCOPUCTLCH0 0x6958\r
+#define DQTCOPDCTLCH0 0x695C\r
+#define CMDDRVPUCTLCH0 0x6968\r
+#define CMDDRVPDCTLCH0 0x696C\r
+#define CMDDLYPUCTLCH0 0x6970\r
+#define CMDDLYPDCTLCH0 0x6974\r
+#define CLKODTPUCTLCH0 0x6980\r
+#define CLKODTPDCTLCH0 0x6984\r
+#define CLKDRVPUCTLCH0 0x6988\r
+#define CLKDRVPDCTLCH0 0x698C\r
+#define CLKDLYPUCTLCH0 0x6990\r
+#define CLKDLYPDCTLCH0 0x6994\r
+#define CLKTCOPUCTLCH0 0x6998\r
+#define CLKTCOPDCTLCH0 0x699C\r
+#define DQSODTPUCTLCH0 0x69A0\r
+#define DQSODTPDCTLCH0 0x69A4\r
+#define DQSDRVPUCTLCH0 0x69A8\r
+#define DQSDRVPDCTLCH0 0x69AC\r
+#define DQSDLYPUCTLCH0 0x69B0\r
+#define DQSDLYPDCTLCH0 0x69B4\r
+#define DQSTCOPUCTLCH0 0x69B8\r
+#define DQSTCOPDCTLCH0 0x69BC\r
+#define CTLDRVPUCTLCH0 0x69C8\r
+#define CTLDRVPDCTLCH0 0x69CC\r
+#define CTLDLYPUCTLCH0 0x69D0\r
+#define CTLDLYPDCTLCH0 0x69D4\r
+#define FNLUPDTCTLCH0 0x69F0\r
+// PLL\r
+#define MPLLCTRL0 0x7800\r
+#define MPLLCTRL1 0x7808\r
+#define MPLLCSR0 0x7810\r
+#define MPLLCSR1 0x7814\r
+#define MPLLCSR2 0x7820\r
+#define MPLLDFT 0x7828\r
+#define MPLLMON0CTL 0x7830\r
+#define MPLLMON1CTL 0x7838\r
+#define MPLLMON2CTL 0x783C\r
+#define SFRTRIM 0x7850\r
+#define MPLLDFTOUT0 0x7858\r
+#define MPLLDFTOUT1 0x785C\r
+#define MASTERRSTN 0x7880\r
+#define PLLLOCKDEL 0x7884\r
+#define SFRDEL 0x7888\r
+#define CRUVISALANECR0 0x78F0\r
+#define CRUVISALANECR1 0x78F4\r
+#define CRUVISACONTROLCR 0x78F8\r
+#define IOSFVISALANECR0 0x78FC\r
+#define IOSFVISALANECR1 0x7900\r
+#define IOSFVISACONTROLCR 0x7904\r
+\r
+//\r
+// END DDRIO registers\r
+//\r
+////\r
+\r
+\r
+#endif\r
--- /dev/null
+/************************************************************************\r
+ *\r
+ * Copyright (c) 2013-2015 Intel Corporation.\r
+ *\r
+* This program and the accompanying materials\r
+* are licensed and made available under the terms and conditions of the BSD License\r
+* which accompanies this distribution. The full text of the license may be found at\r
+* http://opensource.org/licenses/bsd-license.php\r
+*\r
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ *\r
+ ************************************************************************/\r
+#ifndef __GENERAL_DEFINITIONS_H\r
+#define __GENERAL_DEFINITIONS_H\r
+\r
+#undef BIT0\r
+#undef BIT1\r
+#undef BIT2\r
+#undef BIT3\r
+#undef BIT4\r
+#undef BIT5\r
+#undef BIT6\r
+#undef BIT7\r
+#undef BIT8\r
+#undef BIT9\r
+#undef BIT10\r
+#undef BIT11\r
+#undef BIT12\r
+#undef BIT13\r
+#undef BIT14\r
+#undef BIT15\r
+#undef BIT16\r
+#undef BIT17\r
+#undef BIT18\r
+#undef BIT19\r
+#undef BIT20\r
+#undef BIT21\r
+#undef BIT22\r
+#undef BIT23\r
+#undef BIT24\r
+#undef BIT25\r
+#undef BIT26\r
+#undef BIT27\r
+#undef BIT28\r
+#undef BIT29\r
+#undef BIT30\r
+#undef BIT31\r
+\r
+\r
+\r
+// defines\r
+#define BIT0 0x00000001U\r
+#define BIT1 0x00000002U\r
+#define BIT2 0x00000004U\r
+#define BIT3 0x00000008U\r
+#define BIT4 0x00000010U\r
+#define BIT5 0x00000020U\r
+#define BIT6 0x00000040U\r
+#define BIT7 0x00000080U\r
+#define BIT8 0x00000100U\r
+#define BIT9 0x00000200U\r
+#define BIT10 0x00000400U\r
+#define BIT11 0x00000800U\r
+#define BIT12 0x00001000U\r
+#define BIT13 0x00002000U\r
+#define BIT14 0x00004000U\r
+#define BIT15 0x00008000U\r
+#define BIT16 0x00010000U\r
+#define BIT17 0x00020000U\r
+#define BIT18 0x00040000U\r
+#define BIT19 0x00080000U\r
+#define BIT20 0x00100000U\r
+#define BIT21 0x00200000U\r
+#define BIT22 0x00400000U\r
+#define BIT23 0x00800000U\r
+#define BIT24 0x01000000U\r
+#define BIT25 0x02000000U\r
+#define BIT26 0x04000000U\r
+#define BIT27 0x08000000U\r
+#define BIT28 0x10000000U\r
+#define BIT29 0x20000000U\r
+#define BIT30 0x40000000U\r
+#define BIT31 0x80000000U\r
+\r
+\r
+#define true 0x01\r
+#define false 0x00\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+HTE handling routines for MRC use.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "mrc.h"\r
+#include "memory_options.h"\r
+#include "io.h"\r
+\r
+#include "hte.h"\r
+\r
+\r
+#ifdef SIM\r
+VOID delay_n(UINT32 nanoseconds);\r
+#define MySimStall(a) delay_n(a/1000)\r
+#endif\r
+\r
+STATIC VOID EnableAllHteErrors(\r
+ UINT8 Mask)\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ This function enables to HTE to detect all possible errors for\r
+ the given training parameters (per-bit or full byte lane).\r
+\r
+ Returns:\r
+\r
+ None\r
+\r
+ --*/\r
+{\r
+ isbW32m(HTE, 0x000200A2, 0xFFFFFFFF);\r
+ isbW32m(HTE, 0x000200A3, 0x000000FF);\r
+ isbW32m(HTE, 0x000200A4, 0x00000000);\r
+}\r
+\r
+STATIC UINT32 CheckHteErrors(\r
+ VOID)\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ This function goes and reads the HTE register in order to find any error\r
+\r
+ Returns:\r
+\r
+ The errors detected in the HTE status register\r
+\r
+ --*/\r
+{\r
+ return isbR32m(HTE, 0x000200A7);\r
+}\r
+\r
+STATIC VOID WaitForHteComplete(\r
+ VOID)\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ This function waits until HTE finishes\r
+\r
+ Returns:\r
+\r
+ None\r
+\r
+ --*/\r
+{\r
+ UINT32 Tmp;\r
+\r
+ ENTERFN();\r
+\r
+ //\r
+ // Is the test done?\r
+ //\r
+ do\r
+ {\r
+#ifdef SIM\r
+ MySimStall (35000); // 35 ns delay\r
+#endif\r
+ } while (0 != (isbR32m(HTE, 0x00020012) & BIT30));\r
+\r
+ Tmp = isbR32m(HTE, 0x00020011);\r
+ Tmp = Tmp | BIT9;\r
+ Tmp = Tmp & ~(BIT13 | BIT12);\r
+ isbW32m(HTE, 0x00020011, Tmp);\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+STATIC VOID ClearHteErrorRegisters(\r
+ VOID)\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Clears registers related with errors in the HTE.\r
+\r
+ Returns:\r
+\r
+ None\r
+\r
+ --*/\r
+{\r
+ UINT32 Tmp;\r
+\r
+ //\r
+ // Clear all HTE errors and enable error checking\r
+ // for burst and chunk.\r
+ //\r
+ Tmp = isbR32m(HTE, 0x000200A1);\r
+ Tmp |= BIT8;\r
+ isbW32m(HTE, 0x000200A1, Tmp);\r
+}\r
+\r
+UINT32 HteMemInit(\r
+ MRC_PARAMS *CurrentMrcData,\r
+ UINT8 MemInitFlag,\r
+ UINT8 HaltHteEngineOnError)\r
+\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Uses HW HTE engine to initialize or test all memory attached to a given DUNIT.\r
+ If MemInitFlag is 1, this routine writes 0s to all memory locations to initialize\r
+ ECC.\r
+ If MemInitFlag is 0, this routine will send an 5AA55AA5 pattern to all memory\r
+ locations on the RankMask and then read it back. Then it sends an A55AA55A\r
+ pattern to all memory locations on the RankMask and reads it back.\r
+\r
+ Arguments:\r
+\r
+ CurrentMrcData: Host struture for all MRC global data.\r
+ MemInitFlag: 0 for memtest, 1 for meminit.\r
+ HaltHteEngineOnError: Halt the HTE engine on first error observed, or keep\r
+ running to see how many errors are found.\r
+\r
+ Returns:\r
+ Errors register showing HTE failures.\r
+ Also prints out which rank failed the HTE test if failure occurs.\r
+ For rank detection to work, the address map must be left in its default\r
+ state. If MRC changes the address map, this function must be modified\r
+ to change it back to default at the beginning, then restore it at the end.\r
+\r
+ --*/\r
+{\r
+ UINT32 Offset;\r
+ UINT8 TestNum;\r
+ UINT8 i;\r
+\r
+ //\r
+ // Clear out the error registers at the start of each memory\r
+ // init or memory test run.\r
+ //\r
+ ClearHteErrorRegisters();\r
+\r
+ isbW32m(HTE, 0x00020062, 0x00000015);\r
+\r
+ for (Offset = 0x80; Offset <= 0x8F; Offset++)\r
+ {\r
+ isbW32m(HTE, Offset, ((Offset & 1) ? 0xA55A : 0x5AA5));\r
+ }\r
+\r
+ isbW32m(HTE, 0x00020021, 0x00000000);\r
+#ifdef QUICKSIM\r
+ // Just do 4 cache lines for simulation memtest to save time.\r
+ isbW32m(HTE, 0x00020022, 4-1);\r
+#else\r
+ isbW32m(HTE, 0x00020022, (CurrentMrcData->mem_size >> 6) - 1);\r
+#endif\r
+\r
+ isbW32m(HTE, 0x00020063, 0xAAAAAAAA);\r
+ isbW32m(HTE, 0x00020064, 0xCCCCCCCC);\r
+ isbW32m(HTE, 0x00020065, 0xF0F0F0F0);\r
+ isbW32m(HTE, 0x00020066, 0x03000000);\r
+\r
+ switch (MemInitFlag)\r
+ {\r
+ case MrcMemInit:\r
+ TestNum = 1; // Only 1 write pass through memory is needed to initialize ECC.\r
+ break;\r
+ case MrcMemTest:\r
+ TestNum = 4; // Write/read then write/read with inverted pattern.\r
+ break;\r
+ default:\r
+ DPF(D_INFO, "Unknown parameter for MemInitFlag: %d\n", MemInitFlag);\r
+ return 0xFFFFFFFF;\r
+ break;\r
+ }\r
+\r
+ DPF(D_INFO, "HteMemInit");\r
+ for (i = 0; i < TestNum; i++)\r
+ {\r
+ DPF(D_INFO, ".");\r
+\r
+ if (i == 0)\r
+ {\r
+ isbW32m(HTE, 0x00020061, 0x00000000);\r
+ isbW32m(HTE, 0x00020020, 0x00110010);\r
+ }\r
+ else if (i == 1)\r
+ {\r
+ isbW32m(HTE, 0x00020061, 0x00000000);\r
+ isbW32m(HTE, 0x00020020, 0x00010010);\r
+ }\r
+ else if (i == 2)\r
+ {\r
+ isbW32m(HTE, 0x00020061, 0x00010100);\r
+ isbW32m(HTE, 0x00020020, 0x00110010);\r
+ }\r
+ else\r
+ {\r
+ isbW32m(HTE, 0x00020061, 0x00010100);\r
+ isbW32m(HTE, 0x00020020, 0x00010010);\r
+ }\r
+\r
+ isbW32m(HTE, 0x00020011, 0x00111000);\r
+ isbW32m(HTE, 0x00020011, 0x00111100);\r
+\r
+ WaitForHteComplete();\r
+\r
+ //\r
+ // If this is a READ pass, check for errors at the end.\r
+ //\r
+ if ((i % 2) == 1)\r
+ {\r
+ //\r
+ // Return immediately if error.\r
+ //\r
+ if (CheckHteErrors())\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ DPF(D_INFO, "done\n", i);\r
+ return CheckHteErrors();\r
+}\r
+\r
+STATIC UINT16 BasicDataCompareHte(\r
+ MRC_PARAMS *CurrentMrcData,\r
+ UINT32 Address,\r
+ UINT8 FirstRun,\r
+ UINT8 Mode)\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Execute basic single cache line memory write/read/verify test using simple constant\r
+ pattern (different for READ_RAIN and WRITE_TRAIN modes.\r
+ See BasicWriteReadHTE which is external visible wrapper.\r
+\r
+ Arguments:\r
+\r
+ CurrentMrcData: Host struture for all MRC global data.\r
+ Address: memory adress being tested (must hit specific channel/rank)\r
+ FirstRun: If set then hte registers are configured, otherwise\r
+ it is assumed configuration is done and just re-run the test.\r
+ Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)\r
+\r
+ Returns:\r
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)\r
+\r
+ --*/\r
+{\r
+ UINT32 Pattern;\r
+ UINT32 Offset;\r
+\r
+ if (FirstRun)\r
+ {\r
+ isbW32m(HTE, 0x00020020, 0x01B10021);\r
+ isbW32m(HTE, 0x00020021, 0x06000000);\r
+ isbW32m(HTE, 0x00020022, Address >> 6);\r
+ isbW32m(HTE, 0x00020062, 0x00800015);\r
+ isbW32m(HTE, 0x00020063, 0xAAAAAAAA);\r
+ isbW32m(HTE, 0x00020064, 0xCCCCCCCC);\r
+ isbW32m(HTE, 0x00020065, 0xF0F0F0F0);\r
+ isbW32m(HTE, 0x00020061, 0x00030008);\r
+\r
+ if (Mode == WRITE_TRAIN)\r
+ {\r
+ Pattern = 0xC33C0000;\r
+ }\r
+ else // READ_TRAIN\r
+ {\r
+ Pattern = 0xAA5555AA;\r
+ }\r
+\r
+ for (Offset = 0x80; Offset <= 0x8F; Offset++)\r
+ {\r
+ isbW32m(HTE, Offset, Pattern);\r
+ }\r
+ }\r
+\r
+ isbW32m(HTE, 0x000200A1, 0xFFFF1000);\r
+\r
+ isbW32m(HTE, 0x00020011, 0x00011000);\r
+ isbW32m(HTE, 0x00020011, 0x00011100);\r
+\r
+ WaitForHteComplete();\r
+\r
+ //\r
+ // Return bits 15:8 of HTE_CH0_ERR_XSTAT to check for any bytelane errors.\r
+ //\r
+ return ((CheckHteErrors() >> 8) & 0xFF);\r
+}\r
+\r
+STATIC UINT16 ReadWriteDataCompareHte(\r
+ MRC_PARAMS *CurrentMrcData,\r
+ UINT32 Address,\r
+ UINT8 LoopCount,\r
+ UINT32 LfsrSeedVictim,\r
+ UINT32 LfsrSeedAggressor,\r
+ UINT8 VictimBit,\r
+ UINT8 FirstRun)\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Examines single cache line memory with write/read/verify test using\r
+ multiple data patterns (victim-aggressor algorithm).\r
+ See WriteStressBitLanesHTE which is external visible wrapper.\r
+\r
+ Arguments:\r
+\r
+ CurrentMrcData: host struture for all MRC global data.\r
+ Address: memory adress being tested (must hit specific channel/rank)\r
+ LoopCount: number of test iterations\r
+ LfsrSeedXxx: victim aggressor data pattern seed\r
+ VictimBit: should be 0 as auto rotate feature is in use.\r
+ FirstRun: If set then hte registers are configured, otherwise\r
+ it is assumed configuration is done and just re-run the test.\r
+\r
+ Returns:\r
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)\r
+\r
+ --*/\r
+{\r
+ UINT32 Offset;\r
+ UINT32 Tmp;\r
+\r
+ if (FirstRun)\r
+ {\r
+ isbW32m(HTE, 0x00020020, 0x00910024);\r
+ isbW32m(HTE, 0x00020023, 0x00810024);\r
+ isbW32m(HTE, 0x00020021, 0x06070000);\r
+ isbW32m(HTE, 0x00020024, 0x06070000);\r
+ isbW32m(HTE, 0x00020022, Address >> 6);\r
+ isbW32m(HTE, 0x00020025, Address >> 6);\r
+ isbW32m(HTE, 0x00020062, 0x0000002A);\r
+ isbW32m(HTE, 0x00020063, LfsrSeedVictim);\r
+ isbW32m(HTE, 0x00020064, LfsrSeedAggressor);\r
+ isbW32m(HTE, 0x00020065, LfsrSeedVictim);\r
+\r
+ //\r
+ // Write the pattern buffers to select the victim bit. Start with bit0.\r
+ //\r
+ for (Offset = 0x80; Offset <= 0x8F; Offset++)\r
+ {\r
+ if ((Offset % 8) == VictimBit)\r
+ {\r
+ isbW32m(HTE, Offset, 0x55555555);\r
+ }\r
+ else\r
+ {\r
+ isbW32m(HTE, Offset, 0xCCCCCCCC);\r
+ }\r
+ }\r
+\r
+ isbW32m(HTE, 0x00020061, 0x00000000);\r
+ isbW32m(HTE, 0x00020066, 0x03440000);\r
+ isbW32m(HTE, 0x000200A1, 0xFFFF1000);\r
+ }\r
+\r
+ Tmp = 0x10001000 | (LoopCount << 16);\r
+ isbW32m(HTE, 0x00020011, Tmp);\r
+ isbW32m(HTE, 0x00020011, Tmp | BIT8);\r
+\r
+ WaitForHteComplete();\r
+\r
+ return (CheckHteErrors() >> 8) & 0xFF;\r
+}\r
+\r
+UINT16 BasicWriteReadHTE(\r
+ MRC_PARAMS *CurrentMrcData,\r
+ UINT32 Address,\r
+ UINT8 FirstRun,\r
+ UINT8 Mode)\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Execute basic single cache line memory write/read/verify test using simple constant\r
+ pattern (different for READ_RAIN and WRITE_TRAIN modes.\r
+\r
+ Arguments:\r
+\r
+ CurrentMrcData: Host struture for all MRC global data.\r
+ Address: memory adress being tested (must hit specific channel/rank)\r
+ FirstRun: If set then hte registers are configured, otherwise\r
+ it is assumed configuration is done and just re-run the test.\r
+ Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)\r
+\r
+ Returns:\r
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)\r
+\r
+ --*/\r
+{\r
+ UINT16 ByteLaneErrors;\r
+\r
+ ENTERFN();\r
+\r
+ //\r
+ // Enable all error reporting in preparation for HTE test.\r
+ //\r
+ EnableAllHteErrors(0xFF);\r
+ ClearHteErrorRegisters();\r
+\r
+ ByteLaneErrors = BasicDataCompareHte(CurrentMrcData, Address, FirstRun,\r
+ Mode);\r
+\r
+ LEAVEFN();\r
+ return ByteLaneErrors;\r
+}\r
+\r
+UINT16 WriteStressBitLanesHTE(\r
+ MRC_PARAMS *CurrentMrcData,\r
+ UINT32 Address,\r
+ UINT8 FirstRun)\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Examines single cache line memory with write/read/verify test using\r
+ multiple data patterns (victim-aggressor algorithm).\r
+\r
+ Arguments:\r
+\r
+ CurrentMrcData: host struture for all MRC global data.\r
+ Address: memory adress being tested (must hit specific channel/rank)\r
+ FirstRun: If set then hte registers are configured, otherwise\r
+ it is assumed configuration is done and just re-run the test.\r
+\r
+ Returns:\r
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)\r
+\r
+ --*/\r
+{\r
+ UINT16 ByteLaneErrors;\r
+ UINT8 VictimBit = 0;\r
+\r
+ ENTERFN();\r
+\r
+ //\r
+ // Enable all error reporting in preparation for HTE test.\r
+ //\r
+ EnableAllHteErrors(0xFF);\r
+ ClearHteErrorRegisters();\r
+\r
+ //\r
+ // Loop through each bit in the bytelane. Each pass creates a victim bit\r
+ // while keeping all other bits the same - as aggressors.\r
+ // AVN HTE adds an auto-rotate feature which allows us to program the entire victim/aggressor\r
+ // sequence in 1 step. The victim bit rotates on each pass so no need to have software implement\r
+ // a victim bit loop like on VLV.\r
+ //\r
+ ByteLaneErrors = ReadWriteDataCompareHte(CurrentMrcData, Address,\r
+ HTE_LOOP_CNT, HTE_LFSR_VICTIM_SEED, HTE_LFSR_AGRESSOR_SEED, VictimBit,\r
+ FirstRun);\r
+\r
+ LEAVEFN();\r
+ return ByteLaneErrors;\r
+}\r
+\r
+VOID HteMemOp(\r
+ UINT32 Address,\r
+ UINT8 FirstRun,\r
+ UINT8 IsWrite)\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ Execute basic single cache line memory write or read.\r
+ This is just for receive enable / fine write levelling purpose.\r
+\r
+ Arguments:\r
+\r
+ CurrentMrcData: Host structure for all MRC global data.\r
+ Address: memory address used (must hit specific channel/rank)\r
+ FirstRun: If set then hte registers are configured, otherwise\r
+ it is assumed configuration is done and just re-run the test.\r
+ IsWrite: When non-zero memory write operation executed, otherwise read\r
+\r
+ Returns:\r
+ None\r
+\r
+ --*/\r
+{\r
+ UINT32 Offset;\r
+ UINT32 Tmp;\r
+\r
+ EnableAllHteErrors(0xFF);\r
+ ClearHteErrorRegisters();\r
+\r
+ if (FirstRun)\r
+ {\r
+ Tmp = IsWrite ? 0x01110021 : 0x01010021;\r
+ isbW32m(HTE, 0x00020020, Tmp);\r
+\r
+ isbW32m(HTE, 0x00020021, 0x06000000);\r
+ isbW32m(HTE, 0x00020022, Address >> 6);\r
+ isbW32m(HTE, 0x00020062, 0x00800015);\r
+ isbW32m(HTE, 0x00020063, 0xAAAAAAAA);\r
+ isbW32m(HTE, 0x00020064, 0xCCCCCCCC);\r
+ isbW32m(HTE, 0x00020065, 0xF0F0F0F0);\r
+ isbW32m(HTE, 0x00020061, 0x00030008);\r
+\r
+ for (Offset = 0x80; Offset <= 0x8F; Offset++)\r
+ {\r
+ isbW32m(HTE, Offset, 0xC33C0000);\r
+ }\r
+ }\r
+\r
+ isbW32m(HTE, 0x000200A1, 0xFFFF1000);\r
+ isbW32m(HTE, 0x00020011, 0x00011000);\r
+ isbW32m(HTE, 0x00020011, 0x00011100);\r
+\r
+ WaitForHteComplete();\r
+}\r
+\r
--- /dev/null
+/** @file\r
+HTE handling routines for MRC use.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#ifndef __HTE_H\r
+#define __HTE_H\r
+\r
+#define STATIC static\r
+#define VOID void\r
+\r
+#if !defined(__GNUC__) && (__STDC_VERSION__ < 199901L)\r
+typedef uint32_t UINT32;\r
+typedef uint16_t UINT16;\r
+typedef uint8_t UINT8;\r
+#endif\r
+\r
+typedef enum\r
+{\r
+ MrcNoHaltSystemOnError,\r
+ MrcHaltSystemOnError,\r
+ MrcHaltHteEngineOnError,\r
+ MrcNoHaltHteEngineOnError\r
+} HALT_TYPE;\r
+\r
+typedef enum\r
+{\r
+ MrcMemInit, MrcMemTest\r
+} MEM_INIT_OR_TEST;\r
+\r
+#define READ_TRAIN 1\r
+#define WRITE_TRAIN 2\r
+\r
+#define HTE_MEMTEST_NUM 2\r
+#define HTE_LOOP_CNT 5 // EXP_LOOP_CNT field of HTE_CMD_CTL. This CANNOT be less than 4\r
+#define HTE_LFSR_VICTIM_SEED 0xF294BA21 // Random seed for victim.\r
+#define HTE_LFSR_AGRESSOR_SEED 0xEBA7492D // Random seed for aggressor.\r
+UINT32\r
+HteMemInit(\r
+ MRC_PARAMS *CurrentMrcData,\r
+ UINT8 MemInitFlag,\r
+ UINT8 HaltHteEngineOnError);\r
+\r
+UINT16\r
+BasicWriteReadHTE(\r
+ MRC_PARAMS *CurrentMrcData,\r
+ UINT32 Address,\r
+ UINT8 FirstRun,\r
+ UINT8 Mode);\r
+\r
+UINT16\r
+WriteStressBitLanesHTE(\r
+ MRC_PARAMS *CurrentMrcData,\r
+ UINT32 Address,\r
+ UINT8 FirstRun);\r
+\r
+VOID\r
+HteMemOp(\r
+ UINT32 Address,\r
+ UINT8 FirstRun,\r
+ UINT8 IsWrite);\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Declaration of IO handling routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#ifndef __IO_H\r
+#define __IO_H\r
+\r
+#include "core_types.h"\r
+\r
+#include "general_definitions.h"\r
+#include "gen5_iosf_sb_definitions.h"\r
+\r
+// Instruction not present on Quark\r
+#define SFENCE()\r
+\r
+#define DEAD_LOOP() for(;;);\r
+\r
+////\r
+// Define each of the IOSF_SB ports used by MRC\r
+//\r
+\r
+//\r
+// Has to be 0 because of emulation static data\r
+// initialisation:\r
+// Space_t EmuSpace[ SPACE_COUNT] = {0};\r
+//\r
+#define FREE 0x000\r
+\r
+// Pseudo side-band ports for access abstraction\r
+// See Wr32/Rd32 functions\r
+#define MEM 0x101\r
+#define MMIO 0x102\r
+#define DCMD 0x0A0\r
+\r
+// Real side-band ports\r
+// See Wr32/Rd32 functions\r
+#define MCU 0x001\r
+#define HOST_BRIDGE 0x003\r
+#define MEMORY_MANAGER 0x005\r
+#define HTE 0x011\r
+#define DDRPHY 0x012\r
+#define FUSE 0x033\r
+\r
+// End of IOSF_SB ports\r
+////\r
+\r
+// Pciexbar address\r
+#define EC_BASE 0xE0000000\r
+\r
+#define PCIADDR(bus,dev,fn,reg) ( \\r
+ (EC_BASE) + \\r
+ ((bus) << 20) + \\r
+ ((dev) << 15) + \\r
+ ((fn) << 12) + \\r
+ (reg))\r
+\r
+// Various offsets used in the building sideband commands.\r
+#define SB_OPCODE_OFFSET 24\r
+#define SB_PORT_OFFSET 16\r
+#define SB_REG_OFFEST 8\r
+\r
+// Sideband opcodes\r
+#define SB_REG_READ_OPCODE 0x10\r
+#define SB_REG_WRITE_OPCODE 0x11\r
+\r
+#define SB_FUSE_REG_READ_OPCODE 0x06\r
+#define SB_FUSE_REG_WRITE_OPCODE 0x07\r
+\r
+#define SB_DDRIO_REG_READ_OPCODE 0x06\r
+#define SB_DDRIO_REG_WRITE_OPCODE 0x07\r
+\r
+#define SB_DRAM_CMND_OPCODE 0x68\r
+#define SB_WAKE_CMND_OPCODE 0xCA\r
+#define SB_SUSPEND_CMND_OPCODE 0xCC\r
+\r
+// Register addresses for sideband command and data.\r
+#define SB_PACKET_REG 0x00D0\r
+#define SB_DATA_REG 0x00D4\r
+#define SB_HADR_REG 0x00D8\r
+\r
+// We always flag all 4 bytes in the register reads/writes as required.\r
+#define SB_ALL_BYTES_ENABLED 0xF0\r
+\r
+#define SB_COMMAND(Opcode, Port, Reg) \\r
+ ((Opcode << SB_OPCODE_OFFSET) | \\r
+ (Port << SB_PORT_OFFSET) | \\r
+ (Reg << SB_REG_OFFEST) | \\r
+ SB_ALL_BYTES_ENABLED)\r
+\r
+// iosf\r
+#define isbM32m WrMask32\r
+#define isbW32m Wr32\r
+#define isbR32m Rd32\r
+\r
+// pci\r
+\r
+void pciwrite32(\r
+ uint32_t bus,\r
+ uint32_t dev,\r
+ uint32_t fn,\r
+ uint32_t reg,\r
+ uint32_t data);\r
+\r
+uint32_t pciread32(\r
+ uint32_t bus,\r
+ uint32_t dev,\r
+ uint32_t fn,\r
+ uint32_t reg);\r
+\r
+// general\r
+\r
+uint32_t Rd32(\r
+ uint32_t unit,\r
+ uint32_t addr);\r
+\r
+void Wr32(\r
+ uint32_t unit,\r
+ uint32_t addr,\r
+ uint32_t data);\r
+\r
+void WrMask32(\r
+ uint32_t unit,\r
+ uint32_t addr,\r
+ uint32_t data,\r
+ uint32_t mask);\r
+\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Serial conole output and string formating.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "memory_options.h"\r
+#include "general_definitions.h"\r
+\r
+// Resource programmed to PCI bridge, 1MB bound alignment is needed.\r
+// The default value is overwritten by MRC parameter, assuming code\r
+// relocated to eSRAM.\r
+uint32_t UartMmioBase = 0;\r
+\r
+// Serial port registers based on SerialPortLib.c\r
+#define R_UART_BAUD_THR 0\r
+#define R_UART_LSR 20\r
+\r
+#define B_UART_LSR_RXRDY BIT0\r
+#define B_UART_LSR_TXRDY BIT5\r
+#define B_UART_LSR_TEMT BIT6\r
+\r
+// Print mask see DPF and D_Xxxx\r
+#define DPF_MASK DpfPrintMask\r
+\r
+// Select class of messages enabled for printing\r
+uint32_t DpfPrintMask =\r
+ D_ERROR |\r
+ D_INFO |\r
+ // D_REGRD |\r
+ // D_REGWR |\r
+ // D_FCALL |\r
+ // D_TRN |\r
+ 0;\r
+\r
+#ifdef NDEBUG\r
+// Don't generate debug code\r
+void dpf( uint32_t mask, char_t* bla, ...)\r
+{\r
+ return;\r
+}\r
+\r
+uint8_t mgetc(void)\r
+{\r
+ return 0;\r
+}\r
+\r
+uint8_t mgetch(void)\r
+{\r
+ return 0;\r
+}\r
+\r
+#else\r
+\r
+#ifdef SIM\r
+// Use Vpi console in simulation environment\r
+#include <vpi_user.h>\r
+\r
+void dpf( uint32_t mask, char_t* bla, ...)\r
+{\r
+ va_list va;\r
+\r
+ if( 0 == (mask & DPF_MASK)) return;\r
+\r
+ va_start( va, bla);\r
+ vpi_vprintf( bla, va);\r
+ va_end(va);\r
+}\r
+\r
+#else\r
+\r
+#ifdef EMU\r
+// Use standard console in windows environment\r
+#include <stdio.h>\r
+#endif\r
+\r
+// Read character from serial port\r
+uint8_t mgetc(void)\r
+{\r
+#ifdef EMU\r
+\r
+ // Emulation in Windows environment uses console\r
+ getchar();\r
+\r
+#else\r
+ uint8_t c;\r
+\r
+ while ((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) == 0);\r
+ c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);\r
+\r
+ return c;\r
+#endif\r
+}\r
+\r
+\r
+uint8_t mgetch(void)\r
+{\r
+#ifdef EMU\r
+ return 0;\r
+#else\r
+ uint8_t c = 0;\r
+\r
+ if((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) != 0)\r
+ {\r
+ c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);\r
+ }\r
+\r
+ return c;\r
+#endif\r
+}\r
+\r
+// Print single character\r
+static void printc(\r
+ uint8_t c)\r
+{\r
+#ifdef EMU\r
+\r
+ // Emulation in Windows environment uses console output\r
+ putchar(c);\r
+\r
+#else\r
+\r
+ //\r
+ // Use MMIO access to serial port on PCI\r
+ // while( 0 == (0x20 & inp(0x3f8 + 5)));\r
+ // outp(0x3f8 + 0, c);\r
+ //\r
+ while (0\r
+ == (B_UART_LSR_TEMT & *((volatile uint8_t*) (UartMmioBase + R_UART_LSR))))\r
+ ;\r
+ *((volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR)) = c;\r
+#endif\r
+}\r
+\r
+// Print 0 terminated string on serial console\r
+static void printstr(\r
+ char_t *str)\r
+{\r
+ while (*str)\r
+ {\r
+ printc(*str++);\r
+ }\r
+}\r
+// Print 64bit number as hex string on serial console\r
+// the width parameters allows skipping leading zeros\r
+static void printhexx(\r
+ uint64_t val,\r
+ uint32_t width)\r
+{\r
+ uint32_t i;\r
+ uint8_t c;\r
+ uint8_t empty = 1;\r
+\r
+ // 64bit number has 16 characters in hex representation\r
+ for (i = 16; i > 0; i--)\r
+ {\r
+ c = *(((uint8_t *)&val) + ((i - 1) >> 1));\r
+ if (((i - 1) & 1) != 0)\r
+ c = c >> 4;\r
+ c = c & 0x0F;\r
+\r
+ if (c > 9)\r
+ c += 'A' - 10;\r
+ else\r
+ c += '0';\r
+\r
+ if (c != '0')\r
+ {\r
+ // end of leading zeros\r
+ empty = 0;\r
+ }\r
+\r
+ // don't print leading zero\r
+ if (!empty || i <= width)\r
+ {\r
+ printc(c);\r
+ }\r
+ }\r
+}\r
+// Print 32bit number as hex string on serial console\r
+// the width parameters allows skipping leading zeros\r
+static void printhex(\r
+ uint32_t val,\r
+ uint32_t width)\r
+{\r
+ uint32_t i;\r
+ uint8_t c;\r
+ uint8_t empty = 1;\r
+\r
+ // 32bit number has 8 characters in hex representation\r
+ for (i = 8; i > 0; i--)\r
+ {\r
+ c = (uint8_t) ((val >> 28) & 0x0F);\r
+ if (c > 9)\r
+ c += 'A' - 10;\r
+ else\r
+ c += '0';\r
+\r
+ val = val << 4;\r
+\r
+ if (c != '0')\r
+ {\r
+ // end of leading zeros\r
+ empty = 0;\r
+ }\r
+\r
+ // don't print leading zero\r
+ if (!empty || i <= width)\r
+ {\r
+ printc(c);\r
+ }\r
+ }\r
+}\r
+// Print 32bit number as decimal string on serial console\r
+// the width parameters allows skipping leading zeros\r
+static void printdec(\r
+ uint32_t val,\r
+ uint32_t width)\r
+{\r
+ uint32_t i;\r
+ uint8_t c = 0;\r
+ uint8_t empty = 1;\r
+\r
+ // Ten digits is enough for 32bit number in decimal\r
+ uint8_t buf[10];\r
+\r
+ for (i = 0; i < sizeof(buf); i++)\r
+ {\r
+ c = (uint8_t) (val % 10);\r
+ buf[i] = c + '0';\r
+ val = val / 10;\r
+ }\r
+\r
+ while (i > 0)\r
+ {\r
+ c = buf[--i];\r
+\r
+ if (c != '0')\r
+ {\r
+ // end of leading zeros\r
+ empty = 0;\r
+ }\r
+\r
+ // don't print leading zero\r
+ if (!empty || i < width)\r
+ {\r
+ printc(c);\r
+ }\r
+ }\r
+}\r
+\r
+// Consume numeric substring leading the given string\r
+// Return pointer to the first non-numeric character\r
+// Buffer reference by width is updated with number\r
+// converted from the numeric substring.\r
+static char_t *getwidth(\r
+ char_t *bla,\r
+ uint32_t *width)\r
+{\r
+ uint32_t val = 0;\r
+\r
+ while (*bla >= '0' && *bla <= '9')\r
+ {\r
+ val = val * 10 + *bla - '0';\r
+ bla += 1;\r
+ }\r
+\r
+ if (val > 0)\r
+ {\r
+ *width = val;\r
+ }\r
+ return bla;\r
+}\r
+\r
+// Consume print format designator from the head of given string\r
+// Return pointer to first character after format designator\r
+// input fmt\r
+// ----- ---\r
+// s -> s\r
+// d -> d\r
+// X -> X\r
+// llX -> L\r
+static char_t *getformat(\r
+ char_t *bla,\r
+ uint8_t *fmt)\r
+{\r
+ if (bla[0] == 's')\r
+ {\r
+ bla += 1;\r
+ *fmt = 's';\r
+ }\r
+ else if (bla[0] == 'd')\r
+ {\r
+ bla += 1;\r
+ *fmt = 'd';\r
+ }\r
+ else if (bla[0] == 'X' || bla[0] == 'x')\r
+ {\r
+ bla += 1;\r
+ *fmt = 'X';\r
+ }\r
+ else if (bla[0] == 'l' && bla[1] == 'l' && bla[2] == 'X')\r
+ {\r
+ bla += 3;\r
+ *fmt = 'L';\r
+ }\r
+\r
+ return bla;\r
+}\r
+\r
+// Simplified implementation of standard printf function\r
+// The output is directed to serial console. Only selected\r
+// class of messages is printed (mask has to match DpfPrintMask)\r
+// Supported print formats: %[n]s,%[n]d,%[n]X,,%[n]llX\r
+// The width is ignored for %s format.\r
+void dpf(\r
+ uint32_t mask,\r
+ char_t* bla,\r
+ ...)\r
+{\r
+ uint32_t* arg = (uint32_t*) (&bla + 1);\r
+\r
+ // Check UART MMIO base configured\r
+ if (0 == UartMmioBase)\r
+ return;\r
+\r
+ // Check event not masked\r
+ if (0 == (mask & DPF_MASK))\r
+ return;\r
+\r
+ for (;;)\r
+ {\r
+ uint8_t x = *bla++;\r
+ if (x == 0)\r
+ break;\r
+\r
+ if (x == '\n')\r
+ {\r
+ printc('\r');\r
+ printc('\n');\r
+ }\r
+ else if (x == '%')\r
+ {\r
+ uint8_t fmt = 0;\r
+ uint32_t width = 1;\r
+\r
+ bla = getwidth(bla, &width);\r
+ bla = getformat(bla, &fmt);\r
+\r
+ // Print value\r
+ if (fmt == 'd')\r
+ {\r
+ printdec(*arg, width);\r
+ arg += 1;\r
+ }\r
+ else if (fmt == 'X')\r
+ {\r
+ printhex(*arg, width);\r
+ arg += 1;\r
+ }\r
+ else if (fmt == 'L')\r
+ {\r
+ printhexx(*(uint64_t*) arg, width);\r
+ arg += 2;\r
+ }\r
+ else if (fmt == 's')\r
+ {\r
+ printstr(*(char**) arg);\r
+ arg += 1;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ printc(x);\r
+ }\r
+ }\r
+}\r
+\r
+#endif //SIM\r
+#endif //NDEBUG\r
--- /dev/null
+/************************************************************************\r
+ *\r
+ * Copyright (c) 2013-2015 Intel Corporation.\r
+ *\r
+* This program and the accompanying materials\r
+* are licensed and made available under the terms and conditions of the BSD License\r
+* which accompanies this distribution. The full text of the license may be found at\r
+* http://opensource.org/licenses/bsd-license.php\r
+*\r
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ *\r
+ * This file contains all of the Cat Mountain Memory Reference Code (MRC).\r
+ *\r
+ * These functions are generic and should work for any Cat Mountain config.\r
+ *\r
+ * MRC requires two data structures to be passed in which are initialised by "PreMemInit()".\r
+ *\r
+ * The basic flow is as follows:\r
+ * 01) Check for supported DDR speed configuration\r
+ * 02) Set up MEMORY_MANAGER buffer as pass-through (POR)\r
+ * 03) Set Channel Interleaving Mode and Channel Stride to the most aggressive setting possible\r
+ * 04) Set up the MCU logic\r
+ * 05) Set up the DDR_PHY logic\r
+ * 06) Initialise the DRAMs (JEDEC)\r
+ * 07) Perform the Receive Enable Calibration algorithm\r
+ * 08) Perform the Write Leveling algorithm\r
+ * 09) Perform the Read Training algorithm (includes internal Vref)\r
+ * 10) Perform the Write Training algorithm\r
+ * 11) Set Channel Interleaving Mode and Channel Stride to the desired settings\r
+ *\r
+ * Dunit configuration based on Valleyview MRC.\r
+ *\r
+ ***************************************************************************/\r
+\r
+#include "mrc.h"\r
+#include "memory_options.h"\r
+\r
+#include "meminit.h"\r
+#include "meminit_utils.h"\r
+#include "hte.h"\r
+#include "io.h"\r
+\r
+// Override ODT to off state if requested\r
+#define DRMC_DEFAULT (mrc_params->rd_odt_value==0?BIT12:0)\r
+\r
+\r
+// tRFC values (in picoseconds) per density\r
+const uint32_t tRFC[5] =\r
+{\r
+ 90000, // 512Mb\r
+ 110000, // 1Gb\r
+ 160000, // 2Gb\r
+ 300000, // 4Gb\r
+ 350000, // 8Gb\r
+ };\r
+\r
+// tCK clock period in picoseconds per speed index 800, 1066, 1333\r
+const uint32_t tCK[3] =\r
+{\r
+ 2500,\r
+ 1875,\r
+ 1500\r
+};\r
+\r
+#ifdef SIM\r
+// Select static timings specific to simulation environment\r
+#define PLATFORM_ID 0\r
+#else\r
+// Select static timings specific to ClantonPeek platform\r
+#define PLATFORM_ID 1\r
+#endif\r
+\r
+\r
+// Global variables\r
+const uint16_t ddr_wclk[] =\r
+ {193, 158};\r
+\r
+const uint16_t ddr_wctl[] =\r
+ { 1, 217};\r
+\r
+const uint16_t ddr_wcmd[] =\r
+ { 1, 220};\r
+\r
+\r
+#ifdef BACKUP_RCVN\r
+const uint16_t ddr_rcvn[] =\r
+ {129, 498};\r
+#endif // BACKUP_RCVN\r
+\r
+#ifdef BACKUP_WDQS\r
+const uint16_t ddr_wdqs[] =\r
+ { 65, 289};\r
+#endif // BACKUP_WDQS\r
+\r
+#ifdef BACKUP_RDQS\r
+const uint8_t ddr_rdqs[] =\r
+ { 32, 24};\r
+#endif // BACKUP_RDQS\r
+\r
+#ifdef BACKUP_WDQ\r
+const uint16_t ddr_wdq[] =\r
+ { 32, 257};\r
+#endif // BACKUP_WDQ\r
+\r
+\r
+\r
+// Select MEMORY_MANAGER as the source for PRI interface\r
+static void select_memory_manager(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ RegDCO Dco;\r
+\r
+ ENTERFN();\r
+\r
+ Dco.raw = isbR32m(MCU, DCO);\r
+ Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER\r
+ isbW32m(MCU, DCO, Dco.raw);\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+// Select HTE as the source for PRI interface\r
+void select_hte(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ RegDCO Dco;\r
+\r
+ ENTERFN();\r
+\r
+ Dco.raw = isbR32m(MCU, DCO);\r
+ Dco.field.PMICTL = 1; //1 - PRI owned by HTE\r
+ isbW32m(MCU, DCO, Dco.raw);\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+// Send DRAM command, data should be formated\r
+// using DCMD_Xxxx macro or emrsXCommand structure.\r
+static void dram_init_command(\r
+ uint32_t data)\r
+{\r
+ Wr32(DCMD, 0, data);\r
+}\r
+\r
+// Send DRAM wake command using special MCU side-band WAKE opcode\r
+static void dram_wake_command(\r
+ void)\r
+{\r
+ ENTERFN();\r
+\r
+ Wr32(MMIO, PCIADDR(0,0,0,SB_PACKET_REG),\r
+ (uint32_t) SB_COMMAND(SB_WAKE_CMND_OPCODE, MCU, 0));\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+// Stop self refresh driven by MCU\r
+static void clear_self_refresh(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ ENTERFN();\r
+\r
+ // clear the PMSTS Channel Self Refresh bits\r
+ isbM32m(MCU, PMSTS, BIT0, BIT0);\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+// Configure MCU before jedec init sequence\r
+static void prog_decode_before_jedec(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ RegDRP Drp;\r
+ RegDRCF Drfc;\r
+ RegDCAL Dcal;\r
+ RegDSCH Dsch;\r
+ RegDPMC0 Dpmc0;\r
+\r
+ ENTERFN();\r
+\r
+ // Disable power saving features\r
+ Dpmc0.raw = isbR32m(MCU, DPMC0);\r
+ Dpmc0.field.CLKGTDIS = 1;\r
+ Dpmc0.field.DISPWRDN = 1;\r
+ Dpmc0.field.DYNSREN = 0;\r
+ Dpmc0.field.PCLSTO = 0;\r
+ isbW32m(MCU, DPMC0, Dpmc0.raw);\r
+\r
+ // Disable out of order transactions\r
+ Dsch.raw = isbR32m(MCU, DSCH);\r
+ Dsch.field.OOODIS = 1;\r
+ Dsch.field.NEWBYPDIS = 1;\r
+ isbW32m(MCU, DSCH, Dsch.raw);\r
+\r
+ // Disable issuing the REF command\r
+ Drfc.raw = isbR32m(MCU, DRFC);\r
+ Drfc.field.tREFI = 0;\r
+ isbW32m(MCU, DRFC, Drfc.raw);\r
+\r
+ // Disable ZQ calibration short\r
+ Dcal.raw = isbR32m(MCU, DCAL);\r
+ Dcal.field.ZQCINT = 0;\r
+ Dcal.field.SRXZQCL = 0;\r
+ isbW32m(MCU, DCAL, Dcal.raw);\r
+\r
+ // Training performed in address mode 0, rank population has limited impact, however\r
+ // simulator complains if enabled non-existing rank.\r
+ Drp.raw = 0;\r
+ if (mrc_params->rank_enables & 1)\r
+ Drp.field.rank0Enabled = 1;\r
+ if (mrc_params->rank_enables & 2)\r
+ Drp.field.rank1Enabled = 1;\r
+ isbW32m(MCU, DRP, Drp.raw);\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+// After Cold Reset, BIOS should set COLDWAKE bit to 1 before\r
+// sending the WAKE message to the Dunit.\r
+// For Standby Exit, or any other mode in which the DRAM is in\r
+// SR, this bit must be set to 0.\r
+static void perform_ddr_reset(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ ENTERFN();\r
+\r
+ // Set COLDWAKE bit before sending the WAKE message\r
+ isbM32m(MCU, DRMC, BIT16, BIT16);\r
+\r
+ // Send wake command to DUNIT (MUST be done before JEDEC)\r
+ dram_wake_command();\r
+\r
+ // Set default value\r
+ isbW32m(MCU, DRMC, DRMC_DEFAULT);\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+// Dunit Initialisation Complete.\r
+// Indicates that initialisation of the Dunit has completed.\r
+// Memory accesses are permitted and maintenance operation\r
+// begins. Until this bit is set to a 1, the memory controller will\r
+// not accept DRAM requests from the MEMORY_MANAGER or HTE.\r
+static void set_ddr_init_complete(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ RegDCO Dco;\r
+\r
+ ENTERFN();\r
+\r
+ Dco.raw = isbR32m(MCU, DCO);\r
+ Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER\r
+ Dco.field.IC = 1; //1 - initialisation complete\r
+ isbW32m(MCU, DCO, Dco.raw);\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+static void prog_page_ctrl(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ RegDPMC0 Dpmc0;\r
+\r
+ ENTERFN();\r
+\r
+ Dpmc0.raw = isbR32m(MCU, DPMC0);\r
+\r
+ Dpmc0.field.PCLSTO = 0x4;\r
+ Dpmc0.field.PREAPWDEN = 1;\r
+\r
+ isbW32m(MCU, DPMC0, Dpmc0.raw);\r
+}\r
+\r
+// Configure MCU Power Management Control Register\r
+// and Scheduler Control Register.\r
+static void prog_ddr_control(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ RegDSCH Dsch;\r
+ RegDPMC0 Dpmc0;\r
+\r
+ ENTERFN();\r
+\r
+ Dpmc0.raw = isbR32m(MCU, DPMC0);\r
+ Dsch.raw = isbR32m(MCU, DSCH);\r
+\r
+ Dpmc0.field.DISPWRDN = mrc_params->power_down_disable;\r
+ Dpmc0.field.CLKGTDIS = 0;\r
+ Dpmc0.field.PCLSTO = 4;\r
+ Dpmc0.field.PREAPWDEN = 1;\r
+\r
+ Dsch.field.OOODIS = 0;\r
+ Dsch.field.OOOST3DIS = 0;\r
+ Dsch.field.NEWBYPDIS = 0;\r
+\r
+ isbW32m(MCU, DSCH, Dsch.raw);\r
+ isbW32m(MCU, DPMC0, Dpmc0.raw);\r
+\r
+ // CMDTRIST = 2h - CMD/ADDR are tristated when no valid command\r
+ isbM32m(MCU, DPMC1, 2 << 4, BIT5|BIT4);\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+// After training complete configure MCU Rank Population Register\r
+// specifying: ranks enabled, device width, density, address mode.\r
+static void prog_dra_drb(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ RegDRP Drp;\r
+ RegDCO Dco;\r
+\r
+ ENTERFN();\r
+\r
+ Dco.raw = isbR32m(MCU, DCO);\r
+ Dco.field.IC = 0;\r
+ isbW32m(MCU, DCO, Dco.raw);\r
+\r
+ Drp.raw = 0;\r
+ if (mrc_params->rank_enables & 1)\r
+ Drp.field.rank0Enabled = 1;\r
+ if (mrc_params->rank_enables & 2)\r
+ Drp.field.rank1Enabled = 1;\r
+ if (mrc_params->dram_width == x16)\r
+ {\r
+ Drp.field.dimm0DevWidth = 1;\r
+ Drp.field.dimm1DevWidth = 1;\r
+ }\r
+ // Density encoding in DRAMParams_t 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb\r
+ // has to be mapped RANKDENSx encoding (0=1Gb)\r
+ Drp.field.dimm0DevDensity = mrc_params->params.DENSITY - 1;\r
+ Drp.field.dimm1DevDensity = mrc_params->params.DENSITY - 1;\r
+\r
+ // Address mode can be overwritten if ECC enabled\r
+ Drp.field.addressMap = mrc_params->address_mode;\r
+\r
+ isbW32m(MCU, DRP, Drp.raw);\r
+\r
+ Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER\r
+ Dco.field.IC = 1; //1 - initialisation complete\r
+ isbW32m(MCU, DCO, Dco.raw);\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+// Configure refresh rate and short ZQ calibration interval.\r
+// Activate dynamic self refresh.\r
+static void change_refresh_period(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ RegDRCF Drfc;\r
+ RegDCAL Dcal;\r
+ RegDPMC0 Dpmc0;\r
+\r
+ ENTERFN();\r
+\r
+ Drfc.raw = isbR32m(MCU, DRFC);\r
+ Drfc.field.tREFI = mrc_params->refresh_rate;\r
+ Drfc.field.REFDBTCLR = 1;\r
+ isbW32m(MCU, DRFC, Drfc.raw);\r
+\r
+ Dcal.raw = isbR32m(MCU, DCAL);\r
+ Dcal.field.ZQCINT = 3; // 63ms\r
+ isbW32m(MCU, DCAL, Dcal.raw);\r
+\r
+ Dpmc0.raw = isbR32m(MCU, DPMC0);\r
+ Dpmc0.field.ENPHYCLKGATE = 1;\r
+ Dpmc0.field.DYNSREN = 1;\r
+ isbW32m(MCU, DPMC0, Dpmc0.raw);\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+// Send DRAM wake command\r
+static void perform_wake(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ ENTERFN();\r
+\r
+ dram_wake_command();\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+// prog_ddr_timing_control (aka mcu_init):\r
+// POST_CODE[major] == 0x02\r
+//\r
+// It will initialise timing registers in the MCU (DTR0..DTR4).\r
+static void prog_ddr_timing_control(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint8_t TCL, WL;\r
+ uint8_t TRP, TRCD, TRAS, TRFC, TWR, TWTR, TRRD, TRTP, TFAW;\r
+ uint32_t TCK;\r
+\r
+ RegDTR0 Dtr0;\r
+ RegDTR1 Dtr1;\r
+ RegDTR2 Dtr2;\r
+ RegDTR3 Dtr3;\r
+ RegDTR4 Dtr4;\r
+\r
+ ENTERFN();\r
+\r
+ // mcu_init starts\r
+ post_code(0x02, 0x00);\r
+\r
+ Dtr0.raw = isbR32m(MCU, DTR0);\r
+ Dtr1.raw = isbR32m(MCU, DTR1);\r
+ Dtr2.raw = isbR32m(MCU, DTR2);\r
+ Dtr3.raw = isbR32m(MCU, DTR3);\r
+ Dtr4.raw = isbR32m(MCU, DTR4);\r
+\r
+ TCK = tCK[mrc_params->ddr_speed]; // Clock in picoseconds\r
+ TCL = mrc_params->params.tCL; // CAS latency in clocks\r
+ TRP = TCL; // Per CAT MRC\r
+ TRCD = TCL; // Per CAT MRC\r
+ TRAS = MCEIL(mrc_params->params.tRAS, TCK);\r
+ TRFC = MCEIL(tRFC[mrc_params->params.DENSITY], TCK);\r
+ TWR = MCEIL(15000, TCK); // Per JEDEC: tWR=15000ps DDR2/3 from 800-1600\r
+\r
+ TWTR = MCEIL(mrc_params->params.tWTR, TCK);\r
+ TRRD = MCEIL(mrc_params->params.tRRD, TCK);\r
+ TRTP = 4; // Valid for 800 and 1066, use 5 for 1333\r
+ TFAW = MCEIL(mrc_params->params.tFAW, TCK);\r
+\r
+ WL = 5 + mrc_params->ddr_speed;\r
+\r
+ Dtr0.field.dramFrequency = mrc_params->ddr_speed;\r
+\r
+ Dtr0.field.tCL = TCL - 5; //Convert from TCL (DRAM clocks) to VLV indx\r
+ Dtr0.field.tRP = TRP - 5; //5 bit DRAM Clock\r
+ Dtr0.field.tRCD = TRCD - 5; //5 bit DRAM Clock\r
+\r
+ Dtr1.field.tWCL = WL - 3; //Convert from WL (DRAM clocks) to VLV indx\r
+ Dtr1.field.tWTP = WL + 4 + TWR - 14; //Change to tWTP\r
+ Dtr1.field.tRTP = MMAX(TRTP, 4) - 3; //4 bit DRAM Clock\r
+ Dtr1.field.tRRD = TRRD - 4; //4 bit DRAM Clock\r
+ Dtr1.field.tCMD = 1; //2N\r
+ Dtr1.field.tRAS = TRAS - 14; //6 bit DRAM Clock\r
+\r
+ Dtr1.field.tFAW = ((TFAW + 1) >> 1) - 5; //4 bit DRAM Clock\r
+ Dtr1.field.tCCD = 0; //Set 4 Clock CAS to CAS delay (multi-burst)\r
+ Dtr2.field.tRRDR = 1;\r
+ Dtr2.field.tWWDR = 2;\r
+ Dtr2.field.tRWDR = 2;\r
+ Dtr3.field.tWRDR = 2;\r
+ Dtr3.field.tWRDD = 2;\r
+\r
+ if (mrc_params->ddr_speed == DDRFREQ_800)\r
+ {\r
+ // Extended RW delay (+1)\r
+ Dtr3.field.tRWSR = TCL - 5 + 1;\r
+ }\r
+ else if(mrc_params->ddr_speed == DDRFREQ_1066)\r
+ {\r
+ // Extended RW delay (+1)\r
+ Dtr3.field.tRWSR = TCL - 5 + 1;\r
+ }\r
+\r
+ Dtr3.field.tWRSR = 4 + WL + TWTR - 11;\r
+\r
+ if (mrc_params->ddr_speed == DDRFREQ_800)\r
+ {\r
+ Dtr3.field.tXP = MMAX(0, 1 - Dtr1.field.tCMD);\r
+ }\r
+ else\r
+ {\r
+ Dtr3.field.tXP = MMAX(0, 2 - Dtr1.field.tCMD);\r
+ }\r
+\r
+ Dtr4.field.WRODTSTRT = Dtr1.field.tCMD;\r
+ Dtr4.field.WRODTSTOP = Dtr1.field.tCMD;\r
+ Dtr4.field.RDODTSTRT = Dtr1.field.tCMD + Dtr0.field.tCL - Dtr1.field.tWCL + 2; //Convert from WL (DRAM clocks) to VLV indx\r
+ Dtr4.field.RDODTSTOP = Dtr1.field.tCMD + Dtr0.field.tCL - Dtr1.field.tWCL + 2;\r
+ Dtr4.field.TRGSTRDIS = 0;\r
+ Dtr4.field.ODTDIS = 0;\r
+\r
+ isbW32m(MCU, DTR0, Dtr0.raw);\r
+ isbW32m(MCU, DTR1, Dtr1.raw);\r
+ isbW32m(MCU, DTR2, Dtr2.raw);\r
+ isbW32m(MCU, DTR3, Dtr3.raw);\r
+ isbW32m(MCU, DTR4, Dtr4.raw);\r
+\r
+ LEAVEFN();\r
+}\r
+\r
+// ddrphy_init:\r
+// POST_CODE[major] == 0x03\r
+//\r
+// This function performs some initialisation on the DDRIO unit.\r
+// This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES.\r
+static void ddrphy_init(MRCParams_t *mrc_params)\r
+{\r
+ uint32_t tempD; // temporary DWORD\r
+ uint8_t channel_i; // channel counter\r
+ uint8_t rank_i; // rank counter\r
+ uint8_t bl_grp_i; // byte lane group counter (2 BLs per module)\r
+\r
+ uint8_t bl_divisor = /*(mrc_params->channel_width==x16)?2:*/1; // byte lane divisor\r
+ uint8_t speed = mrc_params->ddr_speed & (BIT1|BIT0); // For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333\r
+ uint8_t tCAS;\r
+ uint8_t tCWL;\r
+\r
+ ENTERFN();\r
+\r
+ tCAS = mrc_params->params.tCL;\r
+ tCWL = 5 + mrc_params->ddr_speed;\r
+\r
+ // ddrphy_init starts\r
+ post_code(0x03, 0x00);\r
+\r
+ // HSD#231531\r
+ // Make sure IOBUFACT is deasserted before initialising the DDR PHY.\r
+ // HSD#234845\r
+ // Make sure WRPTRENABLE is deasserted before initialising the DDR PHY.\r
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {\r
+ if (mrc_params->channel_enables & (1<<channel_i)) {\r
+ // Deassert DDRPHY Initialisation Complete\r
+ isbM32m(DDRPHY, (CMDPMCONFIG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT20, BIT20); // SPID_INIT_COMPLETE=0\r
+ // Deassert IOBUFACT\r
+ isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT2, BIT2); // IOBUFACTRST_N=0\r
+ // Disable WRPTR\r
+ isbM32m(DDRPHY, (CMDPTRREG + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT0, BIT0); // WRPTRENABLE=0\r
+ } // if channel enabled\r
+ } // channel_i loop\r
+\r
+ // Put PHY in reset\r
+ isbM32m(DDRPHY, MASTERRSTN, 0, BIT0); // PHYRSTN=0\r
+\r
+ // Initialise DQ01,DQ23,CMD,CLK-CTL,COMP modules\r
+ // STEP0:\r
+ post_code(0x03, 0x10);\r
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {\r
+ if (mrc_params->channel_enables & (1<<channel_i)) {\r
+\r
+ // DQ01-DQ23\r
+ for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {\r
+ isbM32m(DDRPHY, (DQOBSCKEBBCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((bl_grp_i) ? (0x00) : (BIT22)), (BIT22)); // Analog MUX select - IO2xCLKSEL\r
+\r
+ // ODT Strength\r
+ switch (mrc_params->rd_odt_value) {\r
+ case 1: tempD = 0x3; break; // 60 ohm\r
+ case 2: tempD = 0x3; break; // 120 ohm\r
+ case 3: tempD = 0x3; break; // 180 ohm\r
+ default: tempD = 0x3; break; // 120 ohm\r
+ }\r
+ isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (tempD<<5), (BIT6|BIT5)); // ODT strength\r
+ isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (tempD<<5), (BIT6|BIT5)); // ODT strength\r
+ // Dynamic ODT/DIFFAMP\r
+ tempD = (((tCAS)<<24)|((tCAS)<<16)|((tCAS)<<8)|((tCAS)<<0));\r
+ switch (speed) {\r
+ case 0: tempD -= 0x01010101; break; // 800\r
+ case 1: tempD -= 0x02020202; break; // 1066\r
+ case 2: tempD -= 0x03030303; break; // 1333\r
+ case 3: tempD -= 0x04040404; break; // 1600\r
+ }\r
+ 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\r
+ switch (speed) {\r
+ // HSD#234715\r
+ case 0: tempD = ((0x06<<16)|(0x07<<8)); break; // 800\r
+ case 1: tempD = ((0x07<<16)|(0x08<<8)); break; // 1066\r
+ case 2: tempD = ((0x09<<16)|(0x0A<<8)); break; // 1333\r
+ case 3: tempD = ((0x0A<<16)|(0x0B<<8)); break; // 1600\r
+ }\r
+ 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\r
+ 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\r
+\r
+ switch (mrc_params->rd_odt_value) {\r
+ case 0: tempD = ((0x3F<<16)|(0x3f<<10)); break; // override DIFFAMP=on, ODT=off\r
+ default: tempD = ((0x3F<<16)|(0x2A<<10)); break; // override DIFFAMP=on, ODT=on\r
+ }\r
+ 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\r
+ 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\r
+\r
+ // DLL Setup\r
+ // 1xCLK Domain Timings: tEDP,RCVEN,WDQS (PO)\r
+ 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\r
+ 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\r
+\r
+ // RCVEN Bypass (PO)\r
+ isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x0<<7)|(0x0<<0)), (BIT7|BIT0)); // AFE Bypass, RCVEN DIFFAMP\r
+ isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x0<<7)|(0x0<<0)), (BIT7|BIT0)); // AFE Bypass, RCVEN DIFFAMP\r
+ // TX\r
+ isbM32m(DDRPHY, (DQCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT16), (BIT16)); // 0 means driving DQ during DQS-preamble\r
+ isbM32m(DDRPHY, (B01PTRCTL1 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT8), (BIT8)); // WR_LVL mode disable\r
+ // RX (PO)\r
+ 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)\r
+ 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)\r
+ isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (0), (BIT4)); // Per-Bit De-Skew Enable\r
+ isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (0), (BIT4)); // Per-Bit De-Skew Enable\r
+ }\r
+ // CLKEBB\r
+ isbM32m(DDRPHY, (CMDOBSCKEBBCTL + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT23));\r
+\r
+ // Enable tristate control of cmd/address bus\r
+ isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT1|BIT0));\r
+\r
+ // ODT RCOMP\r
+ isbM32m(DDRPHY, (CMDRCOMPODT + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x03<<5)|(0x03<<0)), ((BIT9|BIT8|BIT7|BIT6|BIT5)|(BIT4|BIT3|BIT2|BIT1|BIT0)));\r
+\r
+ // CMDPM* registers must be programmed in this order...\r
+ 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\r
+ 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\r
+ 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\r
+ 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\r
+ 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\r
+ 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\r
+ 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\r
+ // CLK-CTL\r
+ isbM32m(DDRPHY, (CCOBSCKEBBCTL + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT24)); // CLKEBB\r
+ 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\r
+ isbM32m(DDRPHY, (CCRCOMPODT + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x03<<8)|(0x03<<0)), ((BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT RCOMP\r
+ 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\r
+\r
+ // COMP (RON channel specific)\r
+ // - DQ/DQS/DM RON: 32 Ohm\r
+ // - CTRL/CMD RON: 27 Ohm\r
+ // - CLK RON: 26 Ohm\r
+ 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\r
+ 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\r
+ 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\r
+ 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\r
+ 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\r
+\r
+ // DQS Swapped Input Enable\r
+ isbM32m(DDRPHY, (COMPEN1CH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT19|BIT17), ((BIT31|BIT30)|BIT19|BIT17|(BIT15|BIT14)));\r
+\r
+ // ODT VREF = 1.5 x 274/360+274 = 0.65V (code of ~50)\r
+ 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\r
+ 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\r
+ 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\r
+\r
+ // Slew rate settings are frequency specific, numbers below are for 800Mhz (speed == 0)\r
+ // - DQ/DQS/DM/CLK SR: 4V/ns,\r
+ // - CTRL/CMD SR: 1.5V/ns\r
+ tempD = (0x0E<<16)|(0x0E<<12)|(0x08<<8)|(0x0B<<4)|(0x0B<<0);\r
+ 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\r
+ 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\r
+ 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\r
+ isbM32m(DDRPHY, (COMPEN0CH0 + (channel_i * DDRCOMP_CH_OFFSET)), (0), ((BIT31|BIT30)|BIT8)); // COMP\r
+\r
+ #ifdef BACKUP_COMPS\r
+ // DQ COMP Overrides\r
+ isbM32m(DDRPHY, (DQDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU\r
+ isbM32m(DDRPHY, (DQDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD\r
+ isbM32m(DDRPHY, (DQDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU\r
+ isbM32m(DDRPHY, (DQDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD\r
+ isbM32m(DDRPHY, (DQODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU\r
+ isbM32m(DDRPHY, (DQODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD\r
+ isbM32m(DDRPHY, (DQTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU\r
+ isbM32m(DDRPHY, (DQTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD\r
+ // DQS COMP Overrides\r
+ isbM32m(DDRPHY, (DQSDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU\r
+ isbM32m(DDRPHY, (DQSDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD\r
+ isbM32m(DDRPHY, (DQSDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU\r
+ isbM32m(DDRPHY, (DQSDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD\r
+ isbM32m(DDRPHY, (DQSODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU\r
+ isbM32m(DDRPHY, (DQSODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD\r
+ isbM32m(DDRPHY, (DQSTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU\r
+ isbM32m(DDRPHY, (DQSTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD\r
+ // CLK COMP Overrides\r
+ isbM32m(DDRPHY, (CLKDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0C<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU\r
+ isbM32m(DDRPHY, (CLKDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0C<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD\r
+ isbM32m(DDRPHY, (CLKDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x07<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU\r
+ isbM32m(DDRPHY, (CLKDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x07<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD\r
+ isbM32m(DDRPHY, (CLKODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU\r
+ isbM32m(DDRPHY, (CLKODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD\r
+ isbM32m(DDRPHY, (CLKTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU\r
+ isbM32m(DDRPHY, (CLKTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD\r
+ // CMD COMP Overrides\r
+ isbM32m(DDRPHY, (CMDDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU\r
+ isbM32m(DDRPHY, (CMDDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD\r
+ isbM32m(DDRPHY, (CMDDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU\r
+ isbM32m(DDRPHY, (CMDDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD\r
+ // CTL COMP Overrides\r
+ isbM32m(DDRPHY, (CTLDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU\r
+ isbM32m(DDRPHY, (CTLDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD\r
+ isbM32m(DDRPHY, (CTLDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU\r
+ isbM32m(DDRPHY, (CTLDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD\r
+ #else\r
+ // DQ TCOCOMP Overrides\r
+ isbM32m(DDRPHY, (DQTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU\r
+ isbM32m(DDRPHY, (DQTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD\r
+ // DQS TCOCOMP Overrides\r
+ isbM32m(DDRPHY, (DQSTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU\r
+ isbM32m(DDRPHY, (DQSTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD\r
+ // CLK TCOCOMP Overrides\r
+ isbM32m(DDRPHY, (CLKTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU\r
+ isbM32m(DDRPHY, (CLKTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD\r
+ #endif // BACKUP_COMPS\r
+ // program STATIC delays\r
+ #ifdef BACKUP_WCMD\r
+ set_wcmd(channel_i, ddr_wcmd[PLATFORM_ID]);\r
+ #else\r
+ set_wcmd(channel_i, ddr_wclk[PLATFORM_ID] + HALF_CLK);\r
+ #endif // BACKUP_WCMD\r
+ for (rank_i=0; rank_i<NUM_RANKS; rank_i++) {\r
+ if (mrc_params->rank_enables & (1<<rank_i)) {\r
+ set_wclk(channel_i, rank_i, ddr_wclk[PLATFORM_ID]);\r
+ #ifdef BACKUP_WCTL\r
+ set_wctl(channel_i, rank_i, ddr_wctl[PLATFORM_ID]);\r
+ #else\r
+ set_wctl(channel_i, rank_i, ddr_wclk[PLATFORM_ID] + HALF_CLK);\r
+ #endif // BACKUP_WCTL\r
+ }\r
+ }\r
+ }\r
+ }\r
+ // COMP (non channel specific)\r
+ //isbM32m(DDRPHY, (), (), ());\r
+ isbM32m(DDRPHY, (DQANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable\r
+ isbM32m(DDRPHY, (DQANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable\r
+ isbM32m(DDRPHY, (CMDANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable\r
+ isbM32m(DDRPHY, (CMDANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable\r
+ isbM32m(DDRPHY, (CLKANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable\r
+ isbM32m(DDRPHY, (CLKANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable\r
+ isbM32m(DDRPHY, (DQSANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable\r
+ isbM32m(DDRPHY, (DQSANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable\r
+ isbM32m(DDRPHY, (CTLANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable\r
+ isbM32m(DDRPHY, (CTLANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable\r
+ isbM32m(DDRPHY, (DQANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable\r
+ isbM32m(DDRPHY, (DQANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable\r
+ isbM32m(DDRPHY, (CLKANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable\r
+ isbM32m(DDRPHY, (CLKANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable\r
+ isbM32m(DDRPHY, (DQSANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable\r
+ isbM32m(DDRPHY, (DQSANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable\r
+ isbM32m(DDRPHY, (DQANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable\r
+ isbM32m(DDRPHY, (DQANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable\r
+ isbM32m(DDRPHY, (CMDANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable\r
+ isbM32m(DDRPHY, (CMDANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable\r
+ isbM32m(DDRPHY, (CLKANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable\r
+ isbM32m(DDRPHY, (CLKANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable\r
+ isbM32m(DDRPHY, (DQSANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable\r
+ isbM32m(DDRPHY, (DQSANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable\r
+ isbM32m(DDRPHY, (CTLANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable\r
+ isbM32m(DDRPHY, (CTLANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable\r
+ isbM32m(DDRPHY, (DQANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable\r
+ isbM32m(DDRPHY, (DQANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable\r
+ isbM32m(DDRPHY, (CLKANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable\r
+ isbM32m(DDRPHY, (CLKANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable\r
+ isbM32m(DDRPHY, (DQSANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable\r
+ isbM32m(DDRPHY, (DQSANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable\r
+ isbM32m(DDRPHY, (TCOCNTCTRL), (0x1<<0), (BIT1|BIT0)); // TCOCOMP: Pulse Count\r
+ isbM32m(DDRPHY, (CHNLBUFSTATIC), ((0x03<<24)|(0x03<<16)), ((BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODT: CMD/CTL PD/PU\r
+ isbM32m(DDRPHY, (MSCNTR), (0x64<<0), (BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0)); // Set 1us counter\r
+ isbM32m(DDRPHY, (LATCH1CTL), (0x1<<28), (BIT30|BIT29|BIT28)); // ???\r
+\r
+ // Release PHY from reset\r
+ isbM32m(DDRPHY, MASTERRSTN, BIT0, BIT0); // PHYRSTN=1\r
+\r
+ // STEP1:\r
+ post_code(0x03, 0x11);\r
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {\r
+ if (mrc_params->channel_enables & (1<<channel_i)) {\r
+ // DQ01-DQ23\r
+ for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {\r
+ isbM32m(DDRPHY, (DQMDLLCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG\r
+ delay_n(3);\r
+ }\r
+ // ECC\r
+ isbM32m(DDRPHY, (ECCMDLLCTL), (BIT13), (BIT13)); // Enable VREG\r
+ delay_n(3);\r
+ // CMD\r
+ isbM32m(DDRPHY, (CMDMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG\r
+ delay_n(3);\r
+ // CLK-CTL\r
+ isbM32m(DDRPHY, (CCMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG\r
+ delay_n(3);\r
+ }\r
+ }\r
+\r
+ // STEP2:\r
+ post_code(0x03, 0x12);\r
+ delay_n(200);\r
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {\r
+ if (mrc_params->channel_enables & (1<<channel_i)) {\r
+ // DQ01-DQ23\r
+ for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {\r
+ isbM32m(DDRPHY, (DQMDLLCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT17), (BIT17)); // Enable MCDLL\r
+ delay_n(50);\r
+ }\r
+ // ECC\r
+ isbM32m(DDRPHY, (ECCMDLLCTL), (BIT17), (BIT17)); // Enable MCDLL\r
+ delay_n(50);\r
+ // CMD\r
+ isbM32m(DDRPHY, (CMDMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT18), (BIT18)); // Enable MCDLL\r
+ delay_n(50);\r
+ // CLK-CTL\r
+ isbM32m(DDRPHY, (CCMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT18), (BIT18)); // Enable MCDLL\r
+ delay_n(50);\r
+ }\r
+ }\r
+\r
+ // STEP3:\r
+ post_code(0x03, 0x13);\r
+ delay_n(100);\r
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {\r
+ if (mrc_params->channel_enables & (1<<channel_i)) {\r
+ // DQ01-DQ23\r
+ for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {\r
+#ifdef FORCE_16BIT_DDRIO\r
+ tempD = ((bl_grp_i) && (mrc_params->channel_width == x16)) ? ((0x1<<12)|(0x1<<8)|(0xF<<4)|(0xF<<0)) : ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0));\r
+#else\r
+ tempD = ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0));\r
+#endif\r
+ 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\r
+ delay_n(3);\r
+ isbM32m(DDRPHY, (DQDLLRXCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT3|BIT2|BIT1|BIT0), (BIT3|BIT2|BIT1|BIT0)); // Enable RXDLL\r
+ delay_n(3);\r
+ 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\r
+ }\r
+\r
+ // ECC\r
+ tempD = ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0));\r
+ isbM32m(DDRPHY, (ECCDLLTXCTL), (tempD), ((BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // Enable TXDLL\r
+ delay_n(3);\r
+\r
+ // CMD (PO)\r
+ 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\r
+ delay_n(3);\r
+ }\r
+ }\r
+\r
+\r
+ // STEP4:\r
+ post_code(0x03, 0x14);\r
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {\r
+ if (mrc_params->channel_enables & (1<<channel_i)) {\r
+ // Host To Memory Clock Alignment (HMC) for 800/1066\r
+ for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {\r
+ isbM32m(DDRPHY, (DQCLKALIGNREG2 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((bl_grp_i)?(0x3):(0x1)), (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID\r
+ }\r
+ isbM32m(DDRPHY, (ECCCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x2, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID\r
+ isbM32m(DDRPHY, (CMDCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x0, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID\r
+ isbM32m(DDRPHY, (CCCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x2, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID\r
+ isbM32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), (0x2<<4), (BIT5|BIT4)); // CLK_ALIGN_MODE\r
+ isbM32m(DDRPHY, (CMDCLKALIGNREG1 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x18<<16)|(0x10<<8)|(0x8<<2)|(0x1<<0)), ((BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2)|(BIT1|BIT0))); // NUM_SAMPLES, MAX_SAMPLES, MACRO_PI_STEP, MICRO_PI_STEP\r
+ isbM32m(DDRPHY, (CMDCLKALIGNREG2 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x10<<16)|(0x4<<8)|(0x2<<4)), ((BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4))); // ???, TOTAL_NUM_MODULES, FIRST_U_PARTITION\r
+ #ifdef HMC_TEST\r
+ isbM32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT24, BIT24); // START_CLK_ALIGN=1\r
+ while (isbR32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET))) & BIT24); // wait for START_CLK_ALIGN=0\r
+ #endif // HMC_TEST\r
+\r
+ // Set RD/WR Pointer Seperation & COUNTEN & FIFOPTREN\r
+ isbM32m(DDRPHY, (CMDPTRREG + (channel_i * DDRIOCCC_CH_OFFSET)), BIT0, BIT0); // WRPTRENABLE=1\r
+\r
+\r
+#ifdef SIM\r
+ // comp is not working on simulator\r
+#else\r
+ // COMP initial\r
+ isbM32m(DDRPHY, (COMPEN0CH0 + (channel_i * DDRCOMP_CH_OFFSET)), BIT5, BIT5); // enable bypass for CLK buffer (PO)\r
+ isbM32m(DDRPHY, (CMPCTRL), (BIT0), (BIT0)); // Initial COMP Enable\r
+ while (isbR32m(DDRPHY, (CMPCTRL)) & BIT0); // wait for Initial COMP Enable = 0\r
+ isbM32m(DDRPHY, (COMPEN0CH0 + (channel_i * DDRCOMP_CH_OFFSET)), ~BIT5, BIT5); // disable bypass for CLK buffer (PO)\r
+#endif\r
+\r
+ // IOBUFACT\r
+ // STEP4a\r
+ isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT2, BIT2); // IOBUFACTRST_N=1\r
+\r
+ // DDRPHY initialisation complete\r
+ isbM32m(DDRPHY, (CMDPMCONFIG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT20, BIT20); // SPID_INIT_COMPLETE=1\r
+ }\r
+ }\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// jedec_init (aka PerformJedecInit):\r
+// This function performs JEDEC initialisation on all enabled channels.\r
+static void jedec_init(\r
+ MRCParams_t *mrc_params,\r
+ uint32_t silent)\r
+{\r
+ uint8_t TWR, WL, Rank;\r
+ uint32_t TCK;\r
+\r
+ RegDTR0 DTR0reg;\r
+\r
+ DramInitDDR3MRS0 mrs0Command;\r
+ DramInitDDR3EMR1 emrs1Command;\r
+ DramInitDDR3EMR2 emrs2Command;\r
+ DramInitDDR3EMR3 emrs3Command;\r
+\r
+ ENTERFN();\r
+\r
+ // jedec_init starts\r
+ if (!silent)\r
+ {\r
+ post_code(0x04, 0x00);\r
+ }\r
+\r
+ // Assert RESET# for 200us\r
+ isbM32m(DDRPHY, CCDDR3RESETCTL, BIT1, (BIT8|BIT1)); // DDR3_RESET_SET=0, DDR3_RESET_RESET=1\r
+#ifdef QUICKSIM\r
+ // Don't waste time during simulation\r
+ delay_u(2);\r
+#else\r
+ delay_u(200);\r
+#endif\r
+ isbM32m(DDRPHY, CCDDR3RESETCTL, BIT8, (BIT8|BIT1)); // DDR3_RESET_SET=1, DDR3_RESET_RESET=0\r
+\r
+ DTR0reg.raw = isbR32m(MCU, DTR0);\r
+\r
+ // Set CKEVAL for populated ranks\r
+ // then send NOP to each rank (#4550197)\r
+ {\r
+ uint32_t DRPbuffer;\r
+ uint32_t DRMCbuffer;\r
+\r
+ DRPbuffer = isbR32m(MCU, DRP);\r
+ DRPbuffer &= 0x3;\r
+ DRMCbuffer = isbR32m(MCU, DRMC);\r
+ DRMCbuffer &= 0xFFFFFFFC;\r
+ DRMCbuffer |= (BIT4 | DRPbuffer);\r
+\r
+ isbW32m(MCU, DRMC, DRMCbuffer);\r
+\r
+ for (Rank = 0; Rank < NUM_RANKS; Rank++)\r
+ {\r
+ // Skip to next populated rank\r
+ if ((mrc_params->rank_enables & (1 << Rank)) == 0)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ dram_init_command(DCMD_NOP(Rank));\r
+ }\r
+\r
+ isbW32m(MCU, DRMC, DRMC_DEFAULT);\r
+ }\r
+\r
+ // setup for emrs 2\r
+ // BIT[15:11] --> Always "0"\r
+ // BIT[10:09] --> Rtt_WR: want "Dynamic ODT Off" (0)\r
+ // BIT[08] --> Always "0"\r
+ // BIT[07] --> SRT: use sr_temp_range\r
+ // BIT[06] --> ASR: want "Manual SR Reference" (0)\r
+ // BIT[05:03] --> CWL: use oem_tCWL\r
+ // BIT[02:00] --> PASR: want "Full Array" (0)\r
+ emrs2Command.raw = 0;\r
+ emrs2Command.field.bankAddress = 2;\r
+\r
+ WL = 5 + mrc_params->ddr_speed;\r
+ emrs2Command.field.CWL = WL - 5;\r
+ emrs2Command.field.SRT = mrc_params->sr_temp_range;\r
+\r
+ // setup for emrs 3\r
+ // BIT[15:03] --> Always "0"\r
+ // BIT[02] --> MPR: want "Normal Operation" (0)\r
+ // BIT[01:00] --> MPR_Loc: want "Predefined Pattern" (0)\r
+ emrs3Command.raw = 0;\r
+ emrs3Command.field.bankAddress = 3;\r
+\r
+ // setup for emrs 1\r
+ // BIT[15:13] --> Always "0"\r
+ // BIT[12:12] --> Qoff: want "Output Buffer Enabled" (0)\r
+ // BIT[11:11] --> TDQS: want "Disabled" (0)\r
+ // BIT[10:10] --> Always "0"\r
+ // BIT[09,06,02] --> Rtt_nom: use rtt_nom_value\r
+ // BIT[08] --> Always "0"\r
+ // BIT[07] --> WR_LVL: want "Disabled" (0)\r
+ // BIT[05,01] --> DIC: use ron_value\r
+ // BIT[04:03] --> AL: additive latency want "0" (0)\r
+ // BIT[00] --> DLL: want "Enable" (0)\r
+ //\r
+ // (BIT5|BIT1) set Ron value\r
+ // 00 --> RZQ/6 (40ohm)\r
+ // 01 --> RZQ/7 (34ohm)\r
+ // 1* --> RESERVED\r
+ //\r
+ // (BIT9|BIT6|BIT2) set Rtt_nom value\r
+ // 000 --> Disabled\r
+ // 001 --> RZQ/4 ( 60ohm)\r
+ // 010 --> RZQ/2 (120ohm)\r
+ // 011 --> RZQ/6 ( 40ohm)\r
+ // 1** --> RESERVED\r
+ emrs1Command.raw = 0;\r
+ emrs1Command.field.bankAddress = 1;\r
+ emrs1Command.field.dllEnabled = 0; // 0 = Enable , 1 = Disable\r
+\r
+ if (mrc_params->ron_value == 0)\r
+ {\r
+ emrs1Command.field.DIC0 = DDR3_EMRS1_DIC_34;\r
+ }\r
+ else\r
+ {\r
+ emrs1Command.field.DIC0 = DDR3_EMRS1_DIC_40;\r
+ }\r
+\r
+\r
+ if (mrc_params->rtt_nom_value == 0)\r
+ {\r
+ emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_40 << 6);\r
+ }\r
+ else if (mrc_params->rtt_nom_value == 1)\r
+ {\r
+ emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_60 << 6);\r
+ }\r
+ else if (mrc_params->rtt_nom_value == 2)\r
+ {\r
+ emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_120 << 6);\r
+ }\r
+\r
+ // save MRS1 value (excluding control fields)\r
+ mrc_params->mrs1 = emrs1Command.raw >> 6;\r
+\r
+ // setup for mrs 0\r
+ // BIT[15:13] --> Always "0"\r
+ // BIT[12] --> PPD: for Quark (1)\r
+ // BIT[11:09] --> WR: use oem_tWR\r
+ // BIT[08] --> DLL: want "Reset" (1, self clearing)\r
+ // BIT[07] --> MODE: want "Normal" (0)\r
+ // BIT[06:04,02] --> CL: use oem_tCAS\r
+ // BIT[03] --> RD_BURST_TYPE: want "Interleave" (1)\r
+ // BIT[01:00] --> BL: want "8 Fixed" (0)\r
+ // WR:\r
+ // 0 --> 16\r
+ // 1 --> 5\r
+ // 2 --> 6\r
+ // 3 --> 7\r
+ // 4 --> 8\r
+ // 5 --> 10\r
+ // 6 --> 12\r
+ // 7 --> 14\r
+ // CL:\r
+ // BIT[02:02] "0" if oem_tCAS <= 11 (1866?)\r
+ // BIT[06:04] use oem_tCAS-4\r
+ mrs0Command.raw = 0;\r
+ mrs0Command.field.bankAddress = 0;\r
+ mrs0Command.field.dllReset = 1;\r
+ mrs0Command.field.BL = 0;\r
+ mrs0Command.field.PPD = 1;\r
+ mrs0Command.field.casLatency = DTR0reg.field.tCL + 1;\r
+\r
+ TCK = tCK[mrc_params->ddr_speed];\r
+ TWR = MCEIL(15000, TCK); // Per JEDEC: tWR=15000ps DDR2/3 from 800-1600\r
+ mrs0Command.field.writeRecovery = TWR - 4;\r
+\r
+ for (Rank = 0; Rank < NUM_RANKS; Rank++)\r
+ {\r
+ // Skip to next populated rank\r
+ if ((mrc_params->rank_enables & (1 << Rank)) == 0)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ emrs2Command.field.rankSelect = Rank;\r
+ dram_init_command(emrs2Command.raw);\r
+\r
+ emrs3Command.field.rankSelect = Rank;\r
+ dram_init_command(emrs3Command.raw);\r
+\r
+ emrs1Command.field.rankSelect = Rank;\r
+ dram_init_command(emrs1Command.raw);\r
+\r
+ mrs0Command.field.rankSelect = Rank;\r
+ dram_init_command(mrs0Command.raw);\r
+\r
+ dram_init_command(DCMD_ZQCL(Rank));\r
+ }\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// rcvn_cal:\r
+// POST_CODE[major] == 0x05\r
+//\r
+// This function will perform our RCVEN Calibration Algorithm.\r
+// We will only use the 2xCLK domain timings to perform RCVEN Calibration.\r
+// All byte lanes will be calibrated "simultaneously" per channel per rank.\r
+static void rcvn_cal(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint8_t channel_i; // channel counter\r
+ uint8_t rank_i; // rank counter\r
+ uint8_t bl_i; // byte lane counter\r
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor\r
+\r
+#ifdef R2R_SHARING\r
+ uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs\r
+#ifndef BACKUP_RCVN\r
+ uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs\r
+#endif // BACKUP_RCVN\r
+#endif // R2R_SHARING\r
+\r
+#ifdef BACKUP_RCVN\r
+#else\r
+ uint32_t tempD; // temporary DWORD\r
+ uint32_t delay[NUM_BYTE_LANES]; // absolute PI value to be programmed on the byte lane\r
+ RegDTR1 dtr1;\r
+ RegDTR1 dtr1save;\r
+#endif // BACKUP_RCVN\r
+ ENTERFN();\r
+\r
+ // rcvn_cal starts\r
+ post_code(0x05, 0x00);\r
+\r
+#ifndef BACKUP_RCVN\r
+ // need separate burst to sample DQS preamble\r
+ dtr1.raw = dtr1save.raw = isbR32m(MCU, DTR1);\r
+ dtr1.field.tCCD = 1;\r
+ isbW32m(MCU, DTR1, dtr1.raw);\r
+#endif\r
+\r
+#ifdef R2R_SHARING\r
+ // need to set "final_delay[][]" elements to "0"\r
+ memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));\r
+#endif // R2R_SHARING\r
+\r
+ // loop through each enabled channel\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1 << channel_i))\r
+ {\r
+ // perform RCVEN Calibration on a per rank basis\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1 << rank_i))\r
+ {\r
+ // POST_CODE here indicates the current channel and rank being calibrated\r
+ post_code(0x05, (0x10 + ((channel_i << 4) | rank_i)));\r
+\r
+#ifdef BACKUP_RCVN\r
+ // set hard-coded timing values\r
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)\r
+ {\r
+ set_rcvn(channel_i, rank_i, bl_i, ddr_rcvn[PLATFORM_ID]);\r
+ }\r
+#else\r
+ // enable FIFORST\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i += 2)\r
+ {\r
+ isbM32m(DDRPHY, (B01PTRCTL1 + ((bl_i >> 1) * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), 0,\r
+ BIT8); // 0 is enabled\r
+ } // bl_i loop\r
+ // initialise the starting delay to 128 PI (tCAS +1 CLK)\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+#ifdef SIM\r
+ // Original value was late at the end of DQS sequence\r
+ delay[bl_i] = 3 * FULL_CLK;\r
+#else\r
+ delay[bl_i] = (4 + 1) * FULL_CLK; // 1x CLK domain timing is tCAS-4\r
+#endif\r
+\r
+ set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);\r
+ } // bl_i loop\r
+\r
+ // now find the rising edge\r
+ find_rising_edge(mrc_params, delay, channel_i, rank_i, true);\r
+ // Now increase delay by 32 PI (1/4 CLK) to place in center of high pulse.\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ delay[bl_i] += QRTR_CLK;\r
+ set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);\r
+ } // bl_i loop\r
+ // Now decrement delay by 128 PI (1 CLK) until we sample a "0"\r
+ do\r
+ {\r
+\r
+ tempD = sample_dqs(mrc_params, channel_i, rank_i, true);\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ if (tempD & (1 << bl_i))\r
+ {\r
+ if (delay[bl_i] >= FULL_CLK)\r
+ {\r
+ delay[bl_i] -= FULL_CLK;\r
+ set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);\r
+ }\r
+ else\r
+ {\r
+ // not enough delay\r
+ training_message(channel_i, rank_i, bl_i);\r
+ post_code(0xEE, 0x50);\r
+ }\r
+ }\r
+ } // bl_i loop\r
+ } while (tempD & 0xFF);\r
+\r
+#ifdef R2R_SHARING\r
+ // increment "num_ranks_enabled"\r
+ num_ranks_enabled++;\r
+ // Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble.\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ delay[bl_i] += QRTR_CLK;\r
+ // add "delay[]" values to "final_delay[][]" for rolling average\r
+ final_delay[channel_i][bl_i] += delay[bl_i];\r
+ // set timing based on rolling average values\r
+ set_rcvn(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));\r
+ } // bl_i loop\r
+#else\r
+ // Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble.\r
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)\r
+ {\r
+ delay[bl_i] += QRTR_CLK;\r
+ set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);\r
+ } // bl_i loop\r
+\r
+#endif // R2R_SHARING\r
+\r
+ // disable FIFORST\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i += 2)\r
+ {\r
+ isbM32m(DDRPHY, (B01PTRCTL1 + ((bl_i >> 1) * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), BIT8,\r
+ BIT8); // 1 is disabled\r
+ } // bl_i loop\r
+\r
+#endif // BACKUP_RCVN\r
+\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+\r
+#ifndef BACKUP_RCVN\r
+ // restore original\r
+ isbW32m(MCU, DTR1, dtr1save.raw);\r
+#endif\r
+\r
+#ifdef MRC_SV\r
+ if (mrc_params->tune_rcvn)\r
+ {\r
+ uint32_t rcven, val;\r
+ uint32_t rdcmd2rcven;\r
+\r
+ /*\r
+ Formulas for RDCMD2DATAVALID & DIFFAMP dynamic timings\r
+\r
+ 1. Set after RCVEN training\r
+\r
+ //Tune RDCMD2DATAVALID\r
+\r
+ x80/x84[21:16]\r
+ MAX OF 2 RANKS : round up (rdcmd2rcven (rcven 1x) + 2x x 2 + PI/128) + 5\r
+\r
+ //rdcmd2rcven x80/84[12:8]\r
+ //rcven 2x x70[23:20] & [11:8]\r
+\r
+ //Tune DIFFAMP Timings\r
+\r
+ //diffampen launch x88[20:16] & [4:0] -- B01LATCTL1\r
+ MIN OF 2 RANKS : round down (rcven 1x + 2x x 2 + PI/128) - 1\r
+\r
+ //diffampen length x8C/x90 [13:8] -- B0ONDURCTL B1ONDURCTL\r
+ MAX OF 2 RANKS : roundup (rcven 1x + 2x x 2 + PI/128) + 5\r
+\r
+\r
+ 2. need to do a fiforst after settings these values\r
+ */\r
+\r
+ DPF(D_INFO, "BEFORE\n");\r
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0LATCTL0));\r
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B01LATCTL1));\r
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0ONDURCTL));\r
+\r
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1LATCTL0));\r
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1ONDURCTL));\r
+\r
+ rcven = get_rcvn(0, 0, 0) / 128;\r
+ rdcmd2rcven = (isbR32m(DDRPHY, B0LATCTL0) >> 8) & 0x1F;\r
+ val = rdcmd2rcven + rcven + 6;\r
+ isbM32m(DDRPHY, B0LATCTL0, val << 16, (BIT21|BIT20|BIT19|BIT18|BIT17|BIT16));\r
+\r
+ val = rdcmd2rcven + rcven - 1;\r
+ isbM32m(DDRPHY, B01LATCTL1, val << 0, (BIT4|BIT3|BIT2|BIT1|BIT0));\r
+\r
+ val = rdcmd2rcven + rcven + 5;\r
+ isbM32m(DDRPHY, B0ONDURCTL, val << 8, (BIT13|BIT12|BIT11|BIT10|BIT9|BIT8));\r
+\r
+ rcven = get_rcvn(0, 0, 1) / 128;\r
+ rdcmd2rcven = (isbR32m(DDRPHY, B1LATCTL0) >> 8) & 0x1F;\r
+ val = rdcmd2rcven + rcven + 6;\r
+ isbM32m(DDRPHY, B1LATCTL0, val << 16, (BIT21|BIT20|BIT19|BIT18|BIT17|BIT16));\r
+\r
+ val = rdcmd2rcven + rcven - 1;\r
+ isbM32m(DDRPHY, B01LATCTL1, val << 16, (BIT20|BIT19|BIT18|BIT17|BIT16));\r
+\r
+ val = rdcmd2rcven + rcven + 5;\r
+ isbM32m(DDRPHY, B1ONDURCTL, val << 8, (BIT13|BIT12|BIT11|BIT10|BIT9|BIT8));\r
+\r
+ DPF(D_INFO, "AFTER\n");\r
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0LATCTL0));\r
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B01LATCTL1));\r
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0ONDURCTL));\r
+\r
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1LATCTL0));\r
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1ONDURCTL));\r
+\r
+ DPF(D_INFO, "\nPress a key\n");\r
+ mgetc();\r
+\r
+ // fifo reset\r
+ isbM32m(DDRPHY, B01PTRCTL1, 0, BIT8); // 0 is enabled\r
+ delay_n(3);\r
+ isbM32m(DDRPHY, B01PTRCTL1, BIT8, BIT8); // 1 is disabled\r
+ }\r
+#endif\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// Check memory executing write/read/verify of many data patterns\r
+// at the specified address. Bits in the result indicate failure\r
+// on specific byte lane.\r
+static uint32_t check_bls_ex(\r
+ MRCParams_t *mrc_params,\r
+ uint32_t address)\r
+{\r
+ uint32_t result;\r
+ uint8_t first_run = 0;\r
+\r
+ if (mrc_params->hte_setup)\r
+ {\r
+ mrc_params->hte_setup = 0;\r
+\r
+ first_run = 1;\r
+ select_hte(mrc_params);\r
+ }\r
+\r
+ result = WriteStressBitLanesHTE(mrc_params, address, first_run);\r
+\r
+ DPF(D_TRN, "check_bls_ex result is %x\n", result);\r
+ return result;\r
+}\r
+\r
+// Check memory executing simple write/read/verify at\r
+// the specified address. Bits in the result indicate failure\r
+// on specific byte lane.\r
+static uint32_t check_rw_coarse(\r
+ MRCParams_t *mrc_params,\r
+ uint32_t address)\r
+{\r
+ uint32_t result = 0;\r
+ uint8_t first_run = 0;\r
+\r
+ if (mrc_params->hte_setup)\r
+ {\r
+ mrc_params->hte_setup = 0;\r
+\r
+ first_run = 1;\r
+ select_hte(mrc_params);\r
+ }\r
+\r
+ result = BasicWriteReadHTE(mrc_params, address, first_run, WRITE_TRAIN);\r
+\r
+ DPF(D_TRN, "check_rw_coarse result is %x\n", result);\r
+ return result;\r
+}\r
+\r
+// wr_level:\r
+// POST_CODE[major] == 0x06\r
+//\r
+// This function will perform the Write Levelling algorithm (align WCLK and WDQS).\r
+// This algorithm will act on each rank in each channel separately.\r
+static void wr_level(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint8_t channel_i; // channel counter\r
+ uint8_t rank_i; // rank counter\r
+ uint8_t bl_i; // byte lane counter\r
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor\r
+\r
+#ifdef R2R_SHARING\r
+ uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs\r
+#ifndef BACKUP_WDQS\r
+ uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs\r
+#endif // BACKUP_WDQS\r
+#endif // R2R_SHARING\r
+\r
+#ifdef BACKUP_WDQS\r
+#else\r
+ bool all_edges_found; // determines stop condition for CRS_WR_LVL\r
+ uint32_t delay[NUM_BYTE_LANES]; // absolute PI value to be programmed on the byte lane\r
+ // static makes it so the data is loaded in the heap once by shadow(), where\r
+ // non-static copies the data onto the stack every time this function is called.\r
+\r
+ uint32_t address; // address to be checked during COARSE_WR_LVL\r
+ RegDTR4 dtr4;\r
+ RegDTR4 dtr4save;\r
+#endif // BACKUP_WDQS\r
+\r
+ ENTERFN();\r
+\r
+ // wr_level starts\r
+ post_code(0x06, 0x00);\r
+\r
+#ifdef R2R_SHARING\r
+ // need to set "final_delay[][]" elements to "0"\r
+ memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));\r
+#endif // R2R_SHARING\r
+ // loop through each enabled channel\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1 << channel_i))\r
+ {\r
+ // perform WRITE LEVELING algorithm on a per rank basis\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1 << rank_i))\r
+ {\r
+ // POST_CODE here indicates the current rank and channel being calibrated\r
+ post_code(0x06, (0x10 + ((channel_i << 4) | rank_i)));\r
+\r
+#ifdef BACKUP_WDQS\r
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)\r
+ {\r
+ set_wdqs(channel_i, rank_i, bl_i, ddr_wdqs[PLATFORM_ID]);\r
+ set_wdq(channel_i, rank_i, bl_i, (ddr_wdqs[PLATFORM_ID] - QRTR_CLK));\r
+ }\r
+#else\r
+\r
+ { // Begin product specific code\r
+\r
+ // perform a single PRECHARGE_ALL command to make DRAM state machine go to IDLE state\r
+ dram_init_command(DCMD_PREA(rank_i));\r
+\r
+ // enable Write Levelling Mode (EMRS1 w/ Write Levelling Mode Enable)\r
+ dram_init_command(DCMD_MRS1(rank_i,0x0082));\r
+\r
+ // set ODT DRAM Full Time Termination disable in MCU\r
+ dtr4.raw = dtr4save.raw = isbR32m(MCU, DTR4);\r
+ dtr4.field.ODTDIS = 1;\r
+ isbW32m(MCU, DTR4, dtr4.raw);\r
+\r
+ for (bl_i = 0; bl_i < ((NUM_BYTE_LANES / bl_divisor) / 2); bl_i++)\r
+ {\r
+ isbM32m(DDRPHY, DQCTL + (DDRIODQ_BL_OFFSET * bl_i) + (DDRIODQ_CH_OFFSET * channel_i),\r
+ (BIT28 | (0x1 << 8) | (0x1 << 6) | (0x1 << 4) | (0x1 << 2)),\r
+ (BIT28 | (BIT9|BIT8) | (BIT7|BIT6) | (BIT5|BIT4) | (BIT3|BIT2))); // Enable Sandy Bridge Mode (WDQ Tri-State) & Ensure 5 WDQS pulses during Write Leveling\r
+ }\r
+\r
+ isbM32m(DDRPHY, CCDDR3RESETCTL + (DDRIOCCC_CH_OFFSET * channel_i), (BIT16), (BIT16)); // Write Leveling Mode enabled in IO\r
+ } // End product specific code\r
+ // Initialise the starting delay to WCLK\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ { // Begin product specific code\r
+ // CLK0 --> RK0\r
+ // CLK1 --> RK1\r
+ delay[bl_i] = get_wclk(channel_i, rank_i);\r
+ } // End product specific code\r
+ set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]);\r
+ } // bl_i loop\r
+ // now find the rising edge\r
+ find_rising_edge(mrc_params, delay, channel_i, rank_i, false);\r
+ { // Begin product specific code\r
+ // disable Write Levelling Mode\r
+ isbM32m(DDRPHY, CCDDR3RESETCTL + (DDRIOCCC_CH_OFFSET * channel_i), (0), (BIT16)); // Write Leveling Mode disabled in IO\r
+\r
+ for (bl_i = 0; bl_i < ((NUM_BYTE_LANES / bl_divisor) / 2); bl_i++)\r
+ {\r
+ isbM32m(DDRPHY, DQCTL + (DDRIODQ_BL_OFFSET * bl_i) + (DDRIODQ_CH_OFFSET * channel_i),\r
+ ((0x1 << 8) | (0x1 << 6) | (0x1 << 4) | (0x1 << 2)),\r
+ (BIT28 | (BIT9|BIT8) | (BIT7|BIT6) | (BIT5|BIT4) | (BIT3|BIT2))); // Disable Sandy Bridge Mode & Ensure 4 WDQS pulses during normal operation\r
+ } // bl_i loop\r
+\r
+ // restore original DTR4\r
+ isbW32m(MCU, DTR4, dtr4save.raw);\r
+\r
+ // restore original value (Write Levelling Mode Disable)\r
+ dram_init_command(DCMD_MRS1(rank_i, mrc_params->mrs1));\r
+\r
+ // perform a single PRECHARGE_ALL command to make DRAM state machine go to IDLE state\r
+ dram_init_command(DCMD_PREA(rank_i));\r
+ } // End product specific code\r
+\r
+ post_code(0x06, (0x30 + ((channel_i << 4) | rank_i)));\r
+\r
+ // COARSE WRITE LEVEL:\r
+ // check that we're on the correct clock edge\r
+\r
+ // hte reconfiguration request\r
+ mrc_params->hte_setup = 1;\r
+\r
+ // start CRS_WR_LVL with WDQS = WDQS + 128 PI\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ delay[bl_i] = get_wdqs(channel_i, rank_i, bl_i) + FULL_CLK;\r
+ set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]);\r
+ // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI)\r
+ set_wdq(channel_i, rank_i, bl_i, (delay[bl_i] - QRTR_CLK));\r
+ } // bl_i loop\r
+\r
+ // get an address in the targeted channel/rank\r
+ address = get_addr(mrc_params, channel_i, rank_i);\r
+ do\r
+ {\r
+ uint32_t coarse_result = 0x00;\r
+ uint32_t coarse_result_mask = byte_lane_mask(mrc_params);\r
+ all_edges_found = true; // assume pass\r
+\r
+#ifdef SIM\r
+ // need restore memory to idle state as write can be in bad sync\r
+ dram_init_command (DCMD_PREA(rank_i));\r
+#endif\r
+\r
+ mrc_params->hte_setup = 1;\r
+ coarse_result = check_rw_coarse(mrc_params, address);\r
+\r
+ // check for failures and margin the byte lane back 128 PI (1 CLK)\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ if (coarse_result & (coarse_result_mask << bl_i))\r
+ {\r
+ all_edges_found = false;\r
+ delay[bl_i] -= FULL_CLK;\r
+ set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]);\r
+ // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI)\r
+ set_wdq(channel_i, rank_i, bl_i, (delay[bl_i] - QRTR_CLK));\r
+ }\r
+ } // bl_i loop\r
+\r
+ } while (!all_edges_found);\r
+\r
+#ifdef R2R_SHARING\r
+ // increment "num_ranks_enabled"\r
+ num_ranks_enabled++;\r
+ // accumulate "final_delay[][]" values from "delay[]" values for rolling average\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ final_delay[channel_i][bl_i] += delay[bl_i];\r
+ set_wdqs(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));\r
+ // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI)\r
+ set_wdq(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled) - QRTR_CLK);\r
+ } // bl_i loop\r
+#endif // R2R_SHARING\r
+#endif // BACKUP_WDQS\r
+\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// rd_train:\r
+// POST_CODE[major] == 0x07\r
+//\r
+// This function will perform the READ TRAINING Algorithm on all channels/ranks/byte_lanes simultaneously to minimize execution time.\r
+// The idea here is to train the VREF and RDQS (and eventually RDQ) values to achieve maximum READ margins.\r
+// The algorithm will first determine the X coordinate (RDQS setting).\r
+// This is done by collapsing the VREF eye until we find a minimum required RDQS eye for VREF_MIN and VREF_MAX.\r
+// 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.\r
+// The algorithm will then determine the Y coordinate (VREF setting).\r
+// This is done by collapsing the RDQS eye until we find a minimum required VREF eye for RDQS_MIN and RDQS_MAX.\r
+// 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.\r
+// 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.\r
+static void rd_train(\r
+ MRCParams_t *mrc_params)\r
+{\r
+\r
+#define MIN_RDQS_EYE 10 // in PI Codes\r
+#define MIN_VREF_EYE 10 // in VREF Codes\r
+#define RDQS_STEP 1 // how many RDQS codes to jump while margining\r
+#define VREF_STEP 1 // how many VREF codes to jump while margining\r
+#define VREF_MIN (0x00) // offset into "vref_codes[]" for minimum allowed VREF setting\r
+#define VREF_MAX (0x3F) // offset into "vref_codes[]" for maximum allowed VREF setting\r
+#define RDQS_MIN (0x00) // minimum RDQS delay value\r
+#define RDQS_MAX (0x3F) // maximum RDQS delay value\r
+#define B 0 // BOTTOM VREF\r
+#define T 1 // TOP VREF\r
+#define L 0 // LEFT RDQS\r
+#define R 1 // RIGHT RDQS\r
+\r
+ uint8_t channel_i; // channel counter\r
+ uint8_t rank_i; // rank counter\r
+ uint8_t bl_i; // byte lane counter\r
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor\r
+#ifdef BACKUP_RDQS\r
+#else\r
+ uint8_t side_x; // tracks LEFT/RIGHT approach vectors\r
+ uint8_t side_y; // tracks BOTTOM/TOP approach vectors\r
+ 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\r
+ uint8_t y_coordinate[2/*side_x*/][2/*side_y*/][NUM_CHANNELS][NUM_BYTE_LANES]; // Y coordinate data (passing VREF values) for approach vectors\r
+ uint8_t x_center[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; // centered X (RDQS)\r
+ uint8_t y_center[NUM_CHANNELS][NUM_BYTE_LANES]; // centered Y (VREF)\r
+ uint32_t address; // target address for "check_bls_ex()"\r
+ uint32_t result; // result of "check_bls_ex()"\r
+ uint32_t bl_mask; // byte lane mask for "result" checking\r
+#ifdef R2R_SHARING\r
+ uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs\r
+ uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs\r
+#endif // R2R_SHARING\r
+#endif // BACKUP_RDQS\r
+ // rd_train starts\r
+ post_code(0x07, 0x00);\r
+\r
+ ENTERFN();\r
+\r
+#ifdef BACKUP_RDQS\r
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1<<channel_i))\r
+ {\r
+ for (rank_i=0; rank_i<NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1<<rank_i))\r
+ {\r
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)\r
+ {\r
+ set_rdqs(channel_i, rank_i, bl_i, ddr_rdqs[PLATFORM_ID]);\r
+ } // bl_i loop\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+#else\r
+ // initialise x/y_coordinate arrays\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1 << channel_i))\r
+ {\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1 << rank_i))\r
+ {\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ // x_coordinate:\r
+ x_coordinate[L][B][channel_i][rank_i][bl_i] = RDQS_MIN;\r
+ x_coordinate[R][B][channel_i][rank_i][bl_i] = RDQS_MAX;\r
+ x_coordinate[L][T][channel_i][rank_i][bl_i] = RDQS_MIN;\r
+ x_coordinate[R][T][channel_i][rank_i][bl_i] = RDQS_MAX;\r
+ // y_coordinate:\r
+ y_coordinate[L][B][channel_i][bl_i] = VREF_MIN;\r
+ y_coordinate[R][B][channel_i][bl_i] = VREF_MIN;\r
+ y_coordinate[L][T][channel_i][bl_i] = VREF_MAX;\r
+ y_coordinate[R][T][channel_i][bl_i] = VREF_MAX;\r
+ } // bl_i loop\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+\r
+ // initialise other variables\r
+ bl_mask = byte_lane_mask(mrc_params);\r
+ address = get_addr(mrc_params, 0, 0);\r
+\r
+#ifdef R2R_SHARING\r
+ // need to set "final_delay[][]" elements to "0"\r
+ memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));\r
+#endif // R2R_SHARING\r
+\r
+ // look for passing coordinates\r
+ for (side_y = B; side_y <= T; side_y++)\r
+ {\r
+ for (side_x = L; side_x <= R; side_x++)\r
+ {\r
+\r
+ post_code(0x07, (0x10 + (side_y * 2) + (side_x)));\r
+\r
+ // find passing values\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (0x1 << channel_i))\r
+ {\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+\r
+ if (mrc_params->rank_enables & (0x1 << rank_i))\r
+ {\r
+ // set x/y_coordinate search starting settings\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ set_rdqs(channel_i, rank_i, bl_i, x_coordinate[side_x][side_y][channel_i][rank_i][bl_i]);\r
+ set_vref(channel_i, bl_i, y_coordinate[side_x][side_y][channel_i][bl_i]);\r
+ } // bl_i loop\r
+ // get an address in the target channel/rank\r
+ address = get_addr(mrc_params, channel_i, rank_i);\r
+\r
+ // request HTE reconfiguration\r
+ mrc_params->hte_setup = 1;\r
+\r
+ // test the settings\r
+ do\r
+ {\r
+\r
+ // result[07:00] == failing byte lane (MAX 8)\r
+ result = check_bls_ex( mrc_params, address);\r
+\r
+ // check for failures\r
+ if (result & 0xFF)\r
+ {\r
+ // at least 1 byte lane failed\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ if (result & (bl_mask << bl_i))\r
+ {\r
+ // adjust the RDQS values accordingly\r
+ if (side_x == L)\r
+ {\r
+ x_coordinate[L][side_y][channel_i][rank_i][bl_i] += RDQS_STEP;\r
+ }\r
+ else\r
+ {\r
+ x_coordinate[R][side_y][channel_i][rank_i][bl_i] -= RDQS_STEP;\r
+ }\r
+ // check that we haven't closed the RDQS_EYE too much\r
+ if ((x_coordinate[L][side_y][channel_i][rank_i][bl_i] > (RDQS_MAX - MIN_RDQS_EYE)) ||\r
+ (x_coordinate[R][side_y][channel_i][rank_i][bl_i] < (RDQS_MIN + MIN_RDQS_EYE))\r
+ ||\r
+ (x_coordinate[L][side_y][channel_i][rank_i][bl_i]\r
+ == x_coordinate[R][side_y][channel_i][rank_i][bl_i]))\r
+ {\r
+ // not enough RDQS margin available at this VREF\r
+ // update VREF values accordingly\r
+ if (side_y == B)\r
+ {\r
+ y_coordinate[side_x][B][channel_i][bl_i] += VREF_STEP;\r
+ }\r
+ else\r
+ {\r
+ y_coordinate[side_x][T][channel_i][bl_i] -= VREF_STEP;\r
+ }\r
+ // check that we haven't closed the VREF_EYE too much\r
+ if ((y_coordinate[side_x][B][channel_i][bl_i] > (VREF_MAX - MIN_VREF_EYE)) ||\r
+ (y_coordinate[side_x][T][channel_i][bl_i] < (VREF_MIN + MIN_VREF_EYE)) ||\r
+ (y_coordinate[side_x][B][channel_i][bl_i] == y_coordinate[side_x][T][channel_i][bl_i]))\r
+ {\r
+ // VREF_EYE collapsed below MIN_VREF_EYE\r
+ training_message(channel_i, rank_i, bl_i);\r
+ post_code(0xEE, (0x70 + (side_y * 2) + (side_x)));\r
+ }\r
+ else\r
+ {\r
+ // update the VREF setting\r
+ set_vref(channel_i, bl_i, y_coordinate[side_x][side_y][channel_i][bl_i]);\r
+ // reset the X coordinate to begin the search at the new VREF\r
+ x_coordinate[side_x][side_y][channel_i][rank_i][bl_i] =\r
+ (side_x == L) ? (RDQS_MIN) : (RDQS_MAX);\r
+ }\r
+ }\r
+ // update the RDQS setting\r
+ set_rdqs(channel_i, rank_i, bl_i, x_coordinate[side_x][side_y][channel_i][rank_i][bl_i]);\r
+ } // if bl_i failed\r
+ } // bl_i loop\r
+ } // at least 1 byte lane failed\r
+ } while (result & 0xFF);\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+ } // side_x loop\r
+ } // side_y loop\r
+\r
+ post_code(0x07, 0x20);\r
+\r
+ // find final RDQS (X coordinate) & final VREF (Y coordinate)\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1 << channel_i))\r
+ {\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1 << rank_i))\r
+ {\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ uint32_t tempD1;\r
+ uint32_t tempD2;\r
+\r
+ // x_coordinate:\r
+ DPF(D_INFO, "RDQS T/B eye rank%d lane%d : %d-%d %d-%d\n", rank_i, bl_i,\r
+ x_coordinate[L][T][channel_i][rank_i][bl_i],\r
+ x_coordinate[R][T][channel_i][rank_i][bl_i],\r
+ x_coordinate[L][B][channel_i][rank_i][bl_i],\r
+ x_coordinate[R][B][channel_i][rank_i][bl_i]);\r
+\r
+ 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\r
+ 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\r
+ x_center[channel_i][rank_i][bl_i] = (uint8_t) ((tempD1 + tempD2) / 2); // average the above averages\r
+\r
+ // y_coordinate:\r
+ DPF(D_INFO, "VREF R/L eye lane%d : %d-%d %d-%d\n", bl_i,\r
+ y_coordinate[R][B][channel_i][bl_i],\r
+ y_coordinate[R][T][channel_i][bl_i],\r
+ y_coordinate[L][B][channel_i][bl_i],\r
+ y_coordinate[L][T][channel_i][bl_i]);\r
+\r
+ 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\r
+ 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\r
+ y_center[channel_i][bl_i] = (uint8_t) ((tempD1 + tempD2) / 2); // average the above averages\r
+ } // bl_i loop\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+\r
+#ifdef RX_EYE_CHECK\r
+ // perform an eye check\r
+ for (side_y=B; side_y<=T; side_y++)\r
+ {\r
+ for (side_x=L; side_x<=R; side_x++)\r
+ {\r
+\r
+ post_code(0x07, (0x30 + (side_y * 2) + (side_x)));\r
+\r
+ // update the settings for the eye check\r
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1<<channel_i))\r
+ {\r
+ for (rank_i=0; rank_i<NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1<<rank_i))\r
+ {\r
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)\r
+ {\r
+ if (side_x == L)\r
+ {\r
+ set_rdqs(channel_i, rank_i, bl_i, (x_center[channel_i][rank_i][bl_i] - (MIN_RDQS_EYE / 2)));\r
+ }\r
+ else\r
+ {\r
+ set_rdqs(channel_i, rank_i, bl_i, (x_center[channel_i][rank_i][bl_i] + (MIN_RDQS_EYE / 2)));\r
+ }\r
+ if (side_y == B)\r
+ {\r
+ set_vref(channel_i, bl_i, (y_center[channel_i][bl_i] - (MIN_VREF_EYE / 2)));\r
+ }\r
+ else\r
+ {\r
+ set_vref(channel_i, bl_i, (y_center[channel_i][bl_i] + (MIN_VREF_EYE / 2)));\r
+ }\r
+ } // bl_i loop\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+\r
+ // request HTE reconfiguration\r
+ mrc_params->hte_setup = 1;\r
+\r
+ // check the eye\r
+ if (check_bls_ex( mrc_params, address) & 0xFF)\r
+ {\r
+ // one or more byte lanes failed\r
+ post_code(0xEE, (0x74 + (side_x * 2) + (side_y)));\r
+ }\r
+ } // side_x loop\r
+ } // side_y loop\r
+#endif // RX_EYE_CHECK\r
+\r
+ post_code(0x07, 0x40);\r
+\r
+ // set final placements\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1 << channel_i))\r
+ {\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1 << rank_i))\r
+ {\r
+#ifdef R2R_SHARING\r
+ // increment "num_ranks_enabled"\r
+ num_ranks_enabled++;\r
+#endif // R2R_SHARING\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ // x_coordinate:\r
+#ifdef R2R_SHARING\r
+ final_delay[channel_i][bl_i] += x_center[channel_i][rank_i][bl_i];\r
+ set_rdqs(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));\r
+#else\r
+ set_rdqs(channel_i, rank_i, bl_i, x_center[channel_i][rank_i][bl_i]);\r
+#endif // R2R_SHARING\r
+ // y_coordinate:\r
+ set_vref(channel_i, bl_i, y_center[channel_i][bl_i]);\r
+ } // bl_i loop\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+#endif // BACKUP_RDQS\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// wr_train:\r
+// POST_CODE[major] == 0x08\r
+//\r
+// This function will perform the WRITE TRAINING Algorithm on all channels/ranks/byte_lanes simultaneously to minimize execution time.\r
+// The idea here is to train the WDQ timings to achieve maximum WRITE margins.\r
+// 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.\r
+// 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.\r
+static void wr_train(\r
+ MRCParams_t *mrc_params)\r
+{\r
+\r
+#define WDQ_STEP 1 // how many WDQ codes to jump while margining\r
+#define L 0 // LEFT side loop value definition\r
+#define R 1 // RIGHT side loop value definition\r
+\r
+ uint8_t channel_i; // channel counter\r
+ uint8_t rank_i; // rank counter\r
+ uint8_t bl_i; // byte lane counter\r
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor\r
+#ifdef BACKUP_WDQ\r
+#else\r
+ uint8_t side_i; // LEFT/RIGHT side indicator (0=L, 1=R)\r
+ uint32_t tempD; // temporary DWORD\r
+ uint32_t delay[2/*side_i*/][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; // 2 arrays, for L & R side passing delays\r
+ uint32_t address; // target address for "check_bls_ex()"\r
+ uint32_t result; // result of "check_bls_ex()"\r
+ uint32_t bl_mask; // byte lane mask for "result" checking\r
+#ifdef R2R_SHARING\r
+ uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs\r
+ uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs\r
+#endif // R2R_SHARING\r
+#endif // BACKUP_WDQ\r
+\r
+ // wr_train starts\r
+ post_code(0x08, 0x00);\r
+\r
+ ENTERFN();\r
+\r
+#ifdef BACKUP_WDQ\r
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1<<channel_i))\r
+ {\r
+ for (rank_i=0; rank_i<NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1<<rank_i))\r
+ {\r
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)\r
+ {\r
+ set_wdq(channel_i, rank_i, bl_i, ddr_wdq[PLATFORM_ID]);\r
+ } // bl_i loop\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+#else\r
+ // initialise "delay"\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1 << channel_i))\r
+ {\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1 << rank_i))\r
+ {\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ // want to start with WDQ = (WDQS - QRTR_CLK) +/- QRTR_CLK\r
+ tempD = get_wdqs(channel_i, rank_i, bl_i) - QRTR_CLK;\r
+ delay[L][channel_i][rank_i][bl_i] = tempD - QRTR_CLK;\r
+ delay[R][channel_i][rank_i][bl_i] = tempD + QRTR_CLK;\r
+ } // bl_i loop\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+\r
+ // initialise other variables\r
+ bl_mask = byte_lane_mask(mrc_params);\r
+ address = get_addr(mrc_params, 0, 0);\r
+\r
+#ifdef R2R_SHARING\r
+ // need to set "final_delay[][]" elements to "0"\r
+ memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));\r
+#endif // R2R_SHARING\r
+\r
+ // start algorithm on the LEFT side and train each channel/bl until no failures are observed, then repeat for the RIGHT side.\r
+ for (side_i = L; side_i <= R; side_i++)\r
+ {\r
+ post_code(0x08, (0x10 + (side_i)));\r
+\r
+ // set starting values\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1 << channel_i))\r
+ {\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1 << rank_i))\r
+ {\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ set_wdq(channel_i, rank_i, bl_i, delay[side_i][channel_i][rank_i][bl_i]);\r
+ } // bl_i loop\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+\r
+ // find passing values\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (0x1 << channel_i))\r
+ {\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (0x1 << rank_i))\r
+ {\r
+ // get an address in the target channel/rank\r
+ address = get_addr(mrc_params, channel_i, rank_i);\r
+\r
+ // request HTE reconfiguration\r
+ mrc_params->hte_setup = 1;\r
+\r
+ // check the settings\r
+ do\r
+ {\r
+\r
+#ifdef SIM\r
+ // need restore memory to idle state as write can be in bad sync\r
+ dram_init_command (DCMD_PREA(rank_i));\r
+#endif\r
+\r
+ // result[07:00] == failing byte lane (MAX 8)\r
+ result = check_bls_ex( mrc_params, address);\r
+ // check for failures\r
+ if (result & 0xFF)\r
+ {\r
+ // at least 1 byte lane failed\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ if (result & (bl_mask << bl_i))\r
+ {\r
+ if (side_i == L)\r
+ {\r
+ delay[L][channel_i][rank_i][bl_i] += WDQ_STEP;\r
+ }\r
+ else\r
+ {\r
+ delay[R][channel_i][rank_i][bl_i] -= WDQ_STEP;\r
+ }\r
+ // check for algorithm failure\r
+ if (delay[L][channel_i][rank_i][bl_i] != delay[R][channel_i][rank_i][bl_i])\r
+ {\r
+ // margin available, update delay setting\r
+ set_wdq(channel_i, rank_i, bl_i, delay[side_i][channel_i][rank_i][bl_i]);\r
+ }\r
+ else\r
+ {\r
+ // no margin available, notify the user and halt\r
+ training_message(channel_i, rank_i, bl_i);\r
+ post_code(0xEE, (0x80 + side_i));\r
+ }\r
+ } // if bl_i failed\r
+ } // bl_i loop\r
+ } // at least 1 byte lane failed\r
+ } while (result & 0xFF); // stop when all byte lanes pass\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+ } // side_i loop\r
+\r
+ // program WDQ to the middle of passing window\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1 << channel_i))\r
+ {\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1 << rank_i))\r
+ {\r
+#ifdef R2R_SHARING\r
+ // increment "num_ranks_enabled"\r
+ num_ranks_enabled++;\r
+#endif // R2R_SHARING\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+\r
+ DPF(D_INFO, "WDQ eye rank%d lane%d : %d-%d\n", rank_i, bl_i,\r
+ delay[L][channel_i][rank_i][bl_i],\r
+ delay[R][channel_i][rank_i][bl_i]);\r
+\r
+ tempD = (delay[R][channel_i][rank_i][bl_i] + delay[L][channel_i][rank_i][bl_i]) / 2;\r
+\r
+#ifdef R2R_SHARING\r
+ final_delay[channel_i][bl_i] += tempD;\r
+ set_wdq(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));\r
+#else\r
+ set_wdq(channel_i, rank_i, bl_i, tempD);\r
+#endif // R2R_SHARING\r
+\r
+ } // bl_i loop\r
+ } // if rank is enabled\r
+ } // rank_i loop\r
+ } // if channel is enabled\r
+ } // channel_i loop\r
+#endif // BACKUP_WDQ\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// Wrapper for jedec initialisation routine\r
+static void perform_jedec_init(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ jedec_init(mrc_params, 0);\r
+}\r
+\r
+// Configure DDRPHY for Auto-Refresh, Periodic Compensations,\r
+// Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down\r
+static void set_auto_refresh(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint32_t channel_i;\r
+ uint32_t rank_i;\r
+ uint32_t bl_i;\r
+ uint32_t bl_divisor = /*(mrc_params->channel_width==x16)?2:*/1;\r
+ uint32_t tempD;\r
+\r
+ ENTERFN();\r
+\r
+ // enable Auto-Refresh, Periodic Compensations, Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1 << channel_i))\r
+ {\r
+ // Enable Periodic RCOMPS\r
+ isbM32m(DDRPHY, CMPCTRL, (BIT1), (BIT1));\r
+\r
+\r
+ // Enable Dynamic DiffAmp & Set Read ODT Value\r
+ switch (mrc_params->rd_odt_value)\r
+ {\r
+ case 0: tempD = 0x3F; break; // OFF\r
+ default: tempD = 0x00; break; // Auto\r
+ } // rd_odt_value switch\r
+\r
+ for (bl_i=0; bl_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_i++)\r
+ {\r
+ isbM32m(DDRPHY, (B0OVRCTL + (bl_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)),\r
+ ((0x00<<16)|(tempD<<10)),\r
+ ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10))); // Override: DIFFAMP, ODT\r
+\r
+ isbM32m(DDRPHY, (B1OVRCTL + (bl_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)),\r
+ ((0x00<<16)|(tempD<<10)),\r
+ ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10)));// Override: DIFFAMP, ODT\r
+ } // bl_i loop\r
+\r
+ // Issue ZQCS command\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1 << rank_i))\r
+ {\r
+ dram_init_command(DCMD_ZQCS(rank_i));\r
+ } // if rank_i enabled\r
+ } // rank_i loop\r
+\r
+ } // if channel_i enabled\r
+ } // channel_i loop\r
+\r
+ clear_pointers();\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// Depending on configuration enables ECC support.\r
+// Available memory size is decresed, and updated with 0s\r
+// in order to clear error status. Address mode 2 forced.\r
+static void ecc_enable(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ RegDRP Drp;\r
+ RegDSCH Dsch;\r
+ RegDECCCTRL Ctr;\r
+\r
+ if (mrc_params->ecc_enables == 0) return;\r
+\r
+ ENTERFN();\r
+\r
+ // Configuration required in ECC mode\r
+ Drp.raw = isbR32m(MCU, DRP);\r
+ Drp.field.addressMap = 2;\r
+ Drp.field.split64 = 1;\r
+ isbW32m(MCU, DRP, Drp.raw);\r
+\r
+ // Disable new request bypass\r
+ Dsch.raw = isbR32m(MCU, DSCH);\r
+ Dsch.field.NEWBYPDIS = 1;\r
+ isbW32m(MCU, DSCH, Dsch.raw);\r
+\r
+ // Enable ECC\r
+ Ctr.raw = 0;\r
+ Ctr.field.SBEEN = 1;\r
+ Ctr.field.DBEEN = 1;\r
+ Ctr.field.ENCBGEN = 1;\r
+ isbW32m(MCU, DECCCTRL, Ctr.raw);\r
+\r
+#ifdef SIM\r
+ // Read back to be sure writing took place\r
+ Ctr.raw = isbR32m(MCU, DECCCTRL);\r
+#endif\r
+\r
+ // Assume 8 bank memory, one bank is gone for ECC\r
+ mrc_params->mem_size -= mrc_params->mem_size / 8;\r
+\r
+ // For S3 resume memory content has to be preserved\r
+ if (mrc_params->boot_mode != bmS3)\r
+ {\r
+ select_hte(mrc_params);\r
+ HteMemInit(mrc_params, MrcMemInit, MrcHaltHteEngineOnError);\r
+ select_memory_manager(mrc_params);\r
+ }\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// Lock MCU registers at the end of initialisation sequence.\r
+static void lock_registers(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ RegDCO Dco;\r
+\r
+ ENTERFN();\r
+\r
+ Dco.raw = isbR32m(MCU, DCO);\r
+ Dco.field.PMIDIS = 0; //0 - PRI enabled\r
+ Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER\r
+ Dco.field.DRPLOCK = 1;\r
+ Dco.field.REUTLOCK = 1;\r
+ isbW32m(MCU, DCO, Dco.raw);\r
+\r
+ LEAVEFN();\r
+\r
+}\r
+\r
+#ifdef MRC_SV\r
+\r
+// cache write back invalidate\r
+static void asm_wbinvd(void)\r
+{\r
+#if defined (SIM) || defined (GCC)\r
+ asm(\r
+ "wbinvd;"\r
+ );\r
+#else\r
+ __asm wbinvd;\r
+#endif\r
+}\r
+\r
+// cache invalidate\r
+static void asm_invd(void)\r
+{\r
+#if defined (SIM) || defined (GCC)\r
+ asm(\r
+ "invd;"\r
+ );\r
+#else\r
+ __asm invd;\r
+#endif\r
+}\r
+\r
+\r
+static void cpu_read(void)\r
+{\r
+ uint32_t adr, dat, limit;\r
+\r
+ asm_invd();\r
+\r
+ limit = 8 * 1024;\r
+ for (adr = 0; adr < limit; adr += 4)\r
+ {\r
+ dat = *(uint32_t*) adr;\r
+ if ((adr & 0x0F) == 0)\r
+ {\r
+ DPF(D_INFO, "\n%x : ", adr);\r
+ }\r
+ DPF(D_INFO, "%x ", dat);\r
+ }\r
+ DPF(D_INFO, "\n");\r
+\r
+ DPF(D_INFO, "CPU read done\n");\r
+}\r
+\r
+\r
+static void cpu_write(void)\r
+{\r
+ uint32_t adr, limit;\r
+\r
+ limit = 8 * 1024;\r
+ for (adr = 0; adr < limit; adr += 4)\r
+ {\r
+ *(uint32_t*) adr = 0xDEAD0000 + adr;\r
+ }\r
+\r
+ asm_wbinvd();\r
+\r
+ DPF(D_INFO, "CPU write done\n");\r
+}\r
+\r
+\r
+static void cpu_memory_test(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint32_t result = 0;\r
+ uint32_t val, dat, adr, adr0, step, limit;\r
+ uint64_t my_tsc;\r
+\r
+ ENTERFN();\r
+\r
+ asm_invd();\r
+\r
+ adr0 = 1 * 1024 * 1024;\r
+ limit = 256 * 1024 * 1024;\r
+\r
+ for (step = 0; step <= 4; step++)\r
+ {\r
+ DPF(D_INFO, "Mem test step %d starting from %xh\n", step, adr0);\r
+\r
+ my_tsc = read_tsc();\r
+ for (adr = adr0; adr < limit; adr += sizeof(uint32_t))\r
+ {\r
+ if (step == 0) dat = adr;\r
+ else if (step == 1) dat = (1 << ((adr >> 2) & 0x1f));\r
+ else if (step == 2) dat = ~(1 << ((adr >> 2) & 0x1f));\r
+ else if (step == 3) dat = 0x5555AAAA;\r
+ else if (step == 4) dat = 0xAAAA5555;\r
+\r
+ *(uint32_t*) adr = dat;\r
+ }\r
+ DPF(D_INFO, "Write time %llXh\n", read_tsc() - my_tsc);\r
+\r
+ my_tsc = read_tsc();\r
+ for (adr = adr0; adr < limit; adr += sizeof(uint32_t))\r
+ {\r
+ if (step == 0) dat = adr;\r
+ else if (step == 1) dat = (1 << ((adr >> 2) & 0x1f));\r
+ else if (step == 2) dat = ~(1 << ((adr >> 2) & 0x1f));\r
+ else if (step == 3) dat = 0x5555AAAA;\r
+ else if (step == 4) dat = 0xAAAA5555;\r
+\r
+ val = *(uint32_t*) adr;\r
+\r
+ if (val != dat)\r
+ {\r
+ DPF(D_INFO, "%x vs. %x@%x\n", dat, val, adr);\r
+ result = adr|BIT31;\r
+ }\r
+ }\r
+ DPF(D_INFO, "Read time %llXh\n", read_tsc() - my_tsc);\r
+ }\r
+\r
+ DPF( D_INFO, "Memory test result %x\n", result);\r
+ LEAVEFN();\r
+}\r
+#endif // MRC_SV\r
+\r
+\r
+// Execute memory test, if error dtected it is\r
+// indicated in mrc_params->status.\r
+static void memory_test(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint32_t result = 0;\r
+\r
+ ENTERFN();\r
+\r
+ select_hte(mrc_params);\r
+ result = HteMemInit(mrc_params, MrcMemTest, MrcHaltHteEngineOnError);\r
+ select_memory_manager(mrc_params);\r
+\r
+ DPF(D_INFO, "Memory test result %x\n", result);\r
+ mrc_params->status = ((result == 0) ? MRC_SUCCESS : MRC_E_MEMTEST);\r
+ LEAVEFN();\r
+}\r
+\r
+\r
+// Force same timings as with backup settings\r
+static void static_timings(\r
+ MRCParams_t *mrc_params)\r
+\r
+{\r
+ uint8_t ch, rk, bl;\r
+\r
+ for (ch = 0; ch < NUM_CHANNELS; ch++)\r
+ {\r
+ for (rk = 0; rk < NUM_RANKS; rk++)\r
+ {\r
+ for (bl = 0; bl < NUM_BYTE_LANES; bl++)\r
+ {\r
+ set_rcvn(ch, rk, bl, 498); // RCVN\r
+ set_rdqs(ch, rk, bl, 24); // RDQS\r
+ set_wdqs(ch, rk, bl, 292); // WDQS\r
+ set_wdq( ch, rk, bl, 260); // WDQ\r
+ if (rk == 0)\r
+ {\r
+ set_vref(ch, bl, 32); // VREF (RANK0 only)\r
+ }\r
+ }\r
+ set_wctl(ch, rk, 217); // WCTL\r
+ }\r
+ set_wcmd(ch, 220); // WCMD\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+//\r
+// Initialise system memory.\r
+//\r
+void MemInit(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ static const MemInit_t init[] =\r
+ {\r
+ { 0x0101, bmCold|bmFast|bmWarm|bmS3, clear_self_refresh }, //0\r
+ { 0x0200, bmCold|bmFast|bmWarm|bmS3, prog_ddr_timing_control }, //1 initialise the MCU\r
+ { 0x0103, bmCold|bmFast , prog_decode_before_jedec }, //2\r
+ { 0x0104, bmCold|bmFast , perform_ddr_reset }, //3\r
+ { 0x0300, bmCold|bmFast |bmS3, ddrphy_init }, //4 initialise the DDRPHY\r
+ { 0x0400, bmCold|bmFast , perform_jedec_init }, //5 perform JEDEC initialisation of DRAMs\r
+ { 0x0105, bmCold|bmFast , set_ddr_init_complete }, //6\r
+ { 0x0106, bmFast|bmWarm|bmS3, restore_timings }, //7\r
+ { 0x0106, bmCold , default_timings }, //8\r
+ { 0x0500, bmCold , rcvn_cal }, //9 perform RCVN_CAL algorithm\r
+ { 0x0600, bmCold , wr_level }, //10 perform WR_LEVEL algorithm\r
+ { 0x0120, bmCold , prog_page_ctrl }, //11\r
+ { 0x0700, bmCold , rd_train }, //12 perform RD_TRAIN algorithm\r
+ { 0x0800, bmCold , wr_train }, //13 perform WR_TRAIN algorithm\r
+ { 0x010B, bmCold , store_timings }, //14\r
+ { 0x010C, bmCold|bmFast|bmWarm|bmS3, enable_scrambling }, //15\r
+ { 0x010D, bmCold|bmFast|bmWarm|bmS3, prog_ddr_control }, //16\r
+ { 0x010E, bmCold|bmFast|bmWarm|bmS3, prog_dra_drb }, //17\r
+ { 0x010F, bmWarm|bmS3, perform_wake }, //18\r
+ { 0x0110, bmCold|bmFast|bmWarm|bmS3, change_refresh_period }, //19\r
+ { 0x0111, bmCold|bmFast|bmWarm|bmS3, set_auto_refresh }, //20\r
+ { 0x0112, bmCold|bmFast|bmWarm|bmS3, ecc_enable }, //21\r
+ { 0x0113, bmCold|bmFast , memory_test }, //22\r
+ { 0x0114, bmCold|bmFast|bmWarm|bmS3, lock_registers } //23 set init done\r
+ };\r
+\r
+ uint32_t i;\r
+\r
+ ENTERFN();\r
+\r
+ DPF(D_INFO, "Meminit build %s %s\n", __DATE__, __TIME__);\r
+\r
+ // MRC started\r
+ post_code(0x01, 0x00);\r
+\r
+ if (mrc_params->boot_mode != bmCold)\r
+ {\r
+ if (mrc_params->ddr_speed != mrc_params->timings.ddr_speed)\r
+ {\r
+ // full training required as frequency changed\r
+ mrc_params->boot_mode = bmCold;\r
+ }\r
+ }\r
+\r
+ for (i = 0; i < MCOUNT(init); i++)\r
+ {\r
+ uint64_t my_tsc;\r
+\r
+#ifdef MRC_SV\r
+ if (mrc_params->menu_after_mrc && i > 14)\r
+ {\r
+ uint8_t ch;\r
+\r
+ mylop:\r
+\r
+ DPF(D_INFO, "-- c - continue --\n");\r
+ DPF(D_INFO, "-- j - move to jedec init --\n");\r
+ DPF(D_INFO, "-- m - memory test --\n");\r
+ DPF(D_INFO, "-- r - cpu read --\n");\r
+ DPF(D_INFO, "-- w - cpu write --\n");\r
+ DPF(D_INFO, "-- b - hte base test --\n");\r
+ DPF(D_INFO, "-- g - hte extended test --\n");\r
+\r
+ ch = mgetc();\r
+ switch (ch)\r
+ {\r
+ case 'c':\r
+ break;\r
+ case 'j': //move to jedec init\r
+ i = 5;\r
+ break;\r
+\r
+ case 'M':\r
+ case 'N':\r
+ {\r
+ uint32_t n, res, cnt=0;\r
+\r
+ for(n=0; mgetch()==0; n++)\r
+ {\r
+ if( ch == 'M' || n % 256 == 0)\r
+ {\r
+ DPF(D_INFO, "n=%d e=%d\n", n, cnt);\r
+ }\r
+\r
+ res = 0;\r
+\r
+ if( ch == 'M')\r
+ {\r
+ memory_test(mrc_params);\r
+ res |= mrc_params->status;\r
+ }\r
+\r
+ mrc_params->hte_setup = 1;\r
+ res |= check_bls_ex(mrc_params, 0x00000000);\r
+ res |= check_bls_ex(mrc_params, 0x00000000);\r
+ res |= check_bls_ex(mrc_params, 0x00000000);\r
+ res |= check_bls_ex(mrc_params, 0x00000000);\r
+\r
+ if( mrc_params->rank_enables & 2)\r
+ {\r
+ mrc_params->hte_setup = 1;\r
+ res |= check_bls_ex(mrc_params, 0x40000000);\r
+ res |= check_bls_ex(mrc_params, 0x40000000);\r
+ res |= check_bls_ex(mrc_params, 0x40000000);\r
+ res |= check_bls_ex(mrc_params, 0x40000000);\r
+ }\r
+\r
+ if( res != 0)\r
+ {\r
+ DPF(D_INFO, "###########\n");\r
+ DPF(D_INFO, "#\n");\r
+ DPF(D_INFO, "# Error count %d\n", ++cnt);\r
+ DPF(D_INFO, "#\n");\r
+ DPF(D_INFO, "###########\n");\r
+ }\r
+\r
+ } // for\r
+\r
+ select_memory_manager(mrc_params);\r
+ }\r
+ goto mylop;\r
+ case 'm':\r
+ memory_test(mrc_params);\r
+ goto mylop;\r
+ case 'n':\r
+ cpu_memory_test(mrc_params);\r
+ goto mylop;\r
+\r
+ case 'l':\r
+ ch = mgetc();\r
+ if (ch <= '9') DpfPrintMask ^= (ch - '0') << 3;\r
+ DPF(D_INFO, "Log mask %x\n", DpfPrintMask);\r
+ goto mylop;\r
+ case 'p':\r
+ print_timings(mrc_params);\r
+ goto mylop;\r
+ case 'R':\r
+ rd_train(mrc_params);\r
+ goto mylop;\r
+ case 'W':\r
+ wr_train(mrc_params);\r
+ goto mylop;\r
+\r
+ case 'r':\r
+ cpu_read();\r
+ goto mylop;\r
+ case 'w':\r
+ cpu_write();\r
+ goto mylop;\r
+\r
+ case 'g':\r
+ {\r
+ uint32_t result;\r
+ select_hte(mrc_params);\r
+ mrc_params->hte_setup = 1;\r
+ result = check_bls_ex(mrc_params, 0);\r
+ DPF(D_INFO, "Extended test result %x\n", result);\r
+ select_memory_manager(mrc_params);\r
+ }\r
+ goto mylop;\r
+ case 'b':\r
+ {\r
+ uint32_t result;\r
+ select_hte(mrc_params);\r
+ mrc_params->hte_setup = 1;\r
+ result = check_rw_coarse(mrc_params, 0);\r
+ DPF(D_INFO, "Base test result %x\n", result);\r
+ select_memory_manager(mrc_params);\r
+ }\r
+ goto mylop;\r
+ case 'B':\r
+ select_hte(mrc_params);\r
+ HteMemOp(0x2340, 1, 1);\r
+ select_memory_manager(mrc_params);\r
+ goto mylop;\r
+\r
+ case '3':\r
+ {\r
+ RegDPMC0 DPMC0reg;\r
+\r
+ DPF( D_INFO, "===>> Start suspend\n");\r
+ isbR32m(MCU, DSTAT);\r
+\r
+ DPMC0reg.raw = isbR32m(MCU, DPMC0);\r
+ DPMC0reg.field.DYNSREN = 0;\r
+ DPMC0reg.field.powerModeOpCode = 0x05; // Disable Master DLL\r
+ isbW32m(MCU, DPMC0, DPMC0reg.raw);\r
+\r
+ // Should be off for negative test case verification\r
+ #if 1\r
+ Wr32(MMIO, PCIADDR(0,0,0,SB_PACKET_REG),\r
+ (uint32_t)SB_COMMAND(SB_SUSPEND_CMND_OPCODE, MCU, 0));\r
+ #endif\r
+\r
+ DPF( D_INFO, "press key\n");\r
+ mgetc();\r
+ DPF( D_INFO, "===>> Start resume\n");\r
+ isbR32m(MCU, DSTAT);\r
+\r
+ mrc_params->boot_mode = bmS3;\r
+ i = 0;\r
+ }\r
+\r
+ } // switch\r
+\r
+ } // if( menu\r
+#endif //MRC_SV\r
+\r
+ if (mrc_params->boot_mode & init[i].boot_path)\r
+ {\r
+ uint8_t major = init[i].post_code >> 8 & 0xFF;\r
+ uint8_t minor = init[i].post_code >> 0 & 0xFF;\r
+ post_code(major, minor);\r
+\r
+ my_tsc = read_tsc();\r
+ init[i].init_fn(mrc_params);\r
+ DPF(D_TIME, "Execution time %llX", read_tsc() - my_tsc);\r
+ }\r
+ }\r
+\r
+ // display the timings\r
+ print_timings(mrc_params);\r
+\r
+ // MRC is complete.\r
+ post_code(0x01, 0xFF);\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
--- /dev/null
+/************************************************************************\r
+ *\r
+ * Copyright (c) 2013-2015 Intel Corporation.\r
+ *\r
+* This program and the accompanying materials\r
+* are licensed and made available under the terms and conditions of the BSD License\r
+* which accompanies this distribution. The full text of the license may be found at\r
+* http://opensource.org/licenses/bsd-license.php\r
+*\r
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ *\r
+ ************************************************************************/\r
+#ifndef _MEMINIT_H_\r
+#define _MEMINIT_H_\r
+\r
+// function prototypes\r
+void MemInit(MRCParams_t *mrc_params);\r
+\r
+typedef void (*MemInitFn_t)(MRCParams_t *mrc_params);\r
+\r
+typedef struct MemInit_s {\r
+ uint16_t post_code;\r
+ uint16_t boot_path;\r
+ MemInitFn_t init_fn;\r
+} MemInit_t;\r
+\r
+#endif // _MEMINIT_H_\r
--- /dev/null
+/************************************************************************\r
+ *\r
+ * Copyright (c) 2013-2015 Intel Corporation.\r
+ *\r
+* This program and the accompanying materials\r
+* are licensed and made available under the terms and conditions of the BSD License\r
+* which accompanies this distribution. The full text of the license may be found at\r
+* http://opensource.org/licenses/bsd-license.php\r
+*\r
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ *\r
+ ***************************************************************************/\r
+\r
+#include "mrc.h"\r
+#include "memory_options.h"\r
+\r
+#include "meminit_utils.h"\r
+#include "hte.h"\r
+#include "io.h"\r
+\r
+void select_hte(\r
+ MRCParams_t *mrc_params);\r
+\r
+static uint8_t first_run = 0;\r
+\r
+const uint8_t vref_codes[64] =\r
+{ // lowest to highest\r
+ 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, // 00 - 15\r
+ 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, // 16 - 31\r
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 32 - 47\r
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F // 48 - 63\r
+};\r
+\r
+#ifdef EMU\r
+// Track current post code for debugging purpose\r
+uint32_t PostCode;\r
+#endif\r
+\r
+// set_rcvn:\r
+//\r
+// This function will program the RCVEN delays.\r
+// (currently doesn't comprehend rank)\r
+void set_rcvn(\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ uint8_t byte_lane,\r
+ uint32_t pi_count)\r
+{\r
+ uint32_t reg;\r
+ uint32_t msk;\r
+ uint32_t tempD;\r
+\r
+ ENTERFN();\r
+ DPF(D_TRN, "Rcvn ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);\r
+\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // BL0 -> B01PTRCTL0[11:08] (0x0-0xF)\r
+ // BL1 -> B01PTRCTL0[23:20] (0x0-0xF)\r
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);\r
+ msk = (byte_lane & BIT0) ? (BIT23 | BIT22 | BIT21 | BIT20) : (BIT11 | BIT10 | BIT9 | BIT8);\r
+ tempD = (byte_lane & BIT0) ? ((pi_count / HALF_CLK) << 20) : ((pi_count / HALF_CLK) << 8);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)\r
+ // BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)\r
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);\r
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));\r
+ msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24);\r
+ tempD = pi_count << 24;\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // DEADBAND\r
+ // BL0/1 -> B01DBCTL1[08/11] (+1 select)\r
+ // BL0/1 -> B01DBCTL1[02/05] (enable)\r
+ reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);\r
+ msk = 0x00;\r
+ tempD = 0x00;\r
+ // enable\r
+ msk |= (byte_lane & BIT0) ? (BIT5) : (BIT2);\r
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ // select\r
+ msk |= (byte_lane & BIT0) ? (BIT11) : (BIT8);\r
+ if (pi_count < EARLY_DB)\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // error check\r
+ if (pi_count > 0x3F)\r
+ {\r
+ training_message(channel, rank, byte_lane);\r
+ post_code(0xEE, 0xE0);\r
+ }\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// get_rcvn:\r
+//\r
+// This function will return the current RCVEN delay on the given channel, rank, byte_lane as an absolute PI count.\r
+// (currently doesn't comprehend rank)\r
+uint32_t get_rcvn(\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ uint8_t byte_lane)\r
+{\r
+ uint32_t reg;\r
+ uint32_t tempD;\r
+ uint32_t pi_count;\r
+\r
+ ENTERFN();\r
+\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // BL0 -> B01PTRCTL0[11:08] (0x0-0xF)\r
+ // BL1 -> B01PTRCTL0[23:20] (0x0-0xF)\r
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= (byte_lane & BIT0) ? (20) : (8);\r
+ tempD &= 0xF;\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count = tempD * HALF_CLK;\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)\r
+ // BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)\r
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);\r
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= 24;\r
+ tempD &= 0x3F;\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count += tempD;\r
+\r
+ LEAVEFN();\r
+ return pi_count;\r
+}\r
+\r
+// set_rdqs:\r
+//\r
+// This function will program the RDQS delays based on an absolute amount of PIs.\r
+// (currently doesn't comprehend rank)\r
+void set_rdqs(\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ uint8_t byte_lane,\r
+ uint32_t pi_count)\r
+{\r
+ uint32_t reg;\r
+ uint32_t msk;\r
+ uint32_t tempD;\r
+\r
+ ENTERFN();\r
+ DPF(D_TRN, "Rdqs ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);\r
+\r
+ // PI (1/128 MCLK)\r
+ // BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)\r
+ // BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)\r
+ reg = (byte_lane & BIT0) ? (B1RXDQSPICODE) : (B0RXDQSPICODE);\r
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));\r
+ msk = (BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0);\r
+ tempD = pi_count << 0;\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // error check (shouldn't go above 0x3F)\r
+ if (pi_count > 0x47)\r
+ {\r
+ training_message(channel, rank, byte_lane);\r
+ post_code(0xEE, 0xE1);\r
+ }\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// get_rdqs:\r
+//\r
+// This function will return the current RDQS delay on the given channel, rank, byte_lane as an absolute PI count.\r
+// (currently doesn't comprehend rank)\r
+uint32_t get_rdqs(\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ uint8_t byte_lane)\r
+{\r
+ uint32_t reg;\r
+ uint32_t tempD;\r
+ uint32_t pi_count;\r
+\r
+ ENTERFN();\r
+\r
+ // PI (1/128 MCLK)\r
+ // BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)\r
+ // BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)\r
+ reg = (byte_lane & BIT0) ? (B1RXDQSPICODE) : (B0RXDQSPICODE);\r
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));\r
+ tempD = isbR32m(DDRPHY, reg);\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count = tempD & 0x7F;\r
+\r
+ LEAVEFN();\r
+ return pi_count;\r
+}\r
+\r
+// set_wdqs:\r
+//\r
+// This function will program the WDQS delays based on an absolute amount of PIs.\r
+// (currently doesn't comprehend rank)\r
+void set_wdqs(\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ uint8_t byte_lane,\r
+ uint32_t pi_count)\r
+{\r
+ uint32_t reg;\r
+ uint32_t msk;\r
+ uint32_t tempD;\r
+\r
+ ENTERFN();\r
+ DPF(D_TRN, "Wdqs ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);\r
+\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // BL0 -> B01PTRCTL0[07:04] (0x0-0xF)\r
+ // BL1 -> B01PTRCTL0[19:16] (0x0-0xF)\r
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);\r
+ msk = (byte_lane & BIT0) ? (BIT19 | BIT18 | BIT17 | BIT16) : (BIT7 | BIT6 | BIT5 | BIT4);\r
+ tempD = pi_count / HALF_CLK;\r
+ tempD <<= (byte_lane & BIT0) ? (16) : (4);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)\r
+ // BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)\r
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);\r
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));\r
+ msk = (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16);\r
+ tempD = pi_count << 16;\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // DEADBAND\r
+ // BL0/1 -> B01DBCTL1[07/10] (+1 select)\r
+ // BL0/1 -> B01DBCTL1[01/04] (enable)\r
+ reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);\r
+ msk = 0x00;\r
+ tempD = 0x00;\r
+ // enable\r
+ msk |= (byte_lane & BIT0) ? (BIT4) : (BIT1);\r
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ // select\r
+ msk |= (byte_lane & BIT0) ? (BIT10) : (BIT7);\r
+ if (pi_count < EARLY_DB)\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // error check\r
+ if (pi_count > 0x3F)\r
+ {\r
+ training_message(channel, rank, byte_lane);\r
+ post_code(0xEE, 0xE2);\r
+ }\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// get_wdqs:\r
+//\r
+// This function will return the amount of WDQS delay on the given channel, rank, byte_lane as an absolute PI count.\r
+// (currently doesn't comprehend rank)\r
+uint32_t get_wdqs(\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ uint8_t byte_lane)\r
+{\r
+ uint32_t reg;\r
+ uint32_t tempD;\r
+ uint32_t pi_count;\r
+\r
+ ENTERFN();\r
+\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // BL0 -> B01PTRCTL0[07:04] (0x0-0xF)\r
+ // BL1 -> B01PTRCTL0[19:16] (0x0-0xF)\r
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= (byte_lane & BIT0) ? (16) : (4);\r
+ tempD &= 0xF;\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count = (tempD * HALF_CLK);\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)\r
+ // BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)\r
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);\r
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= 16;\r
+ tempD &= 0x3F;\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count += tempD;\r
+\r
+ LEAVEFN();\r
+ return pi_count;\r
+}\r
+\r
+// set_wdq:\r
+//\r
+// This function will program the WDQ delays based on an absolute number of PIs.\r
+// (currently doesn't comprehend rank)\r
+void set_wdq(\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ uint8_t byte_lane,\r
+ uint32_t pi_count)\r
+{\r
+ uint32_t reg;\r
+ uint32_t msk;\r
+ uint32_t tempD;\r
+\r
+ ENTERFN();\r
+ DPF(D_TRN, "Wdq ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);\r
+\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // BL0 -> B01PTRCTL0[03:00] (0x0-0xF)\r
+ // BL1 -> B01PTRCTL0[15:12] (0x0-0xF)\r
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);\r
+ msk = (byte_lane & BIT0) ? (BIT15 | BIT14 | BIT13 | BIT12) : (BIT3 | BIT2 | BIT1 | BIT0);\r
+ tempD = pi_count / HALF_CLK;\r
+ tempD <<= (byte_lane & BIT0) ? (12) : (0);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)\r
+ // BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)\r
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);\r
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));\r
+ msk = (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8);\r
+ tempD = pi_count << 8;\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // DEADBAND\r
+ // BL0/1 -> B01DBCTL1[06/09] (+1 select)\r
+ // BL0/1 -> B01DBCTL1[00/03] (enable)\r
+ reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);\r
+ msk = 0x00;\r
+ tempD = 0x00;\r
+ // enable\r
+ msk |= (byte_lane & BIT0) ? (BIT3) : (BIT0);\r
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ // select\r
+ msk |= (byte_lane & BIT0) ? (BIT9) : (BIT6);\r
+ if (pi_count < EARLY_DB)\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // error check\r
+ if (pi_count > 0x3F)\r
+ {\r
+ training_message(channel, rank, byte_lane);\r
+ post_code(0xEE, 0xE3);\r
+ }\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// get_wdq:\r
+//\r
+// This function will return the amount of WDQ delay on the given channel, rank, byte_lane as an absolute PI count.\r
+// (currently doesn't comprehend rank)\r
+uint32_t get_wdq(\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ uint8_t byte_lane)\r
+{\r
+ uint32_t reg;\r
+ uint32_t tempD;\r
+ uint32_t pi_count;\r
+\r
+ ENTERFN();\r
+\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // BL0 -> B01PTRCTL0[03:00] (0x0-0xF)\r
+ // BL1 -> B01PTRCTL0[15:12] (0x0-0xF)\r
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= (byte_lane & BIT0) ? (12) : (0);\r
+ tempD &= 0xF;\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count = (tempD * HALF_CLK);\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)\r
+ // BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)\r
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);\r
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= 8;\r
+ tempD &= 0x3F;\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count += tempD;\r
+\r
+ LEAVEFN();\r
+ return pi_count;\r
+}\r
+\r
+// set_wcmd:\r
+//\r
+// This function will program the WCMD delays based on an absolute number of PIs.\r
+void set_wcmd(\r
+ uint8_t channel,\r
+ uint32_t pi_count)\r
+{\r
+ uint32_t reg;\r
+ uint32_t msk;\r
+ uint32_t tempD;\r
+\r
+ ENTERFN();\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // CMDPTRREG[11:08] (0x0-0xF)\r
+ reg = CMDPTRREG + (channel * DDRIOCCC_CH_OFFSET);\r
+ msk = (BIT11 | BIT10 | BIT9 | BIT8);\r
+ tempD = pi_count / HALF_CLK;\r
+ tempD <<= 8;\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)\r
+ // CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)\r
+ // CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)\r
+ // CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)\r
+ // CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)\r
+ // CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)\r
+ // CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)\r
+ // CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)\r
+ reg = CMDDLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET);\r
+\r
+ msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24) | (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16)\r
+ | (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8) | (BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0);\r
+\r
+ tempD = (pi_count << 24) | (pi_count << 16) | (pi_count << 8) | (pi_count << 0);\r
+\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+ reg = CMDDLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET); // PO\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // DEADBAND\r
+ // CMDCFGREG0[17] (+1 select)\r
+ // CMDCFGREG0[16] (enable)\r
+ reg = CMDCFGREG0 + (channel * DDRIOCCC_CH_OFFSET);\r
+ msk = 0x00;\r
+ tempD = 0x00;\r
+ // enable\r
+ msk |= BIT16;\r
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ // select\r
+ msk |= BIT17;\r
+ if (pi_count < EARLY_DB)\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // error check\r
+ if (pi_count > 0x3F)\r
+ {\r
+ post_code(0xEE, 0xE4);\r
+ }\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// get_wcmd:\r
+//\r
+// This function will return the amount of WCMD delay on the given channel as an absolute PI count.\r
+uint32_t get_wcmd(\r
+ uint8_t channel)\r
+{\r
+ uint32_t reg;\r
+ uint32_t tempD;\r
+ uint32_t pi_count;\r
+\r
+ ENTERFN();\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // CMDPTRREG[11:08] (0x0-0xF)\r
+ reg = CMDPTRREG + (channel * DDRIOCCC_CH_OFFSET);\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= 8;\r
+ tempD &= 0xF;\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count = tempD * HALF_CLK;\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)\r
+ // CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)\r
+ // CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)\r
+ // CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)\r
+ // CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)\r
+ // CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)\r
+ // CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)\r
+ // CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)\r
+ reg = CMDDLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET);\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= 16;\r
+ tempD &= 0x3F;\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count += tempD;\r
+\r
+ LEAVEFN();\r
+ return pi_count;\r
+}\r
+\r
+// set_wclk:\r
+//\r
+// This function will program the WCLK delays based on an absolute number of PIs.\r
+void set_wclk(\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ uint32_t pi_count)\r
+{\r
+ uint32_t reg;\r
+ uint32_t msk;\r
+ uint32_t tempD;\r
+\r
+ ENTERFN();\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // CCPTRREG[15:12] -> CLK1 (0x0-0xF)\r
+ // CCPTRREG[11:08] -> CLK0 (0x0-0xF)\r
+ reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);\r
+ msk = (BIT15 | BIT14 | BIT13 | BIT12) | (BIT11 | BIT10 | BIT9 | BIT8);\r
+ tempD = ((pi_count / HALF_CLK) << 12) | ((pi_count / HALF_CLK) << 8);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)\r
+ // ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)\r
+ reg = (rank) ? (ECCB1DLLPICODER0) : (ECCB1DLLPICODER0);\r
+ reg += (channel * DDRIOCCC_CH_OFFSET);\r
+ msk = (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16) | (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8);\r
+ tempD = (pi_count << 16) | (pi_count << 8);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+ reg = (rank) ? (ECCB1DLLPICODER1) : (ECCB1DLLPICODER1);\r
+ reg += (channel * DDRIOCCC_CH_OFFSET);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+ reg = (rank) ? (ECCB1DLLPICODER2) : (ECCB1DLLPICODER2);\r
+ reg += (channel * DDRIOCCC_CH_OFFSET);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+ reg = (rank) ? (ECCB1DLLPICODER3) : (ECCB1DLLPICODER3);\r
+ reg += (channel * DDRIOCCC_CH_OFFSET);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // DEADBAND\r
+ // CCCFGREG1[11:08] (+1 select)\r
+ // CCCFGREG1[03:00] (enable)\r
+ reg = CCCFGREG1 + (channel * DDRIOCCC_CH_OFFSET);\r
+ msk = 0x00;\r
+ tempD = 0x00;\r
+ // enable\r
+ msk |= (BIT3 | BIT2 | BIT1 | BIT0); // only ??? matters\r
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ // select\r
+ msk |= (BIT11 | BIT10 | BIT9 | BIT8); // only ??? matters\r
+ if (pi_count < EARLY_DB)\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // error check\r
+ if (pi_count > 0x3F)\r
+ {\r
+ post_code(0xEE, 0xE5);\r
+ }\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// get_wclk:\r
+//\r
+// This function will return the amout of WCLK delay on the given channel, rank as an absolute PI count.\r
+uint32_t get_wclk(\r
+ uint8_t channel,\r
+ uint8_t rank)\r
+{\r
+ uint32_t reg;\r
+ uint32_t tempD;\r
+ uint32_t pi_count;\r
+\r
+ ENTERFN();\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // CCPTRREG[15:12] -> CLK1 (0x0-0xF)\r
+ // CCPTRREG[11:08] -> CLK0 (0x0-0xF)\r
+ reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= (rank) ? (12) : (8);\r
+ tempD &= 0xF;\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count = tempD * HALF_CLK;\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)\r
+ // ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)\r
+ reg = (rank) ? (ECCB1DLLPICODER0) : (ECCB1DLLPICODER0);\r
+ reg += (channel * DDRIOCCC_CH_OFFSET);\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= (rank) ? (16) : (8);\r
+ tempD &= 0x3F;\r
+\r
+ pi_count += tempD;\r
+\r
+ LEAVEFN();\r
+ return pi_count;\r
+}\r
+\r
+// set_wctl:\r
+//\r
+// This function will program the WCTL delays based on an absolute number of PIs.\r
+// (currently doesn't comprehend rank)\r
+void set_wctl(\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ uint32_t pi_count)\r
+{\r
+ uint32_t reg;\r
+ uint32_t msk;\r
+ uint32_t tempD;\r
+\r
+ ENTERFN();\r
+\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // CCPTRREG[31:28] (0x0-0xF)\r
+ // CCPTRREG[27:24] (0x0-0xF)\r
+ reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);\r
+ msk = (BIT31 | BIT30 | BIT29 | BIT28) | (BIT27 | BIT26 | BIT25 | BIT24);\r
+ tempD = ((pi_count / HALF_CLK) << 28) | ((pi_count / HALF_CLK) << 24);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // ECCB1DLLPICODER?[29:24] (0x00-0x3F)\r
+ // ECCB1DLLPICODER?[29:24] (0x00-0x3F)\r
+ reg = ECCB1DLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET);\r
+ msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24);\r
+ tempD = (pi_count << 24);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+ reg = ECCB1DLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+ reg = ECCB1DLLPICODER2 + (channel * DDRIOCCC_CH_OFFSET);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+ reg = ECCB1DLLPICODER3 + (channel * DDRIOCCC_CH_OFFSET);\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // DEADBAND\r
+ // CCCFGREG1[13:12] (+1 select)\r
+ // CCCFGREG1[05:04] (enable)\r
+ reg = CCCFGREG1 + (channel * DDRIOCCC_CH_OFFSET);\r
+ msk = 0x00;\r
+ tempD = 0x00;\r
+ // enable\r
+ msk |= (BIT5 | BIT4); // only ??? matters\r
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ // select\r
+ msk |= (BIT13 | BIT12); // only ??? matters\r
+ if (pi_count < EARLY_DB)\r
+ {\r
+ tempD |= msk;\r
+ }\r
+ isbM32m(DDRPHY, reg, tempD, msk);\r
+\r
+ // error check\r
+ if (pi_count > 0x3F)\r
+ {\r
+ post_code(0xEE, 0xE6);\r
+ }\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// get_wctl:\r
+//\r
+// This function will return the amount of WCTL delay on the given channel, rank as an absolute PI count.\r
+// (currently doesn't comprehend rank)\r
+uint32_t get_wctl(\r
+ uint8_t channel,\r
+ uint8_t rank)\r
+{\r
+ uint32_t reg;\r
+ uint32_t tempD;\r
+ uint32_t pi_count;\r
+\r
+ ENTERFN();\r
+\r
+ // RDPTR (1/2 MCLK, 64 PIs)\r
+ // CCPTRREG[31:28] (0x0-0xF)\r
+ // CCPTRREG[27:24] (0x0-0xF)\r
+ reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= 24;\r
+ tempD &= 0xF;\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count = tempD * HALF_CLK;\r
+\r
+ // PI (1/64 MCLK, 1 PIs)\r
+ // ECCB1DLLPICODER?[29:24] (0x00-0x3F)\r
+ // ECCB1DLLPICODER?[29:24] (0x00-0x3F)\r
+ reg = ECCB1DLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET);\r
+ tempD = isbR32m(DDRPHY, reg);\r
+ tempD >>= 24;\r
+ tempD &= 0x3F;\r
+\r
+ // Adjust PI_COUNT\r
+ pi_count += tempD;\r
+\r
+ LEAVEFN();\r
+ return pi_count;\r
+}\r
+\r
+// set_vref:\r
+//\r
+// This function will program the internal Vref setting in a given byte lane in a given channel.\r
+void set_vref(\r
+ uint8_t channel,\r
+ uint8_t byte_lane,\r
+ uint32_t setting)\r
+{\r
+ uint32_t reg = (byte_lane & 0x1) ? (B1VREFCTL) : (B0VREFCTL);\r
+\r
+ ENTERFN();\r
+ DPF(D_TRN, "Vref ch%d ln%d : val=%03X\n", channel, byte_lane, setting);\r
+\r
+ isbM32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)),\r
+ (vref_codes[setting] << 2), (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2));\r
+ //isbM32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)), (setting<<2), (BIT7|BIT6|BIT5|BIT4|BIT3|BIT2));\r
+ // need to wait ~300ns for Vref to settle (check that this is necessary)\r
+ delay_n(300);\r
+ // ??? may need to clear pointers ???\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// get_vref:\r
+//\r
+// This function will return the internal Vref setting for the given channel, byte_lane;\r
+uint32_t get_vref(\r
+ uint8_t channel,\r
+ uint8_t byte_lane)\r
+{\r
+ uint8_t j;\r
+ uint32_t ret_val = sizeof(vref_codes) / 2;\r
+ uint32_t reg = (byte_lane & 0x1) ? (B1VREFCTL) : (B0VREFCTL);\r
+\r
+ uint32_t tempD;\r
+\r
+ ENTERFN();\r
+ tempD = isbR32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)));\r
+ tempD >>= 2;\r
+ tempD &= 0x3F;\r
+ for (j = 0; j < sizeof(vref_codes); j++)\r
+ {\r
+ if (vref_codes[j] == tempD)\r
+ {\r
+ ret_val = j;\r
+ break;\r
+ }\r
+ }\r
+ LEAVEFN();\r
+ return ret_val;\r
+}\r
+\r
+// clear_pointers:\r
+//\r
+// This function will be used to clear the pointers in a given byte lane in a given channel.\r
+void clear_pointers(\r
+ void)\r
+{\r
+ uint8_t channel_i;\r
+ uint8_t bl_i;\r
+\r
+ ENTERFN();\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ for (bl_i = 0; bl_i < NUM_BYTE_LANES; bl_i++)\r
+ {\r
+ isbM32m(DDRPHY, (B01PTRCTL1 + (channel_i * DDRIODQ_CH_OFFSET) + ((bl_i >> 1) * DDRIODQ_BL_OFFSET)), ~(BIT8),\r
+ (BIT8));\r
+ //delay_m(1); // DEBUG\r
+ isbM32m(DDRPHY, (B01PTRCTL1 + (channel_i * DDRIODQ_CH_OFFSET) + ((bl_i >> 1) * DDRIODQ_BL_OFFSET)), (BIT8),\r
+ (BIT8));\r
+ }\r
+ }\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// void enable_cache:\r
+void enable_cache(\r
+ void)\r
+{\r
+ // Cache control not used in Quark MRC\r
+ return;\r
+}\r
+\r
+// void disable_cache:\r
+void disable_cache(\r
+ void)\r
+{\r
+ // Cache control not used in Quark MRC\r
+ return;\r
+}\r
+\r
+// Send DRAM command, data should be formated\r
+// using DCMD_Xxxx macro or emrsXCommand structure.\r
+static void dram_init_command(\r
+ uint32_t data)\r
+{\r
+ Wr32(DCMD, 0, data);\r
+}\r
+\r
+// find_rising_edge:\r
+//\r
+// This function will find the rising edge transition on RCVN or WDQS.\r
+void find_rising_edge(\r
+ MRCParams_t *mrc_params,\r
+ uint32_t delay[],\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ bool rcvn)\r
+{\r
+\r
+#define SAMPLE_CNT 3 // number of sample points\r
+#define SAMPLE_DLY 26 // number of PIs to increment per sample\r
+#define FORWARD true // indicates to increase delays when looking for edge\r
+#define BACKWARD false // indicates to decrease delays when looking for edge\r
+\r
+ bool all_edges_found; // determines stop condition\r
+ bool direction[NUM_BYTE_LANES]; // direction indicator\r
+ uint8_t sample_i; // sample counter\r
+ uint8_t bl_i; // byte lane counter\r
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor\r
+ uint32_t sample_result[SAMPLE_CNT]; // results of "sample_dqs()"\r
+ uint32_t tempD; // temporary DWORD\r
+ uint32_t transition_pattern;\r
+\r
+ ENTERFN();\r
+\r
+ // select hte and request initial configuration\r
+ select_hte(mrc_params);\r
+ first_run = 1;\r
+\r
+ // Take 3 sample points (T1,T2,T3) to obtain a transition pattern.\r
+ for (sample_i = 0; sample_i < SAMPLE_CNT; sample_i++)\r
+ {\r
+ // program the desired delays for sample\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ // increase sample delay by 26 PI (0.2 CLK)\r
+ if (rcvn)\r
+ {\r
+ set_rcvn(channel, rank, bl_i, delay[bl_i] + (sample_i * SAMPLE_DLY));\r
+ }\r
+ else\r
+ {\r
+ set_wdqs(channel, rank, bl_i, delay[bl_i] + (sample_i * SAMPLE_DLY));\r
+ }\r
+ } // bl_i loop\r
+ // take samples (Tsample_i)\r
+ sample_result[sample_i] = sample_dqs(mrc_params, channel, rank, rcvn);\r
+\r
+ DPF(D_TRN, "Find rising edge %s ch%d rnk%d: #%d dly=%d dqs=%02X\n",\r
+ (rcvn ? "RCVN" : "WDQS"), channel, rank,\r
+ sample_i, sample_i * SAMPLE_DLY, sample_result[sample_i]);\r
+\r
+ } // sample_i loop\r
+\r
+ // This pattern will help determine where we landed and ultimately how to place RCVEN/WDQS.\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ // build "transition_pattern" (MSB is 1st sample)\r
+ transition_pattern = 0x00;\r
+ for (sample_i = 0; sample_i < SAMPLE_CNT; sample_i++)\r
+ {\r
+ transition_pattern |= ((sample_result[sample_i] & (1 << bl_i)) >> bl_i) << (SAMPLE_CNT - 1 - sample_i);\r
+ } // sample_i loop\r
+\r
+ DPF(D_TRN, "=== transition pattern %d\n", transition_pattern);\r
+\r
+ // set up to look for rising edge based on "transition_pattern"\r
+ switch (transition_pattern)\r
+ {\r
+ case 0x00: // sampled 0->0->0\r
+ // move forward from T3 looking for 0->1\r
+ delay[bl_i] += 2 * SAMPLE_DLY;\r
+ direction[bl_i] = FORWARD;\r
+ break;\r
+ case 0x01: // sampled 0->0->1\r
+ case 0x05: // sampled 1->0->1 (bad duty cycle) *HSD#237503*\r
+ // move forward from T2 looking for 0->1\r
+ delay[bl_i] += 1 * SAMPLE_DLY;\r
+ direction[bl_i] = FORWARD;\r
+ break;\r
+// HSD#237503\r
+// case 0x02: // sampled 0->1->0 (bad duty cycle)\r
+// training_message(channel, rank, bl_i);\r
+// post_code(0xEE, 0xE8);\r
+// break;\r
+ case 0x02: // sampled 0->1->0 (bad duty cycle) *HSD#237503*\r
+ case 0x03: // sampled 0->1->1\r
+ // move forward from T1 looking for 0->1\r
+ delay[bl_i] += 0 * SAMPLE_DLY;\r
+ direction[bl_i] = FORWARD;\r
+ break;\r
+ case 0x04: // sampled 1->0->0 (assumes BL8, HSD#234975)\r
+ // move forward from T3 looking for 0->1\r
+ delay[bl_i] += 2 * SAMPLE_DLY;\r
+ direction[bl_i] = FORWARD;\r
+ break;\r
+// HSD#237503\r
+// case 0x05: // sampled 1->0->1 (bad duty cycle)\r
+// training_message(channel, rank, bl_i);\r
+// post_code(0xEE, 0xE9);\r
+// break;\r
+ case 0x06: // sampled 1->1->0\r
+ case 0x07: // sampled 1->1->1\r
+ // move backward from T1 looking for 1->0\r
+ delay[bl_i] += 0 * SAMPLE_DLY;\r
+ direction[bl_i] = BACKWARD;\r
+ break;\r
+ default:\r
+ post_code(0xEE, 0xEE);\r
+ break;\r
+ } // transition_pattern switch\r
+ // program delays\r
+ if (rcvn)\r
+ {\r
+ set_rcvn(channel, rank, bl_i, delay[bl_i]);\r
+ }\r
+ else\r
+ {\r
+ set_wdqs(channel, rank, bl_i, delay[bl_i]);\r
+ }\r
+ } // bl_i loop\r
+\r
+ // Based on the observed transition pattern on the byte lane,\r
+ // begin looking for a rising edge with single PI granularity.\r
+ do\r
+ {\r
+ all_edges_found = true; // assume all byte lanes passed\r
+ tempD = sample_dqs(mrc_params, channel, rank, rcvn); // take a sample\r
+ // check all each byte lane for proper edge\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ if (tempD & (1 << bl_i))\r
+ {\r
+ // sampled "1"\r
+ if (direction[bl_i] == BACKWARD)\r
+ {\r
+ // keep looking for edge on this byte lane\r
+ all_edges_found = false;\r
+ delay[bl_i] -= 1;\r
+ if (rcvn)\r
+ {\r
+ set_rcvn(channel, rank, bl_i, delay[bl_i]);\r
+ }\r
+ else\r
+ {\r
+ set_wdqs(channel, rank, bl_i, delay[bl_i]);\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // sampled "0"\r
+ if (direction[bl_i] == FORWARD)\r
+ {\r
+ // keep looking for edge on this byte lane\r
+ all_edges_found = false;\r
+ delay[bl_i] += 1;\r
+ if (rcvn)\r
+ {\r
+ set_rcvn(channel, rank, bl_i, delay[bl_i]);\r
+ }\r
+ else\r
+ {\r
+ set_wdqs(channel, rank, bl_i, delay[bl_i]);\r
+ }\r
+ }\r
+ }\r
+ } // bl_i loop\r
+ } while (!all_edges_found);\r
+\r
+ // restore DDR idle state\r
+ dram_init_command(DCMD_PREA(rank));\r
+\r
+ DPF(D_TRN, "Delay %03X %03X %03X %03X\n",\r
+ delay[0], delay[1], delay[2], delay[3]);\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// sample_dqs:\r
+//\r
+// This function will sample the DQTRAINSTS registers in the given channel/rank SAMPLE_SIZE times looking for a valid '0' or '1'.\r
+// It will return an encoded DWORD in which each bit corresponds to the sampled value on the byte lane.\r
+uint32_t sample_dqs(\r
+ MRCParams_t *mrc_params,\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ bool rcvn)\r
+{\r
+ uint8_t j; // just a counter\r
+ uint8_t bl_i; // which BL in the module (always 2 per module)\r
+ uint8_t bl_grp; // which BL module\r
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor\r
+ uint32_t msk[2]; // BLx in module\r
+ uint32_t sampled_val[SAMPLE_SIZE]; // DQTRAINSTS register contents for each sample\r
+ uint32_t num_0s; // tracks the number of '0' samples\r
+ uint32_t num_1s; // tracks the number of '1' samples\r
+ uint32_t ret_val = 0x00; // assume all '0' samples\r
+ uint32_t address = get_addr(mrc_params, channel, rank);\r
+\r
+ // initialise "msk[]"\r
+ msk[0] = (rcvn) ? (BIT1) : (BIT9); // BL0\r
+ msk[1] = (rcvn) ? (BIT0) : (BIT8); // BL1\r
+\r
+\r
+ // cycle through each byte lane group\r
+ for (bl_grp = 0; bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2; bl_grp++)\r
+ {\r
+ // take SAMPLE_SIZE samples\r
+ for (j = 0; j < SAMPLE_SIZE; j++)\r
+ {\r
+ HteMemOp(address, first_run, rcvn?0:1);\r
+ first_run = 0;\r
+\r
+ // record the contents of the proper DQTRAINSTS register\r
+ sampled_val[j] = isbR32m(DDRPHY, (DQTRAINSTS + (bl_grp * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET)));\r
+ }\r
+ // look for a majority value ( (SAMPLE_SIZE/2)+1 ) on the byte lane\r
+ // and set that value in the corresponding "ret_val" bit\r
+ for (bl_i = 0; bl_i < 2; bl_i++)\r
+ {\r
+ num_0s = 0x00; // reset '0' tracker for byte lane\r
+ num_1s = 0x00; // reset '1' tracker for byte lane\r
+ for (j = 0; j < SAMPLE_SIZE; j++)\r
+ {\r
+ if (sampled_val[j] & msk[bl_i])\r
+ {\r
+ num_1s++;\r
+ }\r
+ else\r
+ {\r
+ num_0s++;\r
+ }\r
+ }\r
+ if (num_1s > num_0s)\r
+ {\r
+ ret_val |= (1 << (bl_i + (bl_grp * 2)));\r
+ }\r
+ }\r
+ }\r
+\r
+ // "ret_val.0" contains the status of BL0\r
+ // "ret_val.1" contains the status of BL1\r
+ // "ret_val.2" contains the status of BL2\r
+ // etc.\r
+ return ret_val;\r
+}\r
+\r
+// get_addr:\r
+//\r
+// This function will return a 32 bit address in the desired channel and rank.\r
+uint32_t get_addr(\r
+ MRCParams_t *mrc_params,\r
+ uint8_t channel,\r
+ uint8_t rank)\r
+{\r
+ uint32_t offset = 0x02000000; // 32MB\r
+\r
+ // Begin product specific code\r
+ if (channel > 0)\r
+ {\r
+ DPF(D_ERROR, "ILLEGAL CHANNEL\n");\r
+ DEAD_LOOP();\r
+ }\r
+\r
+ if (rank > 1)\r
+ {\r
+ DPF(D_ERROR, "ILLEGAL RANK\n");\r
+ DEAD_LOOP();\r
+ }\r
+\r
+ // use 256MB lowest density as per DRP == 0x0003\r
+ offset += rank * (256 * 1024 * 1024);\r
+\r
+ return offset;\r
+}\r
+\r
+// byte_lane_mask:\r
+//\r
+// This function will return a 32 bit mask that will be used to check for byte lane failures.\r
+uint32_t byte_lane_mask(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint32_t j;\r
+ uint32_t ret_val = 0x00;\r
+\r
+ // set "ret_val" based on NUM_BYTE_LANES such that you will check only BL0 in "result"\r
+ // (each bit in "result" represents a byte lane)\r
+ for (j = 0; j < MAX_BYTE_LANES; j += NUM_BYTE_LANES)\r
+ {\r
+ ret_val |= (1 << ((j / NUM_BYTE_LANES) * NUM_BYTE_LANES));\r
+ }\r
+\r
+ // HSD#235037\r
+ // need to adjust the mask for 16-bit mode\r
+ if (mrc_params->channel_width == x16)\r
+ {\r
+ ret_val |= (ret_val << 2);\r
+ }\r
+\r
+ return ret_val;\r
+}\r
+\r
+\r
+// read_tsc:\r
+//\r
+// This function will do some assembly to return TSC register contents as a uint64_t.\r
+uint64_t read_tsc(\r
+ void)\r
+{\r
+ volatile uint64_t tsc; // EDX:EAX\r
+\r
+#if defined (SIM) || defined (GCC)\r
+ volatile uint32_t tscH; // EDX\r
+ volatile uint32_t tscL;// EAX\r
+\r
+ asm("rdtsc":"=a"(tscL),"=d"(tscH));\r
+ tsc = tscH;\r
+ tsc = (tsc<<32)|tscL;\r
+#else\r
+ tsc = __rdtsc();\r
+#endif\r
+\r
+ return tsc;\r
+}\r
+\r
+// get_tsc_freq:\r
+//\r
+// This function returns the TSC frequency in MHz\r
+uint32_t get_tsc_freq(\r
+ void)\r
+{\r
+ static uint32_t freq[] =\r
+ { 533, 400, 200, 100 };\r
+ uint32_t fuse;\r
+#if 0\r
+ fuse = (isbR32m(FUSE, 0) >> 12) & (BIT1|BIT0);\r
+#else\r
+ // todo!!! Fixed 533MHz for emulation or debugging\r
+ fuse = 0;\r
+#endif\r
+ return freq[fuse];\r
+}\r
+\r
+#ifndef SIM\r
+// delay_n:\r
+//\r
+// This is a simple delay function.\r
+// It takes "nanoseconds" as a parameter.\r
+void delay_n(\r
+ uint32_t nanoseconds)\r
+{\r
+ // 1000 MHz clock has 1ns period --> no conversion required\r
+ uint64_t final_tsc = read_tsc();\r
+ final_tsc += ((get_tsc_freq() * (nanoseconds)) / 1000);\r
+\r
+ while (read_tsc() < final_tsc)\r
+ ;\r
+ return;\r
+}\r
+#endif\r
+\r
+// delay_u:\r
+//\r
+// This is a simple delay function.\r
+// It takes "microseconds as a parameter.\r
+void delay_u(\r
+ uint32_t microseconds)\r
+{\r
+ // 64 bit math is not an option, just use loops\r
+ while (microseconds--)\r
+ {\r
+ delay_n(1000);\r
+ }\r
+ return;\r
+}\r
+\r
+// delay_m:\r
+//\r
+// This is a simple delay function.\r
+// It takes "milliseconds" as a parameter.\r
+void delay_m(\r
+ uint32_t milliseconds)\r
+{\r
+ // 64 bit math is not an option, just use loops\r
+ while (milliseconds--)\r
+ {\r
+ delay_u(1000);\r
+ }\r
+ return;\r
+}\r
+\r
+// delay_s:\r
+//\r
+// This is a simple delay function.\r
+// It takes "seconds" as a parameter.\r
+void delay_s(\r
+ uint32_t seconds)\r
+{\r
+ // 64 bit math is not an option, just use loops\r
+ while (seconds--)\r
+ {\r
+ delay_m(1000);\r
+ }\r
+ return;\r
+}\r
+\r
+// post_code:\r
+//\r
+// This function will output the POST CODE to the four 7-Segment LED displays.\r
+void post_code(\r
+ uint8_t major,\r
+ uint8_t minor)\r
+{\r
+#ifdef EMU\r
+ // Update global variable for execution tracking in debug env\r
+ PostCode = ((major << 8) | minor);\r
+#endif\r
+\r
+ // send message to UART\r
+ DPF(D_INFO, "POST: 0x%01X%02X\n", major, minor);\r
+\r
+ // error check:\r
+ if (major == 0xEE)\r
+ {\r
+ // todo!!! Consider updating error status and exit MRC\r
+#ifdef SIM\r
+ // enable Ctrl-C handling\r
+ for(;;) delay_n(100);\r
+#else\r
+ DEAD_LOOP();\r
+#endif\r
+ }\r
+}\r
+\r
+void training_message(\r
+ uint8_t channel,\r
+ uint8_t rank,\r
+ uint8_t byte_lane)\r
+{\r
+ // send message to UART\r
+ DPF(D_INFO, "CH%01X RK%01X BL%01X\n", channel, rank, byte_lane);\r
+ return;\r
+}\r
+\r
+void print_timings(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint8_t algo_i;\r
+ uint8_t channel_i;\r
+ uint8_t rank_i;\r
+ uint8_t bl_i;\r
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1;\r
+\r
+ DPF(D_INFO, "\n---------------------------");\r
+ DPF(D_INFO, "\nALGO[CH:RK] BL0 BL1 BL2 BL3");\r
+ DPF(D_INFO, "\n===========================");\r
+ for (algo_i = 0; algo_i < eMAX_ALGOS; algo_i++)\r
+ {\r
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)\r
+ {\r
+ if (mrc_params->channel_enables & (1 << channel_i))\r
+ {\r
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)\r
+ {\r
+ if (mrc_params->rank_enables & (1 << rank_i))\r
+ {\r
+ switch (algo_i)\r
+ {\r
+ case eRCVN:\r
+ DPF(D_INFO, "\nRCVN[%02d:%02d]", channel_i, rank_i);\r
+ break;\r
+ case eWDQS:\r
+ DPF(D_INFO, "\nWDQS[%02d:%02d]", channel_i, rank_i);\r
+ break;\r
+ case eWDQx:\r
+ DPF(D_INFO, "\nWDQx[%02d:%02d]", channel_i, rank_i);\r
+ break;\r
+ case eRDQS:\r
+ DPF(D_INFO, "\nRDQS[%02d:%02d]", channel_i, rank_i);\r
+ break;\r
+ case eVREF:\r
+ DPF(D_INFO, "\nVREF[%02d:%02d]", channel_i, rank_i);\r
+ break;\r
+ case eWCMD:\r
+ DPF(D_INFO, "\nWCMD[%02d:%02d]", channel_i, rank_i);\r
+ break;\r
+ case eWCTL:\r
+ DPF(D_INFO, "\nWCTL[%02d:%02d]", channel_i, rank_i);\r
+ break;\r
+ case eWCLK:\r
+ DPF(D_INFO, "\nWCLK[%02d:%02d]", channel_i, rank_i);\r
+ break;\r
+ default:\r
+ break;\r
+ } // algo_i switch\r
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)\r
+ {\r
+ switch (algo_i)\r
+ {\r
+ case eRCVN:\r
+ DPF(D_INFO, " %03d", get_rcvn(channel_i, rank_i, bl_i));\r
+ break;\r
+ case eWDQS:\r
+ DPF(D_INFO, " %03d", get_wdqs(channel_i, rank_i, bl_i));\r
+ break;\r
+ case eWDQx:\r
+ DPF(D_INFO, " %03d", get_wdq(channel_i, rank_i, bl_i));\r
+ break;\r
+ case eRDQS:\r
+ DPF(D_INFO, " %03d", get_rdqs(channel_i, rank_i, bl_i));\r
+ break;\r
+ case eVREF:\r
+ DPF(D_INFO, " %03d", get_vref(channel_i, bl_i));\r
+ break;\r
+ case eWCMD:\r
+ DPF(D_INFO, " %03d", get_wcmd(channel_i));\r
+ break;\r
+ case eWCTL:\r
+ DPF(D_INFO, " %03d", get_wctl(channel_i, rank_i));\r
+ break;\r
+ case eWCLK:\r
+ DPF(D_INFO, " %03d", get_wclk(channel_i, rank_i));\r
+ break;\r
+ default:\r
+ break;\r
+ } // algo_i switch\r
+ } // bl_i loop\r
+ } // if rank_i enabled\r
+ } // rank_i loop\r
+ } // if channel_i enabled\r
+ } // channel_i loop\r
+ } // algo_i loop\r
+ DPF(D_INFO, "\n---------------------------");\r
+ DPF(D_INFO, "\n");\r
+ return;\r
+}\r
+\r
+// 32 bit LFSR with characteristic polynomial: X^32 + X^22 +X^2 + X^1\r
+// The function takes pointer to previous 32 bit value and modifies it to next value.\r
+void lfsr32(\r
+ uint32_t *lfsr_ptr)\r
+{\r
+ uint32_t bit;\r
+ uint32_t lfsr;\r
+ uint32_t i;\r
+\r
+ lfsr = *lfsr_ptr;\r
+\r
+ for (i = 0; i < 32; i++)\r
+ {\r
+ bit = 1 ^ (lfsr & BIT0);\r
+ bit = bit ^ ((lfsr & BIT1) >> 1);\r
+ bit = bit ^ ((lfsr & BIT2) >> 2);\r
+ bit = bit ^ ((lfsr & BIT22) >> 22);\r
+\r
+ lfsr = ((lfsr >> 1) | (bit << 31));\r
+ }\r
+\r
+ *lfsr_ptr = lfsr;\r
+ return;\r
+}\r
+\r
+// The purpose of this function is to ensure the SEC comes out of reset\r
+// and IA initiates the SEC enabling Memory Scrambling.\r
+void enable_scrambling(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint32_t lfsr = 0;\r
+ uint8_t i;\r
+\r
+ if (mrc_params->scrambling_enables == 0)\r
+ return;\r
+\r
+ ENTERFN();\r
+\r
+ // 32 bit seed is always stored in BIOS NVM.\r
+ lfsr = mrc_params->timings.scrambler_seed;\r
+\r
+ if (mrc_params->boot_mode == bmCold)\r
+ {\r
+ // factory value is 0 and in first boot, a clock based seed is loaded.\r
+ if (lfsr == 0)\r
+ {\r
+ lfsr = read_tsc() & 0x0FFFFFFF; // get seed from system clock and make sure it is not all 1's\r
+ }\r
+ // need to replace scrambler\r
+ // get next 32bit LFSR 16 times which is the last part of the previous scrambler vector.\r
+ else\r
+ {\r
+ for (i = 0; i < 16; i++)\r
+ {\r
+ lfsr32(&lfsr);\r
+ }\r
+ }\r
+ mrc_params->timings.scrambler_seed = lfsr; // save new seed.\r
+ } // if (cold_boot)\r
+\r
+ // In warm boot or S3 exit, we have the previous seed.\r
+ // In cold boot, we have the last 32bit LFSR which is the new seed.\r
+ lfsr32(&lfsr); // shift to next value\r
+ isbW32m(MCU, SCRMSEED, (lfsr & 0x0003FFFF));\r
+ for (i = 0; i < 2; i++)\r
+ {\r
+ isbW32m(MCU, SCRMLO + i, (lfsr & 0xAAAAAAAA));\r
+ }\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
+// This function will store relevant timing data\r
+// This data will be used on subsequent boots to speed up boot times\r
+// and is required for Suspend To RAM capabilities.\r
+void store_timings(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint8_t ch, rk, bl;\r
+ MrcTimings_t *mt = &mrc_params->timings;\r
+\r
+ for (ch = 0; ch < NUM_CHANNELS; ch++)\r
+ {\r
+ for (rk = 0; rk < NUM_RANKS; rk++)\r
+ {\r
+ for (bl = 0; bl < NUM_BYTE_LANES; bl++)\r
+ {\r
+ mt->rcvn[ch][rk][bl] = get_rcvn(ch, rk, bl); // RCVN\r
+ mt->rdqs[ch][rk][bl] = get_rdqs(ch, rk, bl); // RDQS\r
+ mt->wdqs[ch][rk][bl] = get_wdqs(ch, rk, bl); // WDQS\r
+ mt->wdq[ch][rk][bl] = get_wdq(ch, rk, bl); // WDQ\r
+ if (rk == 0)\r
+ {\r
+ mt->vref[ch][bl] = get_vref(ch, bl); // VREF (RANK0 only)\r
+ }\r
+ }\r
+ mt->wctl[ch][rk] = get_wctl(ch, rk); // WCTL\r
+ }\r
+ mt->wcmd[ch] = get_wcmd(ch); // WCMD\r
+ }\r
+\r
+ // need to save for a case of changing frequency after warm reset\r
+ mt->ddr_speed = mrc_params->ddr_speed;\r
+\r
+ return;\r
+}\r
+\r
+// This function will retrieve relevant timing data\r
+// This data will be used on subsequent boots to speed up boot times\r
+// and is required for Suspend To RAM capabilities.\r
+void restore_timings(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint8_t ch, rk, bl;\r
+ const MrcTimings_t *mt = &mrc_params->timings;\r
+\r
+ for (ch = 0; ch < NUM_CHANNELS; ch++)\r
+ {\r
+ for (rk = 0; rk < NUM_RANKS; rk++)\r
+ {\r
+ for (bl = 0; bl < NUM_BYTE_LANES; bl++)\r
+ {\r
+ set_rcvn(ch, rk, bl, mt->rcvn[ch][rk][bl]); // RCVN\r
+ set_rdqs(ch, rk, bl, mt->rdqs[ch][rk][bl]); // RDQS\r
+ set_wdqs(ch, rk, bl, mt->wdqs[ch][rk][bl]); // WDQS\r
+ set_wdq(ch, rk, bl, mt->wdq[ch][rk][bl]); // WDQ\r
+ if (rk == 0)\r
+ {\r
+ set_vref(ch, bl, mt->vref[ch][bl]); // VREF (RANK0 only)\r
+ }\r
+ }\r
+ set_wctl(ch, rk, mt->wctl[ch][rk]); // WCTL\r
+ }\r
+ set_wcmd(ch, mt->wcmd[ch]); // WCMD\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+// Configure default settings normally set as part of read training\r
+// Some defaults have to be set earlier as they may affect earlier\r
+// training steps.\r
+void default_timings(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ uint8_t ch, rk, bl;\r
+\r
+ for (ch = 0; ch < NUM_CHANNELS; ch++)\r
+ {\r
+ for (rk = 0; rk < NUM_RANKS; rk++)\r
+ {\r
+ for (bl = 0; bl < NUM_BYTE_LANES; bl++)\r
+ {\r
+ set_rdqs(ch, rk, bl, 24); // RDQS\r
+ if (rk == 0)\r
+ {\r
+ set_vref(ch, bl, 32); // VREF (RANK0 only)\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return;\r
+}\r
+\r
--- /dev/null
+/************************************************************************\r
+ *\r
+ * Copyright (c) 2013-2015 Intel Corporation.\r
+ *\r
+* This program and the accompanying materials\r
+* are licensed and made available under the terms and conditions of the BSD License\r
+* which accompanies this distribution. The full text of the license may be found at\r
+* http://opensource.org/licenses/bsd-license.php\r
+*\r
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ *\r
+ ***************************************************************************/\r
+#ifndef _MEMINIT_UTILS_H_\r
+#define _MEMINIT_UTILS_H_\r
+\r
+// General Definitions:\r
+#ifdef QUICKSIM\r
+#define SAMPLE_SIZE 4 // reduce number of training samples in simulation env\r
+#else\r
+#define SAMPLE_SIZE 6 // must be odd number\r
+#endif\r
+\r
+#define EARLY_DB (0x12) // must be less than this number to enable early deadband\r
+#define LATE_DB (0x34) // must be greater than this number to enable late deadband\r
+#define CHX_REGS (11*4)\r
+#define FULL_CLK 128\r
+#define HALF_CLK 64\r
+#define QRTR_CLK 32\r
+\r
+\r
+\r
+#define MCEIL(num,den) ((uint8_t)((num+den-1)/den))\r
+#define MMAX(a,b) ((((int32_t)(a))>((int32_t)(b)))?(a):(b))\r
+#define MCOUNT(a) (sizeof(a)/sizeof(*a))\r
+\r
+typedef enum ALGOS_enum {\r
+ eRCVN = 0,\r
+ eWDQS,\r
+ eWDQx,\r
+ eRDQS,\r
+ eVREF,\r
+ eWCMD,\r
+ eWCTL,\r
+ eWCLK,\r
+ eMAX_ALGOS,\r
+} ALGOs_t;\r
+\r
+\r
+// Prototypes:\r
+void set_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);\r
+void set_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);\r
+void set_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);\r
+void set_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);\r
+void set_wcmd(uint8_t channel, uint32_t pi_count);\r
+void set_wclk(uint8_t channel, uint8_t grp, uint32_t pi_count);\r
+void set_wctl(uint8_t channel, uint8_t rank, uint32_t pi_count);\r
+void set_vref(uint8_t channel, uint8_t byte_lane, uint32_t setting);\r
+uint32_t get_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane);\r
+uint32_t get_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane);\r
+uint32_t get_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane);\r
+uint32_t get_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane);\r
+uint32_t get_wcmd(uint8_t channel);\r
+uint32_t get_wclk(uint8_t channel, uint8_t group);\r
+uint32_t get_wctl(uint8_t channel, uint8_t rank);\r
+uint32_t get_vref(uint8_t channel, uint8_t byte_lane);\r
+\r
+void clear_pointers(void);\r
+void enable_cache(void);\r
+void disable_cache(void);\r
+void find_rising_edge(MRCParams_t *mrc_params, uint32_t delay[], uint8_t channel, uint8_t rank, bool rcvn);\r
+uint32_t sample_dqs(MRCParams_t *mrc_params, uint8_t channel, uint8_t rank, bool rcvn);\r
+uint32_t get_addr(MRCParams_t *mrc_params, uint8_t channel, uint8_t rank);\r
+uint32_t byte_lane_mask(MRCParams_t *mrc_params);\r
+\r
+uint64_t read_tsc(void);\r
+uint32_t get_tsc_freq(void);\r
+void delay_n(uint32_t nanoseconds);\r
+void delay_u(uint32_t microseconds);\r
+void delay_m(uint32_t milliseconds);\r
+void delay_s(uint32_t seconds);\r
+\r
+void post_code(uint8_t major, uint8_t minor);\r
+void training_message(uint8_t channel, uint8_t rank, uint8_t byte_lane);\r
+void print_timings(MRCParams_t *mrc_params);\r
+\r
+void enable_scrambling(MRCParams_t *mrc_params);\r
+void store_timings(MRCParams_t *mrc_params);\r
+void restore_timings(MRCParams_t *mrc_params);\r
+void default_timings(MRCParams_t *mrc_params);\r
+\r
+#ifndef SIM\r
+void *memset(void *d, int c, size_t n);\r
+void *memcpy(void *d, const void *s, size_t n);\r
+#endif\r
+\r
+#endif // _MEMINIT_UTILS_H_\r
--- /dev/null
+/** @file\r
+Common definitions and compilation switches for MRC\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#ifndef __MEMORY_OPTIONS_H\r
+#define __MEMORY_OPTIONS_H\r
+\r
+#include "core_types.h"\r
+\r
+// MRC COMPILE TIME SWITCHES:\r
+// ==========================\r
+\r
+\r
+\r
+//#define MRC_SV // enable some validation opitons\r
+\r
+#if defined (SIM) || defined(EMU)\r
+#define QUICKSIM // reduce execution time using shorter rd/wr sequences\r
+#endif\r
+\r
+#define CLT // required for Quark project\r
+\r
+\r
+\r
+//#define BACKUP_RCVN // enable STATIC timing settings for RCVN (BACKUP_MODE)\r
+//#define BACKUP_WDQS // enable STATIC timing settings for WDQS (BACKUP_MODE)\r
+//#define BACKUP_RDQS // enable STATIC timing settings for RDQS (BACKUP_MODE)\r
+//#define BACKUP_WDQ // enable STATIC timing settings for WDQ (BACKUP_MODE)\r
+\r
+\r
+\r
+//#define BACKUP_COMPS // enable *COMP overrides (BACKUP_MODE)\r
+//#define RX_EYE_CHECK // enable the RD_TRAIN eye check\r
+#define HMC_TEST // enable Host to Memory Clock Alignment\r
+#define R2R_SHARING // enable multi-rank support via rank2rank sharing\r
+\r
+#define FORCE_16BIT_DDRIO // disable signals not used in 16bit mode of DDRIO\r
+\r
+\r
+\r
+//\r
+// Debug support\r
+//\r
+\r
+#ifdef NDEBUG\r
+#define DPF if(0) dpf\r
+#else\r
+#define DPF dpf\r
+#endif\r
+\r
+void dpf( uint32_t mask, char_t *bla, ...);\r
+\r
+\r
+uint8_t mgetc(void);\r
+uint8_t mgetch(void);\r
+\r
+\r
+// Debug print type\r
+#define D_ERROR 0x0001\r
+#define D_INFO 0x0002\r
+#define D_REGRD 0x0004\r
+#define D_REGWR 0x0008\r
+#define D_FCALL 0x0010\r
+#define D_TRN 0x0020\r
+#define D_TIME 0x0040\r
+\r
+#define ENTERFN() DPF(D_FCALL, "<%s>\n", __FUNCTION__)\r
+#define LEAVEFN() DPF(D_FCALL, "</%s>\n", __FUNCTION__)\r
+#define REPORTFN() DPF(D_FCALL, "<%s/>\n", __FUNCTION__)\r
+\r
+extern uint32_t DpfPrintMask;\r
+\r
+#endif\r
--- /dev/null
+/************************************************************************\r
+ *\r
+ * Copyright (c) 2013-2015 Intel Corporation.\r
+ *\r
+* This program and the accompanying materials\r
+* are licensed and made available under the terms and conditions of the BSD License\r
+* which accompanies this distribution. The full text of the license may be found at\r
+* http://opensource.org/licenses/bsd-license.php\r
+*\r
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ *\r
+ ************************************************************************/\r
+#include "mrc.h"\r
+#include "memory_options.h"\r
+\r
+#include "meminit.h"\r
+#include "meminit_utils.h"\r
+#include "prememinit.h"\r
+#include "io.h"\r
+\r
+// Base address for UART registers\r
+extern uint32_t UartMmioBase;\r
+\r
+//\r
+// Memory Reference Code entry point when executing from BIOS\r
+//\r
+void Mrc( MRCParams_t *mrc_params)\r
+{\r
+ // configure uart base address assuming code relocated to eSRAM\r
+ UartMmioBase = mrc_params->uart_mmio_base;\r
+\r
+ ENTERFN();\r
+\r
+ DPF(D_INFO, "MRC Version %04X %s %s\n", MRC_VERSION, __DATE__, __TIME__);\r
+\r
+ // this will set up the data structures used by MemInit()\r
+ PreMemInit(mrc_params);\r
+\r
+ // this will initialize system memory\r
+ MemInit(mrc_params);\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
--- /dev/null
+/************************************************************************\r
+ *\r
+ * Copyright (c) 2013-2015 Intel Corporation.\r
+ *\r
+* This program and the accompanying materials\r
+* are licensed and made available under the terms and conditions of the BSD License\r
+* which accompanies this distribution. The full text of the license may be found at\r
+* http://opensource.org/licenses/bsd-license.php\r
+*\r
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ *\r
+ ************************************************************************/\r
+#ifndef _MRC_H_\r
+#define _MRC_H_\r
+\r
+#include "core_types.h"\r
+\r
+// define the MRC Version\r
+#define MRC_VERSION 0x0112\r
+\r
+\r
+// architectural definitions\r
+#define NUM_CHANNELS 1 // number of channels\r
+#define NUM_RANKS 2 // number of ranks per channel\r
+#define NUM_BYTE_LANES 4 // number of byte lanes per channel\r
+\r
+// software limitations\r
+#define MAX_CHANNELS 1\r
+#define MAX_RANKS 2\r
+#define MAX_BYTE_LANES 4\r
+\r
+// only to mock MrcWrapper\r
+#define MAX_SOCKETS 1\r
+#define MAX_SIDES 1\r
+#define MAX_ROWS (MAX_SIDES * MAX_SOCKETS)\r
+// end\r
+\r
+\r
+// Specify DRAM of nenory channel width\r
+enum {\r
+ x8, // DRAM width\r
+ x16, // DRAM width & Channel Width\r
+ x32 // Channel Width\r
+};\r
+\r
+// Specify DRAM speed\r
+enum {\r
+ DDRFREQ_800,\r
+ DDRFREQ_1066\r
+};\r
+\r
+// Specify DRAM type\r
+enum {\r
+ DDR3,\r
+ DDR3L\r
+};\r
+\r
+// Delay configuration for individual signals\r
+// Vref setting\r
+// Scrambler seed\r
+typedef struct MrcTimings_s\r
+{\r
+ uint32_t rcvn[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];\r
+ uint32_t rdqs[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];\r
+ uint32_t wdqs[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];\r
+ uint32_t wdq [NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];\r
+ uint32_t vref[NUM_CHANNELS][NUM_BYTE_LANES];\r
+ uint32_t wctl[NUM_CHANNELS][NUM_RANKS];\r
+ uint32_t wcmd[NUM_CHANNELS];\r
+\r
+ uint32_t scrambler_seed;\r
+ uint8_t ddr_speed; // need to save for the case of frequency change\r
+} MrcTimings_t;\r
+\r
+\r
+// DENSITY: 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb\r
+// tCL is DRAM CAS Latency in clocks.\r
+// All other timings are in picoseconds.\r
+// Refer to JEDEC spec (or DRAM datasheet) when changing these values.\r
+typedef struct DRAMParams_s {\r
+ uint8_t DENSITY;\r
+ uint8_t tCL; // CAS latency in clocks\r
+ uint32_t tRAS; // ACT to PRE command period\r
+ uint32_t tWTR; // Delay from start of internal write transaction to internal read command\r
+ uint32_t tRRD; // ACT to ACT command period (JESD79 specific to page size 1K/2K)\r
+ uint32_t tFAW; // Four activate window (JESD79 specific to page size 1K/2K)\r
+} DRAMParams_t;\r
+\r
+\r
+// Boot mode defined as bit mask (1<<n)\r
+#define bmCold 1 // full training\r
+#define bmFast 2 // restore timing parameters\r
+#define bmS3 4 // resume from S3\r
+#define bmWarm 8\r
+#define bmUnknown 0\r
+\r
+\r
+// MRC execution status\r
+#define MRC_SUCCESS 0 // initialization ok\r
+#define MRC_E_MEMTEST 1 // memtest failed\r
+\r
+\r
+//\r
+// Input/output/context parameters for Memory Reference Code\r
+//\r
+typedef struct MRCParams_s\r
+{\r
+ //\r
+ // Global settings\r
+ //\r
+\r
+ uint32_t boot_mode; // bmCold, bmFast, bmWarm, bmS3\r
+ uint32_t uart_mmio_base; // pcie serial port base address (force 0 to disable debug)\r
+\r
+ uint8_t dram_width; // x8, x16\r
+ uint8_t ddr_speed; // DDRFREQ_800, DDRFREQ_1066\r
+ uint8_t ddr_type; // DDR3, DDR3L\r
+ uint8_t ecc_enables; // 0, 1 (memory size reduced to 7/8)\r
+ uint8_t scrambling_enables; // 0, 1\r
+ uint32_t rank_enables; // 1, 3 (1'st rank has to be populated if 2'nd rank present)\r
+ uint32_t channel_enables; // 1 only\r
+ uint32_t channel_width; // x16 only\r
+ uint32_t address_mode; // 0, 1, 2 (mode 2 forced if ecc enabled)\r
+\r
+ // memConfig_t begin\r
+ uint8_t refresh_rate; // REFRESH_RATE : 1=1.95us, 2=3.9us, 3=7.8us, others=RESERVED\r
+ uint8_t sr_temp_range; // SR_TEMP_RANGE : 0=normal, 1=extended, others=RESERVED\r
+ uint8_t ron_value; // RON_VALUE : 0=34ohm, 1=40ohm, others=RESERVED (select MRS1.DIC driver impedance control)\r
+ uint8_t rtt_nom_value; // RTT_NOM_VALUE : 0=40ohm, 1=60ohm, 2=120ohm, others=RESERVED\r
+ uint8_t rd_odt_value; // RD_ODT_VALUE : 0=off, 1=60ohm, 2=120ohm, 3=180ohm, others=RESERVED\r
+ // memConfig_t end\r
+\r
+ DRAMParams_t params;\r
+\r
+ //\r
+ // Internally used\r
+ //\r
+\r
+ uint32_t board_id; // internally used for board layout (use x8 or x16 memory)\r
+ uint32_t hte_setup : 1; // when set hte reconfiguration requested\r
+ uint32_t menu_after_mrc : 1;\r
+ uint32_t power_down_disable :1;\r
+ uint32_t tune_rcvn :1;\r
+\r
+ uint32_t channel_size[NUM_CHANNELS];\r
+ uint32_t column_bits[NUM_CHANNELS];\r
+ uint32_t row_bits[NUM_CHANNELS];\r
+\r
+ uint32_t mrs1; // register content saved during training\r
+\r
+ //\r
+ // Output\r
+ //\r
+\r
+ uint32_t status; // initialization result (non zero specifies error code)\r
+ uint32_t mem_size; // total memory size in bytes (excludes ECC banks)\r
+\r
+ MrcTimings_t timings; // training results (also used on input)\r
+\r
+} MRCParams_t;\r
+\r
+// Alternative type name for consistent naming convention\r
+#define MRC_PARAMS MRCParams_t\r
+\r
+#endif // _MRC_H_\r
--- /dev/null
+/** @file\r
+The interface layer for memory controller access.\r
+It is supporting both real hardware platform and simulation environment.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "mrc.h"\r
+#include "memory_options.h"\r
+#include "meminit_utils.h"\r
+#include "io.h"\r
+\r
+#ifdef SIM\r
+\r
+void SimMmio32Write (\r
+ uint32_t be,\r
+ uint32_t address,\r
+ uint32_t data );\r
+\r
+void SimMmio32Read (\r
+ uint32_t be,\r
+ uint32_t address,\r
+ uint32_t *data );\r
+\r
+void SimDelayClk (\r
+ uint32_t x2clk );\r
+\r
+// This is a simple delay function.\r
+// It takes "nanoseconds" as a parameter.\r
+void delay_n(uint32_t nanoseconds)\r
+{\r
+ SimDelayClk( 800*nanoseconds/1000);\r
+}\r
+#endif\r
+\r
+/****\r
+ *\r
+ ***/\r
+uint32_t Rd32(\r
+ uint32_t unit,\r
+ uint32_t addr)\r
+{\r
+ uint32_t data;\r
+\r
+ switch (unit)\r
+ {\r
+ case MEM:\r
+ case MMIO:\r
+#ifdef SIM\r
+ SimMmio32Read( 1, addr, &data);\r
+#else\r
+ data = *PTR32(addr);\r
+#endif\r
+ break;\r
+\r
+ case MCU:\r
+ case HOST_BRIDGE:\r
+ case MEMORY_MANAGER:\r
+ case HTE:\r
+ // Handle case addr bigger than 8bit\r
+ pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);\r
+ addr &= 0x00FF;\r
+\r
+ pciwrite32(0, 0, 0, SB_PACKET_REG,\r
+ SB_COMMAND(SB_REG_READ_OPCODE, unit, addr));\r
+ data = pciread32(0, 0, 0, SB_DATA_REG);\r
+ break;\r
+\r
+ case DDRPHY:\r
+ // Handle case addr bigger than 8bit\r
+ pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);\r
+ addr &= 0x00FF;\r
+\r
+ pciwrite32(0, 0, 0, SB_PACKET_REG,\r
+ SB_COMMAND(SB_DDRIO_REG_READ_OPCODE, unit, addr));\r
+ data = pciread32(0, 0, 0, SB_DATA_REG);\r
+ break;\r
+\r
+ default:\r
+ DEAD_LOOP()\r
+ ;\r
+ }\r
+\r
+ if (unit < MEM)\r
+ DPF(D_REGRD, "RD32 %03X %08X %08X\n", unit, addr, data);\r
+\r
+ return data;\r
+}\r
+\r
+/****\r
+ *\r
+ ***/\r
+void Wr32(\r
+ uint32_t unit,\r
+ uint32_t addr,\r
+ uint32_t data)\r
+{\r
+ if (unit < MEM)\r
+ DPF(D_REGWR, "WR32 %03X %08X %08X\n", unit, addr, data);\r
+\r
+ switch (unit)\r
+ {\r
+ case MEM:\r
+ case MMIO:\r
+#ifdef SIM\r
+ SimMmio32Write( 1, addr, data);\r
+#else\r
+ *PTR32(addr) = data;\r
+#endif\r
+ break;\r
+\r
+ case MCU:\r
+ case HOST_BRIDGE:\r
+ case MEMORY_MANAGER:\r
+ case HTE:\r
+ // Handle case addr bigger than 8bit\r
+ pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);\r
+ addr &= 0x00FF;\r
+\r
+ pciwrite32(0, 0, 0, SB_DATA_REG, data);\r
+ pciwrite32(0, 0, 0, SB_PACKET_REG,\r
+ SB_COMMAND(SB_REG_WRITE_OPCODE, unit, addr));\r
+ break;\r
+\r
+ case DDRPHY:\r
+ // Handle case addr bigger than 8bit\r
+ pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);\r
+ addr &= 0x00FF;\r
+\r
+ pciwrite32(0, 0, 0, SB_DATA_REG, data);\r
+ pciwrite32(0, 0, 0, SB_PACKET_REG,\r
+ SB_COMMAND(SB_DDRIO_REG_WRITE_OPCODE, unit, addr));\r
+ break;\r
+\r
+ case DCMD:\r
+ pciwrite32(0, 0, 0, SB_HADR_REG, 0);\r
+ pciwrite32(0, 0, 0, SB_DATA_REG, data);\r
+ pciwrite32(0, 0, 0, SB_PACKET_REG,\r
+ SB_COMMAND(SB_DRAM_CMND_OPCODE, MCU, 0));\r
+ break;\r
+\r
+ default:\r
+ DEAD_LOOP()\r
+ ;\r
+ }\r
+}\r
+\r
+/****\r
+ *\r
+ ***/\r
+void WrMask32(\r
+ uint32_t unit,\r
+ uint32_t addr,\r
+ uint32_t data,\r
+ uint32_t mask)\r
+{\r
+ Wr32(unit, addr, ((Rd32(unit, addr) & ~mask) | (data & mask)));\r
+}\r
+\r
+/****\r
+ *\r
+ ***/\r
+void pciwrite32(\r
+ uint32_t bus,\r
+ uint32_t dev,\r
+ uint32_t fn,\r
+ uint32_t reg,\r
+ uint32_t data)\r
+{\r
+ Wr32(MMIO, PCIADDR(bus,dev,fn,reg), data);\r
+}\r
+\r
+/****\r
+ *\r
+ ***/\r
+uint32_t pciread32(\r
+ uint32_t bus,\r
+ uint32_t dev,\r
+ uint32_t fn,\r
+ uint32_t reg)\r
+{\r
+ return Rd32(MMIO, PCIADDR(bus,dev,fn,reg));\r
+}\r
+\r
--- /dev/null
+/************************************************************************\r
+ *\r
+ * Copyright (c) 2013-2015 Intel Corporation.\r
+ *\r
+* This program and the accompanying materials\r
+* are licensed and made available under the terms and conditions of the BSD License\r
+* which accompanies this distribution. The full text of the license may be found at\r
+* http://opensource.org/licenses/bsd-license.php\r
+*\r
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ *\r
+ ************************************************************************/\r
+\r
+#include "mrc.h"\r
+#include "memory_options.h"\r
+\r
+#include "meminit_utils.h"\r
+#include "prememinit.h"\r
+#include "io.h"\r
+\r
+// Read character from serial console\r
+uint8_t mgetc(void);\r
+\r
+extern uint32_t DpfPrintMask;\r
+\r
+// Adjust configuration parameters before initialisation\r
+// sequence.\r
+void PreMemInit(\r
+ MRCParams_t *mrc_params)\r
+{\r
+ const DRAMParams_t *dram_params;\r
+\r
+ uint8_t dram_width;\r
+ uint32_t dram_cfg_index;\r
+ uint32_t channel_i;\r
+\r
+ ENTERFN();\r
+\r
+#ifdef MRC_SV\r
+ {\r
+ uint8_t ch;\r
+\r
+ myloop:\r
+\r
+ DPF(D_INFO, "- c - continue\n");\r
+ DPF(D_INFO, "- f - boot mode [%d]\n", mrc_params->boot_mode);\r
+ DPF(D_INFO, "- r - rank enable [%d]\n", mrc_params->rank_enables);\r
+ DPF(D_INFO, "- e - ecc switch [%d]\n", mrc_params->ecc_enables);\r
+ DPF(D_INFO, "- b - scrambling switch [%d]\n", mrc_params->scrambling_enables);\r
+ DPF(D_INFO, "- a - adr mode [%d]\n", mrc_params->address_mode);\r
+ DPF(D_INFO, "- m - menu after mrc [%d]\n", mrc_params->menu_after_mrc);\r
+ DPF(D_INFO, "- t - tune to rcvn [%d]\n", mrc_params->tune_rcvn);\r
+ DPF(D_INFO, "- o - odt switch [%d]\n", mrc_params->rd_odt_value);\r
+ DPF(D_INFO, "- d - dram density [%d]\n", mrc_params->params.DENSITY);\r
+ DPF(D_INFO, "- p - power down disable [%d]\n", mrc_params->power_down_disable);\r
+ DPF(D_INFO, "- l - log switch 0x%x\n", DpfPrintMask);\r
+ ch = mgetc();\r
+\r
+ switch (ch)\r
+ {\r
+ case 'f':\r
+ mrc_params->boot_mode >>= 1;\r
+ if(mrc_params->boot_mode == bmUnknown)\r
+ {\r
+ mrc_params->boot_mode = bmWarm;\r
+ }\r
+ DPF(D_INFO, "Boot mode %d\n", mrc_params->boot_mode);\r
+ break;\r
+\r
+ case 'p':\r
+ mrc_params->power_down_disable ^= 1;\r
+ DPF(D_INFO, "Power down disable %d\n", mrc_params->power_down_disable);\r
+ break;\r
+\r
+ case 'r':\r
+ mrc_params->rank_enables ^= 2;\r
+ DPF(D_INFO, "Rank enable %d\n", mrc_params->rank_enables);\r
+ break;\r
+\r
+ case 'e':\r
+ mrc_params->ecc_enables ^= 1;\r
+ DPF(D_INFO, "Ecc enable %d\n", mrc_params->ecc_enables);\r
+ break;\r
+\r
+ case 'b':\r
+ mrc_params->scrambling_enables ^= 1;\r
+ DPF(D_INFO, "Scrambler enable %d\n", mrc_params->scrambling_enables);\r
+ break;\r
+\r
+ case 'a':\r
+ mrc_params->address_mode = (mrc_params->address_mode + 1) % 3;\r
+ DPF(D_INFO, "Adr mode %d\n", mrc_params->address_mode);\r
+ break;\r
+\r
+ case 'm':\r
+ mrc_params->menu_after_mrc ^= 1;\r
+ DPF(D_INFO, "Menu after mrc %d\n", mrc_params->menu_after_mrc);\r
+ break;\r
+\r
+ case 't':\r
+ mrc_params->tune_rcvn ^= 1;\r
+ DPF(D_INFO, "Tune to rcvn %d\n", mrc_params->tune_rcvn);\r
+ break;\r
+\r
+ case 'o':\r
+ mrc_params->rd_odt_value = (mrc_params->rd_odt_value + 1) % 4;\r
+ DPF(D_INFO, "Rd_odt_value %d\n", mrc_params->rd_odt_value);\r
+ break;\r
+\r
+ case 'd':\r
+ mrc_params->params.DENSITY = (mrc_params->params.DENSITY + 1) % 4;\r
+ DPF(D_INFO, "Dram density %d\n", mrc_params->params.DENSITY);\r
+ break;\r
+\r
+ case 'l':\r
+ DpfPrintMask ^= 0x30;\r
+ DPF(D_INFO, "Log mask %x\n", DpfPrintMask);\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ if (ch != 'c')\r
+ goto myloop;\r
+\r
+ }\r
+#endif\r
+\r
+ // initially expect success\r
+ mrc_params->status = MRC_SUCCESS;\r
+\r
+ // todo!!! Setup board layout (must be reviewed as is selecting static timings)\r
+ // 0 == R0 (DDR3 x16), 1 == R1 (DDR3 x16), 2 == DV (DDR3 x8), 3 == SV (DDR3 x8)\r
+ if (mrc_params->dram_width == x8)\r
+ {\r
+ mrc_params->board_id = 2; // select x8 layout\r
+ }\r
+ else\r
+ {\r
+ mrc_params->board_id = 0; // select x16 layout\r
+ }\r
+\r
+ // initially no memory\r
+ mrc_params->mem_size = 0;\r
+ channel_i = 0;\r
+\r
+ // begin of channel settings\r
+ dram_width = mrc_params->dram_width;\r
+ dram_params = &mrc_params->params;\r
+ dram_cfg_index = 0;\r
+\r
+ // Determine Column & Row Bits:\r
+ // Column:\r
+ // 11 for 8Gbx8, else 10\r
+ mrc_params->column_bits[channel_i] = ((dram_params[dram_cfg_index].DENSITY == 4) && (dram_width == x8)) ? (11) : (10);\r
+\r
+ // Row:\r
+ // 512Mbx16=12 512Mbx8=13\r
+ // 1Gbx16=13 1Gbx8=14\r
+ // 2Gbx16=14 2Gbx8=15\r
+ // 4Gbx16=15 4Gbx8=16\r
+ // 8Gbx16=16 8Gbx8=16\r
+ mrc_params->row_bits[channel_i] = 12 + (dram_params[dram_cfg_index].DENSITY)\r
+ + (((dram_params[dram_cfg_index].DENSITY < 4) && (dram_width == x8)) ? (1) : (0));\r
+\r
+ // Determine Per Channel Memory Size:\r
+ // (For 2 RANKs, multiply by 2)\r
+ // (For 16 bit data bus, divide by 2)\r
+ // DENSITY WIDTH MEM_AVAILABLE\r
+ // 512Mb x16 0x008000000 ( 128MB)\r
+ // 512Mb x8 0x010000000 ( 256MB)\r
+ // 1Gb x16 0x010000000 ( 256MB)\r
+ // 1Gb x8 0x020000000 ( 512MB)\r
+ // 2Gb x16 0x020000000 ( 512MB)\r
+ // 2Gb x8 0x040000000 (1024MB)\r
+ // 4Gb x16 0x040000000 (1024MB)\r
+ // 4Gb x8 0x080000000 (2048MB)\r
+ mrc_params->channel_size[channel_i] = (1 << dram_params[dram_cfg_index].DENSITY);\r
+ mrc_params->channel_size[channel_i] *= ((dram_width == x8) ? (2) : (1));\r
+ mrc_params->channel_size[channel_i] *= (mrc_params->rank_enables == 0x3) ? (2) : (1);\r
+ mrc_params->channel_size[channel_i] *= (mrc_params->channel_width == x16) ? (1) : (2);\r
+\r
+ // Determine memory size (convert number of 64MB/512Mb units)\r
+ mrc_params->mem_size += mrc_params->channel_size[channel_i] << 26;\r
+\r
+ // end of channel settings\r
+\r
+ LEAVEFN();\r
+ return;\r
+}\r
+\r
--- /dev/null
+/************************************************************************\r
+ *\r
+ * Copyright (c) 2013-2015 Intel Corporation.\r
+ *\r
+* This program and the accompanying materials\r
+* are licensed and made available under the terms and conditions of the BSD License\r
+* which accompanies this distribution. The full text of the license may be found at\r
+* http://opensource.org/licenses/bsd-license.php\r
+*\r
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ *\r
+ ************************************************************************/\r
+#ifndef __PREMEMINIT_H_\r
+#define __PREMEMINIT_H_\r
+\r
+// Function prototypes\r
+void PreMemInit(MRCParams_t *mrc_params);\r
+\r
+\r
+#endif // _PREMEMINIT_H_\r
--- /dev/null
+/** @file\r
+Common header file shared by all source files.\r
+\r
+This file includes package header files, library classes and protocol, PPI & GUID definitions.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef __COMMON_HEADER_H_\r
+#define __COMMON_HEADER_H_\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiDxe.h>\r
+#include <IntelQNCDxe.h>\r
+\r
+//\r
+// The protocols, PPI and GUID definitions for this module\r
+//\r
+#include <Protocol/PciHostBridgeResourceAllocation.h>\r
+#include <Protocol/LegacyRegion2.h>\r
+#include <Protocol/SmbusHc.h>\r
+#include <Protocol/QncS3Support.h>\r
+\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/BaseLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/MtrrLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/SmbusLib.h>\r
+#include <Library/S3IoLib.h>\r
+#include <Library/S3BootScriptLib.h>\r
+#include <Library/IntelQNCLib.h>\r
+#include <Library/QNCAccessLib.h>\r
+#include <AcpiCpuData.h>\r
+\r
+extern EFI_HANDLE gQNCInitImageHandle;\r
+extern QNC_DEVICE_ENABLES mQNCDeviceEnables;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Implementation for SMBus DXE driver entry point and SMBus Host\r
+Controller protocol.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "CommonHeader.h"\r
+\r
+#include "DxeQNCSmbus.h"\r
+\r
+//\r
+// Interface defintion of SMBUS Host Controller Protocol.\r
+//\r
+EFI_SMBUS_HC_PROTOCOL mSmbusHc = {\r
+ SmbusExecute,\r
+ SmbusArpDevice,\r
+ SmbusGetArpMap,\r
+ SmbusNotify\r
+};\r
+\r
+//\r
+// Handle to install SMBus Host Controller protocol.\r
+//\r
+EFI_HANDLE mSmbusHcHandle = NULL;\r
+UINT8 mDeviceMapEntries = 0;\r
+EFI_SMBUS_DEVICE_MAP mDeviceMap[MAX_SMBUS_DEVICES];\r
+UINT8 mPlatformNumRsvd = 0;\r
+UINT8 *mPlatformAddrRsvd = NULL;\r
+\r
+//\r
+// These addresses are reserved by the SMBus 2.0 specification\r
+//\r
+UINT8 mReservedAddress[SMBUS_NUM_RESERVED] = {\r
+ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x18, 0x50, 0x6E, 0xC2,\r
+ 0xF0, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFC, 0xFE\r
+};\r
+\r
+\r
+/**\r
+ Gets Io port base address of Smbus Host Controller.\r
+\r
+ This internal function depends on a feature flag named PcdIchSmbusFixedIoPortBaseAddress\r
+ to retrieve Smbus Io port base. If that feature flag is true, it will get Smbus Io port base\r
+ address from a preset Pcd entry named PcdIchSmbusIoPortBaseAddress; otherwise, it will always\r
+ read Pci configuration space to get that value in each Smbus bus transaction.\r
+\r
+ @return The Io port base address of Smbus host controller.\r
+\r
+**/\r
+UINTN\r
+GetSmbusIoPortBaseAddress (\r
+ VOID\r
+ )\r
+{\r
+ UINTN IoPortBaseAddress;\r
+\r
+ if (FeaturePcdGet (PcdSmbaIoBaseAddressFixed)) {\r
+ IoPortBaseAddress = (UINTN) PcdGet16 (PcdSmbaIoBaseAddress);\r
+ } else {\r
+ IoPortBaseAddress = (UINTN) LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) & B_QNC_LPC_SMBUS_BASE_MASK;\r
+ }\r
+\r
+ //\r
+ // Make sure that the IO port base address has been properly set.\r
+ //\r
+ ASSERT (IoPortBaseAddress != 0);\r
+\r
+ return IoPortBaseAddress;\r
+}\r
+\r
+\r
+VOID\r
+InitializeInternal (\r
+ )\r
+{\r
+ UINTN IoPortBaseAddress;\r
+\r
+ IoPortBaseAddress = GetSmbusIoPortBaseAddress ();\r
+\r
+ //\r
+ // Step1: Enable QNC SMBUS I/O space.\r
+ //\r
+ LpcPciCfg32Or(R_QNC_LPC_SMBUS_BASE, B_QNC_LPC_SMBUS_BASE_EN);\r
+\r
+ //\r
+ // Step2: Clear Status Register before anyone uses the interfaces.\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);\r
+\r
+ //\r
+ // Step3: Program the correct smbus clock\r
+ //\r
+ IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCLK, V_QNC_SMBUS_HCLK_100KHZ);\r
+}\r
+\r
+\r
+\r
+\r
+BOOLEAN\r
+IsAddressAvailable (\r
+ IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress\r
+ )\r
+{\r
+ UINT8 Index;\r
+\r
+ //\r
+ // See if we have already assigned this address to a device\r
+ //\r
+ for (Index = 0; Index < mDeviceMapEntries; Index++) {\r
+ if (SlaveAddress.SmbusDeviceAddress ==\r
+ mDeviceMap[Index].SmbusDeviceAddress.SmbusDeviceAddress) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // See if this address is claimed by a platform non-ARP-capable device\r
+ //\r
+ for (Index = 0; Index < mPlatformNumRsvd; Index++) {\r
+ if ((SlaveAddress.SmbusDeviceAddress << 1) == mPlatformAddrRsvd[Index]) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ //\r
+ // See if this is a reserved address\r
+ //\r
+ for (Index = 0; Index < SMBUS_NUM_RESERVED; Index++) {\r
+ if (SlaveAddress.SmbusDeviceAddress == (UINTN) mReservedAddress[Index]) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+GetNextAvailableAddress (\r
+ IN EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress\r
+ )\r
+{\r
+ for (SlaveAddress->SmbusDeviceAddress = 0x03;\r
+ SlaveAddress->SmbusDeviceAddress < 0x7F;\r
+ SlaveAddress->SmbusDeviceAddress++\r
+ ) {\r
+ if (IsAddressAvailable (*SlaveAddress)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return EFI_OUT_OF_RESOURCES;\r
+}\r
+\r
+EFI_STATUS\r
+SmbusPrepareToArp (\r
+ )\r
+{\r
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;\r
+ EFI_STATUS Status;\r
+ UINTN Length;\r
+ UINT8 Buffer;\r
+\r
+ SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;\r
+ Length = 1;\r
+ Buffer = SMBUS_DATA_PREPARE_TO_ARP;\r
+\r
+ Status = Execute (\r
+ SlaveAddress,\r
+ 0,\r
+ EfiSmbusSendByte,\r
+ TRUE,\r
+ &Length,\r
+ &Buffer\r
+ );\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+SmbusGetUdidGeneral (\r
+ IN OUT EFI_SMBUS_DEVICE_MAP *DeviceMap\r
+ )\r
+{\r
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;\r
+ EFI_STATUS Status;\r
+ UINTN Length;\r
+ UINT8 Buffer[SMBUS_GET_UDID_LENGTH];\r
+\r
+ SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;\r
+ Length = SMBUS_GET_UDID_LENGTH;\r
+\r
+ Status = Execute (\r
+ SlaveAddress,\r
+ SMBUS_DATA_GET_UDID_GENERAL,\r
+ EfiSmbusReadBlock,\r
+ TRUE,\r
+ &Length,\r
+ Buffer\r
+ );\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ if (Length == SMBUS_GET_UDID_LENGTH) {\r
+ DeviceMap->SmbusDeviceUdid.DeviceCapabilities = Buffer[0];\r
+ DeviceMap->SmbusDeviceUdid.VendorRevision = Buffer[1];\r
+ DeviceMap->SmbusDeviceUdid.VendorId = (UINT16)((Buffer[2] << 8) + Buffer[3]);\r
+ DeviceMap->SmbusDeviceUdid.DeviceId = (UINT16)((Buffer[4] << 8) + Buffer[5]);\r
+ DeviceMap->SmbusDeviceUdid.Interface = (UINT16)((Buffer[6] << 8) + Buffer[7]);\r
+ DeviceMap->SmbusDeviceUdid.SubsystemVendorId = (UINT16)((Buffer[8] << 8) + Buffer[9]);\r
+ DeviceMap->SmbusDeviceUdid.SubsystemDeviceId = (UINT16)((Buffer[10] << 8) + Buffer[11]);\r
+ DeviceMap->SmbusDeviceUdid.VendorSpecificId = (UINT32)((Buffer[12] << 24) + (Buffer[13] << 16) + (Buffer[14] << 8) + Buffer[15]);\r
+ DeviceMap->SmbusDeviceAddress.SmbusDeviceAddress = (UINT8)(Buffer[16] >> 1);\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+SmbusAssignAddress (\r
+ IN OUT EFI_SMBUS_DEVICE_MAP *DeviceMap\r
+ )\r
+{\r
+ EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;\r
+ EFI_STATUS Status;\r
+ UINTN Length;\r
+ UINT8 Buffer[SMBUS_GET_UDID_LENGTH];\r
+\r
+ Buffer[0] = DeviceMap->SmbusDeviceUdid.DeviceCapabilities;\r
+ Buffer[1] = DeviceMap->SmbusDeviceUdid.VendorRevision;\r
+ Buffer[2] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorId >> 8);\r
+ Buffer[3] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorId);\r
+ Buffer[4] = (UINT8)(DeviceMap->SmbusDeviceUdid.DeviceId >> 8);\r
+ Buffer[5] = (UINT8)(DeviceMap->SmbusDeviceUdid.DeviceId);\r
+ Buffer[6] = (UINT8)(DeviceMap->SmbusDeviceUdid.Interface >> 8);\r
+ Buffer[7] = (UINT8)(DeviceMap->SmbusDeviceUdid.Interface);\r
+ Buffer[8] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemVendorId >> 8);\r
+ Buffer[9] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemVendorId);\r
+ Buffer[10] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemDeviceId >> 8);\r
+ Buffer[11] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemDeviceId);\r
+ Buffer[12] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 24);\r
+ Buffer[13] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 16);\r
+ Buffer[14] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 8);\r
+ Buffer[15] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId);\r
+ Buffer[16] = (UINT8)(DeviceMap->SmbusDeviceAddress.SmbusDeviceAddress << 1);\r
+\r
+ SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;\r
+ Length = SMBUS_GET_UDID_LENGTH;\r
+\r
+ Status = Execute (\r
+ SlaveAddress,\r
+ SMBUS_DATA_ASSIGN_ADDRESS,\r
+ EfiSmbusWriteBlock,\r
+ TRUE,\r
+ &Length,\r
+ Buffer\r
+ );\r
+ return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+SmbusFullArp (\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SMBUS_DEVICE_MAP *CurrentDeviceMap;\r
+\r
+ Status = SmbusPrepareToArp ();\r
+ if (EFI_ERROR(Status)) {\r
+ if (Status == EFI_DEVICE_ERROR) {\r
+ //\r
+ // ARP is complete\r
+ //\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Main loop to ARP all ARP-capable devices\r
+ //\r
+ do {\r
+ CurrentDeviceMap = &mDeviceMap[mDeviceMapEntries];\r
+ Status = SmbusGetUdidGeneral (CurrentDeviceMap);\r
+ if (EFI_ERROR(Status)) {\r
+ break;\r
+ }\r
+\r
+ if (CurrentDeviceMap->SmbusDeviceAddress.SmbusDeviceAddress == (0xFF >> 1)) {\r
+ //\r
+ // If address is unassigned, assign it\r
+ //\r
+ Status = GetNextAvailableAddress (\r
+ &CurrentDeviceMap->SmbusDeviceAddress\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else if (((CurrentDeviceMap->SmbusDeviceUdid.DeviceCapabilities) & 0xC0) != 0) {\r
+ //\r
+ // if address is not fixed, check if the current address is available\r
+ //\r
+ if (!IsAddressAvailable (\r
+ CurrentDeviceMap->SmbusDeviceAddress\r
+ )) {\r
+ //\r
+ // if currently assigned address is already used, get a new one\r
+ //\r
+ Status = GetNextAvailableAddress (\r
+ &CurrentDeviceMap->SmbusDeviceAddress\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+ }\r
+\r
+ Status = SmbusAssignAddress (CurrentDeviceMap);\r
+ if (EFI_ERROR(Status)) {\r
+ //\r
+ // If there was a device error, just continue on and try again.\r
+ // Other errors should be reported.\r
+ //\r
+ if (Status != EFI_DEVICE_ERROR) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ //\r
+ // If there was no error, the address was assigned and we must update our\r
+ // records.\r
+ //\r
+ mDeviceMapEntries++;\r
+ }\r
+\r
+ } while (mDeviceMapEntries < MAX_SMBUS_DEVICES);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+SmbusDirectedArp (\r
+ IN EFI_SMBUS_UDID *SmbusUdid,\r
+ IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SMBUS_DEVICE_MAP *CurrentDeviceMap;\r
+\r
+ if (mDeviceMapEntries >= MAX_SMBUS_DEVICES) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ CurrentDeviceMap = &mDeviceMap[mDeviceMapEntries];\r
+\r
+ //\r
+ // Find an available address to assign\r
+ //\r
+ Status = GetNextAvailableAddress (\r
+ &CurrentDeviceMap->SmbusDeviceAddress\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ CurrentDeviceMap->SmbusDeviceUdid.DeviceCapabilities = SmbusUdid->DeviceCapabilities;\r
+ CurrentDeviceMap->SmbusDeviceUdid.DeviceId = SmbusUdid->DeviceId;\r
+ CurrentDeviceMap->SmbusDeviceUdid.Interface = SmbusUdid->Interface;\r
+ CurrentDeviceMap->SmbusDeviceUdid.SubsystemDeviceId = SmbusUdid->SubsystemDeviceId;\r
+ CurrentDeviceMap->SmbusDeviceUdid.SubsystemVendorId = SmbusUdid->SubsystemVendorId;\r
+ CurrentDeviceMap->SmbusDeviceUdid.VendorId = SmbusUdid->VendorId;\r
+ CurrentDeviceMap->SmbusDeviceUdid.VendorRevision = SmbusUdid->VendorRevision;\r
+ CurrentDeviceMap->SmbusDeviceUdid.VendorSpecificId = SmbusUdid->VendorSpecificId;\r
+\r
+ Status = SmbusAssignAddress (CurrentDeviceMap);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ mDeviceMapEntries++;\r
+ SlaveAddress->SmbusDeviceAddress = CurrentDeviceMap->SmbusDeviceAddress.SmbusDeviceAddress;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Executes an SMBus operation to an SMBus controller. Returns when either the command has been\r
+ executed or an error is encountered in doing the operation.\r
+\r
+ The Execute() function provides a standard way to execute an operation as defined in the System\r
+ Management Bus (SMBus) Specification. The resulting transaction will be either that the SMBus\r
+ slave devices accept this transaction or that this function returns with error.\r
+\r
+ @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.\r
+ @param SlaveAddress The SMBus slave address of the device with which to communicate.\r
+ @param Command This command is transmitted by the SMBus host controller to the\r
+ SMBus slave device and the interpretation is SMBus slave device\r
+ specific. It can mean the offset to a list of functions inside an\r
+ SMBus slave device. Not all operations or slave devices support\r
+ this command's registers.\r
+ @param Operation Signifies which particular SMBus hardware protocol instance that\r
+ it will use to execute the SMBus transactions. This SMBus\r
+ hardware protocol is defined by the SMBus Specification and is\r
+ not related to EFI.\r
+ @param PecCheck Defines if Packet Error Code (PEC) checking is required for this\r
+ operation.\r
+ @param Length Signifies the number of bytes that this operation will do. The\r
+ maximum number of bytes can be revision specific and operation\r
+ specific. This field will contain the actual number of bytes that\r
+ are executed for this operation. Not all operations require this\r
+ argument.\r
+ @param Buffer Contains the value of data to execute to the SMBus slave device.\r
+ Not all operations require this argument. The length of this\r
+ buffer is identified by Length.\r
+\r
+ @retval EFI_SUCCESS The last data that was returned from the access matched the poll\r
+ exit criteria.\r
+ @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).\r
+ @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is\r
+ determined by the SMBus host controller device.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval EFI_DEVICE_ERROR The request was not completed because a failure that was\r
+ reflected in the Host Status Register bit. Device errors are a\r
+ result of a transaction collision, illegal command field,\r
+ unclaimed cycle (host initiated), or bus errors (collisions).\r
+ @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.\r
+ @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead\r
+ and EfiSmbusQuickWrite. Length is outside the range of valid\r
+ values.\r
+ @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.\r
+ @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbusExecute (\r
+ IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
+ IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,\r
+ IN CONST EFI_SMBUS_DEVICE_COMMAND Command,\r
+ IN CONST EFI_SMBUS_OPERATION Operation,\r
+ IN CONST BOOLEAN PecCheck,\r
+ IN OUT UINTN *Length,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ InitializeInternal ();\r
+ return Execute (\r
+ SlaveAddress,\r
+ Command,\r
+ Operation,\r
+ PecCheck,\r
+ Length,\r
+ Buffer\r
+ );\r
+}\r
+\r
+/**\r
+ Sets the SMBus slave device addresses for the device with a given unique ID or enumerates the\r
+ entire bus.\r
+\r
+ The ArpDevice() function provides a standard way for a device driver to enumerate the entire\r
+ SMBus or specific devices on the bus.\r
+\r
+ @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.\r
+ @param ArpAll A Boolean expression that indicates if the host drivers need to\r
+ enumerate all the devices or enumerate only the device that is\r
+ identified by SmbusUdid. If ArpAll is TRUE, SmbusUdid and\r
+ SlaveAddress are optional. If ArpAll is FALSE, ArpDevice will\r
+ enumerate SmbusUdid and the address will be at SlaveAddress.\r
+ @param SmbusUdid The Unique Device Identifier (UDID) that is associated with this\r
+ device.\r
+ @param SlaveAddress The SMBus slave address that is associated with an SMBus UDID.\r
+\r
+ @retval EFI_SUCCESS The last data that was returned from the access matched the poll\r
+ exit criteria.\r
+ @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).\r
+ @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is\r
+ determined by the SMBus host controller device.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval EFI_DEVICE_ERROR The request was not completed because a failure that was\r
+ reflected in the Host Status Register bit. Device errors are a\r
+ result of a transaction collision, illegal command field,\r
+ unclaimed cycle (host initiated), or bus errors (collisions).\r
+ @retval EFI_UNSUPPORTED The corresponding SMBus operation is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbusArpDevice (\r
+ IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
+ IN BOOLEAN ArpAll,\r
+ IN EFI_SMBUS_UDID *SmbusUdid, OPTIONAL\r
+ IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress OPTIONAL\r
+ )\r
+{\r
+ InitializeInternal ();\r
+\r
+ if (ArpAll) {\r
+ return SmbusFullArp ();\r
+ } else {\r
+ if ((SmbusUdid == NULL) || (SlaveAddress == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ return SmbusDirectedArp ((EFI_SMBUS_UDID *)SmbusUdid, SlaveAddress);\r
+ }\r
+}\r
+\r
+/**\r
+ Returns a pointer to the Address Resolution Protocol (ARP) map that contains the ID/address pair\r
+ of the slave devices that were enumerated by the SMBus host controller driver.\r
+\r
+ The GetArpMap() function returns the mapping of all the SMBus devices that were enumerated by the\r
+ SMBus host driver.\r
+\r
+ @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.\r
+ @param Length Size of the buffer that contains the SMBus device map.\r
+ @param SmbusDeviceMap The pointer to the device map as enumerated by the SMBus\r
+ controller driver.\r
+\r
+ @retval EFI_SUCCESS The SMBus returned the current device map.\r
+ @retval EFI_UNSUPPORTED The corresponding operation is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbusGetArpMap (\r
+ IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
+ IN OUT UINTN *Length,\r
+ IN OUT EFI_SMBUS_DEVICE_MAP **SmbusDeviceMap\r
+ )\r
+{\r
+ *Length = mDeviceMapEntries;\r
+ *SmbusDeviceMap = mDeviceMap;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Allows a device driver to register for a callback when the bus driver detects a state that it\r
+ needs to propagate to other drivers that are registered for a callback.\r
+\r
+ The Notify() function registers all the callback functions to allow the bus driver to call these\r
+ functions when the SlaveAddress/Data pair happens.\r
+ If NotifyFunction is NULL, then ASSERT ().\r
+\r
+ @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.\r
+ @param SlaveAddress The SMBUS hardware address to which the SMBUS device is\r
+ preassigned or allocated.\r
+ @param Data Data of the SMBus host notify command that the caller wants to be\r
+ called.\r
+ @param NotifyFunction The function to call when the bus driver detects the SlaveAddress\r
+ and Data pair.\r
+\r
+ @retval EFI_SUCCESS NotifyFunction was registered.\r
+ @retval EFI_UNSUPPORTED The corresponding operation is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbusNotify (\r
+ IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
+ IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,\r
+ IN CONST UINTN Data,\r
+ IN CONST EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction\r
+ )\r
+{\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Entry point to the DXE Driver that produces the SMBus Host Controller Protocol.\r
+\r
+ @param ImageHandle ImageHandle of the loaded driver.\r
+ @param SystemTable Pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The entry point of SMBus DXE driver is executed successfully.\r
+ @retval !EFI_SUCESS Some error occurs in the entry point of SMBus DXE driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeQNCSmbus (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ mPlatformNumRsvd = (UINT8)PcdGet32 (PcdPlatformSmbusAddrNum);\r
+ mPlatformAddrRsvd = (UINT8 *)(UINTN) PcdGet64 (PcdPlatformSmbusAddrTable);\r
+\r
+ //\r
+ // Install SMBus Host Controller protocol interface.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mSmbusHcHandle,\r
+ &gEfiSmbusHcProtocolGuid,\r
+ &mSmbusHc,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Header file for the defintions used in SMBus DXE driver.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef _DXE_QNC_SMBUS_H_\r
+#define _DXE_QNC_SMBUS_H_\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmbus.h"\r
+\r
+#define MAX_SMBUS_DEVICES 107 // Max number of SMBus devices (7 bit\r
+ // address yields 128 combinations but 21\r
+ // of those are reserved)\r
+\r
+#define MICROSECOND 10\r
+#define MILLISECOND (1000 * MICROSECOND)\r
+#define ONESECOND (1000 * MILLISECOND)\r
+\r
+#define STALL_TIME 1000000 // 1,000,000 microseconds = 1 second\r
+#define BUS_TRIES 3 // How many times to retry on Bus Errors\r
+#define SMBUS_NUM_RESERVED 21 // Number of device addresses that are\r
+ // reserved by the SMBus spec.\r
+#define SMBUS_ADDRESS_ARP 0xC2 >> 1\r
+#define SMBUS_DATA_PREPARE_TO_ARP 0x01\r
+#define SMBUS_DATA_RESET_DEVICE 0x02\r
+#define SMBUS_DATA_GET_UDID_GENERAL 0x03\r
+#define SMBUS_DATA_ASSIGN_ADDRESS 0x04\r
+#define SMBUS_GET_UDID_LENGTH 17 // 16 byte UDID + 1 byte address\r
+\r
+/**\r
+ Executes an SMBus operation to an SMBus controller. Returns when either the command has been\r
+ executed or an error is encountered in doing the operation.\r
+\r
+ The Execute() function provides a standard way to execute an operation as defined in the System\r
+ Management Bus (SMBus) Specification. The resulting transaction will be either that the SMBus\r
+ slave devices accept this transaction or that this function returns with error.\r
+\r
+ @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.\r
+ @param SlaveAddress The SMBus slave address of the device with which to communicate.\r
+ @param Command This command is transmitted by the SMBus host controller to the\r
+ SMBus slave device and the interpretation is SMBus slave device\r
+ specific. It can mean the offset to a list of functions inside an\r
+ SMBus slave device. Not all operations or slave devices support\r
+ this command's registers.\r
+ @param Operation Signifies which particular SMBus hardware protocol instance that\r
+ it will use to execute the SMBus transactions. This SMBus\r
+ hardware protocol is defined by the SMBus Specification and is\r
+ not related to EFI.\r
+ @param PecCheck Defines if Packet Error Code (PEC) checking is required for this\r
+ operation.\r
+ @param Length Signifies the number of bytes that this operation will do. The\r
+ maximum number of bytes can be revision specific and operation\r
+ specific. This field will contain the actual number of bytes that\r
+ are executed for this operation. Not all operations require this\r
+ argument.\r
+ @param Buffer Contains the value of data to execute to the SMBus slave device.\r
+ Not all operations require this argument. The length of this\r
+ buffer is identified by Length.\r
+\r
+ @retval EFI_SUCCESS The last data that was returned from the access matched the poll\r
+ exit criteria.\r
+ @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).\r
+ @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is\r
+ determined by the SMBus host controller device.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval EFI_DEVICE_ERROR The request was not completed because a failure that was\r
+ reflected in the Host Status Register bit. Device errors are a\r
+ result of a transaction collision, illegal command field,\r
+ unclaimed cycle (host initiated), or bus errors (collisions).\r
+ @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.\r
+ @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead\r
+ and EfiSmbusQuickWrite. Length is outside the range of valid\r
+ values.\r
+ @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.\r
+ @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbusExecute (\r
+ IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
+ IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,\r
+ IN CONST EFI_SMBUS_DEVICE_COMMAND Command,\r
+ IN CONST EFI_SMBUS_OPERATION Operation,\r
+ IN CONST BOOLEAN PecCheck,\r
+ IN OUT UINTN *Length,\r
+ IN OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Sets the SMBus slave device addresses for the device with a given unique ID or enumerates the\r
+ entire bus.\r
+\r
+ The ArpDevice() function provides a standard way for a device driver to enumerate the entire\r
+ SMBus or specific devices on the bus.\r
+\r
+ @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.\r
+ @param ArpAll A Boolean expression that indicates if the host drivers need to\r
+ enumerate all the devices or enumerate only the device that is\r
+ identified by SmbusUdid. If ArpAll is TRUE, SmbusUdid and\r
+ SlaveAddress are optional. If ArpAll is FALSE, ArpDevice will\r
+ enumerate SmbusUdid and the address will be at SlaveAddress.\r
+ @param SmbusUdid The Unique Device Identifier (UDID) that is associated with this\r
+ device.\r
+ @param SlaveAddress The SMBus slave address that is associated with an SMBus UDID.\r
+\r
+ @retval EFI_SUCCESS The last data that was returned from the access matched the poll\r
+ exit criteria.\r
+ @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).\r
+ @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is\r
+ determined by the SMBus host controller device.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval EFI_DEVICE_ERROR The request was not completed because a failure that was\r
+ reflected in the Host Status Register bit. Device errors are a\r
+ result of a transaction collision, illegal command field,\r
+ unclaimed cycle (host initiated), or bus errors (collisions).\r
+ @retval EFI_UNSUPPORTED The corresponding operation is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbusArpDevice (\r
+ IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
+ IN BOOLEAN ArpAll,\r
+ IN EFI_SMBUS_UDID *SmbusUdid, OPTIONAL\r
+ IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress OPTIONAL\r
+ );\r
+\r
+/**\r
+ Returns a pointer to the Address Resolution Protocol (ARP) map that contains the ID/address pair\r
+ of the slave devices that were enumerated by the SMBus host controller driver.\r
+\r
+ The GetArpMap() function returns the mapping of all the SMBus devices that were enumerated by the\r
+ SMBus host driver.\r
+\r
+ @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.\r
+ @param Length Size of the buffer that contains the SMBus device map.\r
+ @param SmbusDeviceMap The pointer to the device map as enumerated by the SMBus\r
+ controller driver.\r
+\r
+ @retval EFI_SUCCESS The SMBus returned the current device map.\r
+ @retval EFI_UNSUPPORTED The corresponding operation is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbusGetArpMap (\r
+ IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
+ IN OUT UINTN *Length,\r
+ IN OUT EFI_SMBUS_DEVICE_MAP **SmbusDeviceMap\r
+ );\r
+\r
+/**\r
+ Allows a device driver to register for a callback when the bus driver detects a state that it\r
+ needs to propagate to other drivers that are registered for a callback.\r
+\r
+ The Notify() function registers all the callback functions to allow the bus driver to call these\r
+ functions when the SlaveAddress/Data pair happens.\r
+ If NotifyFunction is NULL, then ASSERT ().\r
+\r
+ @param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.\r
+ @param SlaveAddress The SMBUS hardware address to which the SMBUS device is\r
+ preassigned or allocated.\r
+ @param Data Data of the SMBus host notify command that the caller wants to be\r
+ called.\r
+ @param NotifyFunction The function to call when the bus driver detects the SlaveAddress\r
+ and Data pair.\r
+\r
+ @retval EFI_SUCCESS NotifyFunction was registered.\r
+ @retval EFI_UNSUPPORTED The corresponding operation is not supported.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmbusNotify (\r
+ IN CONST EFI_SMBUS_HC_PROTOCOL *This,\r
+ IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,\r
+ IN CONST UINTN Data,\r
+ IN CONST EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction\r
+ );\r
+\r
+/**\r
+ Entry point to the DXE Driver that produces the SMBus Host Controller Protocol.\r
+\r
+ @param ImageHandle ImageHandle of the loaded driver.\r
+ @param SystemTable Pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The entry point of SMBus DXE driver is executed successfully.\r
+ @retval !EFI_SUCESS Some error occurs in the entry point of SMBus DXE driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeQNCSmbus (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+QNC Legacy Region Driver\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "CommonHeader.h"\r
+#include "LegacyRegion.h"\r
+\r
+//\r
+// Handle used to install the Legacy Region Protocol\r
+//\r
+EFI_HANDLE mLegacyRegion2Handle = NULL;\r
+\r
+//\r
+// Instance of the Legacy Region Protocol to install into the handle database\r
+//\r
+EFI_LEGACY_REGION2_PROTOCOL mLegacyRegion2 = {\r
+ LegacyRegion2Decode,\r
+ LegacyRegion2Lock,\r
+ LegacyRegion2BootLock,\r
+ LegacyRegion2Unlock,\r
+ LegacyRegionGetInfo\r
+};\r
+\r
+\r
+/**\r
+ Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.\r
+\r
+ If the On parameter evaluates to TRUE, this function enables memory reads in the address range\r
+ Start to (Start + Length - 1).\r
+ If the On parameter evaluates to FALSE, this function disables memory reads in the address range\r
+ Start to (Start + Length - 1).\r
+\r
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
+ @param Start[in] The beginning of the physical address of the region whose attributes\r
+ should be modified.\r
+ @param Length[in] The number of bytes of memory whose attributes should be modified.\r
+ The actual number of bytes modified may be greater than the number\r
+ specified.\r
+ @param Granularity[out] The number of bytes in the last region affected. This may be less\r
+ than the total number of bytes affected if the starting address\r
+ was not aligned to a region's starting address or if the length\r
+ was greater than the number of bytes in the first region.\r
+ @param On[in] Decode / Non-Decode flag.\r
+\r
+ @retval EFI_SUCCESS The region's attributes were successfully modified.\r
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyRegion2Decode (\r
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
+ IN UINT32 Start,\r
+ IN UINT32 Length,\r
+ OUT UINT32 *Granularity,\r
+ IN BOOLEAN *On\r
+ )\r
+{\r
+ return QNCLegacyRegionManipulation (Start, Length, On, NULL, Granularity);\r
+}\r
+\r
+\r
+/**\r
+ Modify the hardware to disallow memory attribute changes in a region.\r
+\r
+ This function makes the attributes of a region read only. Once a region is boot-locked with this\r
+ function, the read and write attributes of that region cannot be changed until a power cycle has\r
+ reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.\r
+\r
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
+ @param Start[in] The beginning of the physical address of the region whose\r
+ attributes should be modified.\r
+ @param Length[in] The number of bytes of memory whose attributes should be modified.\r
+ The actual number of bytes modified may be greater than the number\r
+ specified.\r
+ @param Granularity[out] The number of bytes in the last region affected. This may be less\r
+ than the total number of bytes affected if the starting address was\r
+ not aligned to a region's starting address or if the length was\r
+ greater than the number of bytes in the first region.\r
+\r
+ @retval EFI_SUCCESS The region's attributes were successfully modified.\r
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
+ @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in\r
+ a way that will not affect memory regions outside the legacy memory\r
+ region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyRegion2BootLock (\r
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
+ IN UINT32 Start,\r
+ IN UINT32 Length,\r
+ OUT UINT32 *Granularity\r
+ )\r
+{\r
+ if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+ Modify the hardware to disallow memory writes in a region.\r
+\r
+ This function changes the attributes of a memory range to not allow writes.\r
+\r
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
+ @param Start[in] The beginning of the physical address of the region whose\r
+ attributes should be modified.\r
+ @param Length[in] The number of bytes of memory whose attributes should be modified.\r
+ The actual number of bytes modified may be greater than the number\r
+ specified.\r
+ @param Granularity[out] The number of bytes in the last region affected. This may be less\r
+ than the total number of bytes affected if the starting address was\r
+ not aligned to a region's starting address or if the length was\r
+ greater than the number of bytes in the first region.\r
+\r
+ @retval EFI_SUCCESS The region's attributes were successfully modified.\r
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyRegion2Lock (\r
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
+ IN UINT32 Start,\r
+ IN UINT32 Length,\r
+ OUT UINT32 *Granularity\r
+ )\r
+{\r
+ BOOLEAN WriteEnable;\r
+\r
+ WriteEnable = FALSE;\r
+ return QNCLegacyRegionManipulation (Start, Length, NULL, &WriteEnable, Granularity);\r
+}\r
+\r
+\r
+/**\r
+ Modify the hardware to allow memory writes in a region.\r
+\r
+ This function changes the attributes of a memory range to allow writes.\r
+\r
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
+ @param Start[in] The beginning of the physical address of the region whose\r
+ attributes should be modified.\r
+ @param Length[in] The number of bytes of memory whose attributes should be modified.\r
+ The actual number of bytes modified may be greater than the number\r
+ specified.\r
+ @param Granularity[out] The number of bytes in the last region affected. This may be less\r
+ than the total number of bytes affected if the starting address was\r
+ not aligned to a region's starting address or if the length was\r
+ greater than the number of bytes in the first region.\r
+\r
+ @retval EFI_SUCCESS The region's attributes were successfully modified.\r
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyRegion2Unlock (\r
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
+ IN UINT32 Start,\r
+ IN UINT32 Length,\r
+ OUT UINT32 *Granularity\r
+ )\r
+{\r
+ BOOLEAN WriteEnable;\r
+\r
+ WriteEnable = TRUE;\r
+ return QNCLegacyRegionManipulation (Start, Length, NULL, &WriteEnable, Granularity);\r
+}\r
+\r
+/**\r
+ Get region information for the attributes of the Legacy Region.\r
+\r
+ This function is used to discover the granularity of the attributes for the memory in the legacy\r
+ region. Each attribute may have a different granularity and the granularity may not be the same\r
+ for all memory ranges in the legacy region.\r
+\r
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
+ @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor\r
+ buffer.\r
+ @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy\r
+ region information is deposited. This buffer will contain a list of\r
+ DescriptorCount number of region descriptors. This function will\r
+ provide the memory for the buffer.\r
+\r
+ @retval EFI_SUCCESS The region's attributes were successfully modified.\r
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyRegionGetInfo (\r
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
+ OUT UINT32 *DescriptorCount,\r
+ OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor\r
+ )\r
+{\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+ Entry point to the DXE Driver that produces the Legacy Region Protocol.\r
+\r
+ @retval EFI_SUCCESS One or more of the drivers returned a success code.\r
+ @retval !EFI_SUCESS The return status from the last driver entry point in the list.\r
+\r
+**/\r
+EFI_STATUS\r
+LegacyRegionInit (\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Install the Legacy Region Protocol on a new handle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mLegacyRegion2Handle,\r
+ &gEfiLegacyRegion2ProtocolGuid, &mLegacyRegion2,\r
+ NULL\r
+ );\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+The header file legacy region initialization in QNC DXE component.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _LEGACY_REGION_H_\r
+#define _LEGACY_REGION_H_\r
+#include "CommonHeader.h"\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#define LEGACY_REGION_INSTANCE_SIGNATURE SIGNATURE_32('R','E','G','N')\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+\r
+ EFI_HANDLE Handle;\r
+ EFI_LEGACY_REGION2_PROTOCOL LegacyRegion2;\r
+ EFI_HANDLE ImageHandle;\r
+\r
+ //\r
+ // Protocol for PAM register access\r
+ //\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+} LEGACY_REGION_INSTANCE;\r
+\r
+#define LEGACY_REGION_INSTANCE_FROM_THIS(this) \\r
+ CR(this, LEGACY_REGION_INSTANCE, LegacyRegion2, LEGACY_REGION_INSTANCE_SIGNATURE)\r
+\r
+\r
+EFI_STATUS\r
+LegacyRegionManipluateRegion (\r
+ IN LEGACY_REGION_INSTANCE *Private\r
+ );\r
+\r
+EFI_STATUS\r
+LegacyRegionInit (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.\r
+\r
+ If the On parameter evaluates to TRUE, this function enables memory reads in the address range\r
+ Start to (Start + Length - 1).\r
+ If the On parameter evaluates to FALSE, this function disables memory reads in the address range\r
+ Start to (Start + Length - 1).\r
+\r
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
+ @param Start[in] The beginning of the physical address of the region whose attributes\r
+ should be modified.\r
+ @param Length[in] The number of bytes of memory whose attributes should be modified.\r
+ The actual number of bytes modified may be greater than the number\r
+ specified.\r
+ @param Granularity[out] The number of bytes in the last region affected. This may be less\r
+ than the total number of bytes affected if the starting address\r
+ was not aligned to a region's starting address or if the length\r
+ was greater than the number of bytes in the first region.\r
+ @param On[in] Decode / Non-Decode flag.\r
+\r
+ @retval EFI_SUCCESS The region's attributes were successfully modified.\r
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyRegion2Decode (\r
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
+ IN UINT32 Start,\r
+ IN UINT32 Length,\r
+ OUT UINT32 *Granularity,\r
+ IN BOOLEAN *On\r
+ );\r
+\r
+/**\r
+ Modify the hardware to disallow memory writes in a region.\r
+\r
+ This function changes the attributes of a memory range to not allow writes.\r
+\r
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
+ @param Start[in] The beginning of the physical address of the region whose\r
+ attributes should be modified.\r
+ @param Length[in] The number of bytes of memory whose attributes should be modified.\r
+ The actual number of bytes modified may be greater than the number\r
+ specified.\r
+ @param Granularity[out] The number of bytes in the last region affected. This may be less\r
+ than the total number of bytes affected if the starting address was\r
+ not aligned to a region's starting address or if the length was\r
+ greater than the number of bytes in the first region.\r
+\r
+ @retval EFI_SUCCESS The region's attributes were successfully modified.\r
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyRegion2Lock (\r
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
+ IN UINT32 Start,\r
+ IN UINT32 Length,\r
+ OUT UINT32 *Granularity\r
+ );\r
+\r
+/**\r
+ Modify the hardware to disallow memory attribute changes in a region.\r
+\r
+ This function makes the attributes of a region read only. Once a region is boot-locked with this\r
+ function, the read and write attributes of that region cannot be changed until a power cycle has\r
+ reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.\r
+\r
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
+ @param Start[in] The beginning of the physical address of the region whose\r
+ attributes should be modified.\r
+ @param Length[in] The number of bytes of memory whose attributes should be modified.\r
+ The actual number of bytes modified may be greater than the number\r
+ specified.\r
+ @param Granularity[out] The number of bytes in the last region affected. This may be less\r
+ than the total number of bytes affected if the starting address was\r
+ not aligned to a region's starting address or if the length was\r
+ greater than the number of bytes in the first region.\r
+\r
+ @retval EFI_SUCCESS The region's attributes were successfully modified.\r
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
+ @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in\r
+ a way that will not affect memory regions outside the legacy memory\r
+ region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyRegion2BootLock (\r
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
+ IN UINT32 Start,\r
+ IN UINT32 Length,\r
+ OUT UINT32 *Granularity\r
+ );\r
+\r
+/**\r
+ Modify the hardware to allow memory writes in a region.\r
+\r
+ This function changes the attributes of a memory range to allow writes.\r
+\r
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
+ @param Start[in] The beginning of the physical address of the region whose\r
+ attributes should be modified.\r
+ @param Length[in] The number of bytes of memory whose attributes should be modified.\r
+ The actual number of bytes modified may be greater than the number\r
+ specified.\r
+ @param Granularity[out] The number of bytes in the last region affected. This may be less\r
+ than the total number of bytes affected if the starting address was\r
+ not aligned to a region's starting address or if the length was\r
+ greater than the number of bytes in the first region.\r
+\r
+ @retval EFI_SUCCESS The region's attributes were successfully modified.\r
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyRegion2Unlock (\r
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
+ IN UINT32 Start,\r
+ IN UINT32 Length,\r
+ OUT UINT32 *Granularity\r
+ );\r
+\r
+/**\r
+ Get region information for the attributes of the Legacy Region.\r
+\r
+ This function is used to discover the granularity of the attributes for the memory in the legacy\r
+ region. Each attribute may have a different granularity and the granularity may not be the same\r
+ for all memory ranges in the legacy region.\r
+\r
+ @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
+ @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor\r
+ buffer.\r
+ @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy\r
+ region information is deposited. This buffer will contain a list of\r
+ DescriptorCount number of region descriptors. This function will\r
+ provide the memory for the buffer.\r
+\r
+ @retval EFI_SUCCESS The region's attributes were successfully modified.\r
+ @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LegacyRegionGetInfo (\r
+ IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
+ OUT UINT32 *DescriptorCount,\r
+ OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor\r
+ );\r
+\r
+#endif //_QNC_LEGACY_REGION_H_\r
--- /dev/null
+/** @file\r
+QuarkNcSocId module initialization module\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "CommonHeader.h"\r
+\r
+#include "LegacyRegion.h"\r
+#include "DxeQNCSmbus.h"\r
+\r
+#include "QNCInit.h"\r
+\r
+//\r
+// Definitions\r
+//\r
+#define QNC_RESERVED_ITEM_IO 0\r
+#define QNC_RESERVED_ITEM_MEMORYIO 1\r
+#define DXE_DEVICE_DISABLED 0\r
+#define DXE_DEVICE_ENABLED 1\r
+\r
+typedef struct _QNC_SPACE_TABLE_ITEM {\r
+ UINTN IoOrMemory;\r
+ UINTN Type;\r
+ EFI_PHYSICAL_ADDRESS BaseAddress;\r
+ UINT64 Length;\r
+ UINTN Alignment;\r
+ BOOLEAN RuntimeOrNot;\r
+} QNC_SPACE_TABLE_ITEM;\r
+\r
+typedef struct {\r
+ ACPI_CPU_DATA AcpuCpuData;\r
+ MTRR_SETTINGS MtrrTable;\r
+ IA32_DESCRIPTOR GdtrProfile;\r
+ IA32_DESCRIPTOR IdtrProfile;\r
+ CPU_REGISTER_TABLE RegisterTable;\r
+ CPU_REGISTER_TABLE PreSmmInitRegisterTable;\r
+} ACPI_CPU_DATA_EX;\r
+\r
+//\r
+// Spaces to be reserved in GCD\r
+// Expand it to add more\r
+//\r
+const QNC_SPACE_TABLE_ITEM mQNCReservedSpaceTable[] = {\r
+ {\r
+ QNC_RESERVED_ITEM_MEMORYIO,\r
+ EfiGcdMemoryTypeMemoryMappedIo,\r
+ FixedPcdGet64 (PcdIoApicBaseAddress),\r
+ FixedPcdGet64 (PcdIoApicSize),\r
+ 0,\r
+ FALSE\r
+ },\r
+ {\r
+ QNC_RESERVED_ITEM_MEMORYIO,\r
+ EfiGcdMemoryTypeMemoryMappedIo,\r
+ FixedPcdGet64 (PcdHpetBaseAddress),\r
+ FixedPcdGet64 (PcdHpetSize),\r
+ 0,\r
+ FALSE\r
+ }\r
+};\r
+\r
+//\r
+// Global variable for ImageHandle of QNCInit driver\r
+//\r
+EFI_HANDLE gQNCInitImageHandle;\r
+QNC_DEVICE_ENABLES mQNCDeviceEnables;\r
+\r
+\r
+VOID\r
+QNCInitializeResource (\r
+ VOID\r
+ );\r
+\r
+EFI_STATUS\r
+InitializeQNCPolicy (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Allocate EfiACPIMemoryNVS below 4G memory address.\r
+\r
+ This function allocates EfiACPIMemoryNVS below 4G memory address.\r
+\r
+ @param Size Size of memory to allocate.\r
+\r
+ @return Allocated address for output.\r
+\r
+**/\r
+VOID *\r
+AllocateAcpiNvsMemoryBelow4G (\r
+ IN UINTN Size\r
+ )\r
+{\r
+ UINTN Pages;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ EFI_STATUS Status;\r
+ VOID* Buffer;\r
+\r
+ Pages = EFI_SIZE_TO_PAGES (Size);\r
+ Address = 0xffffffff;\r
+\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiACPIMemoryNVS,\r
+ Pages,\r
+ &Address\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Buffer = (VOID *) (UINTN) Address;\r
+ ZeroMem (Buffer, Size);\r
+\r
+ return Buffer;\r
+}\r
+\r
+/**\r
+ Prepare ACPI NVS memory below 4G memory for use of S3 resume.\r
+\r
+ This function allocates ACPI NVS memory below 4G memory for use of S3 resume,\r
+ and saves data into the memory region.\r
+\r
+**/\r
+VOID\r
+SaveCpuS3Data (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ ACPI_CPU_DATA_EX *AcpiCpuDataEx;\r
+ ACPI_CPU_DATA *AcpiCpuData;\r
+ UINTN GdtSize;\r
+ UINTN IdtSize;\r
+ VOID *Gdt;\r
+ VOID *Idt;\r
+\r
+ //\r
+ // Allocate ACPI NVS memory below 4G memory for use of S3 resume.\r
+ //\r
+ AcpiCpuDataEx = AllocateAcpiNvsMemoryBelow4G (sizeof (ACPI_CPU_DATA_EX));\r
+ AcpiCpuData = &AcpiCpuDataEx->AcpuCpuData;\r
+\r
+ //\r
+ //\r
+ //\r
+ AcpiCpuData->NumberOfCpus = 1;\r
+ AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize);\r
+ AcpiCpuData->ApMachineCheckHandlerBase = 0;\r
+ AcpiCpuData->ApMachineCheckHandlerSize = 0;\r
+ AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->GdtrProfile;\r
+ AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->IdtrProfile;\r
+ AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->MtrrTable;\r
+ AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->RegisterTable;\r
+ AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->PreSmmInitRegisterTable;\r
+\r
+ //\r
+ // Allocate stack space for all CPUs\r
+ //\r
+ AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateAcpiNvsMemoryBelow4G (AcpiCpuData->NumberOfCpus * AcpiCpuData->StackSize);\r
+\r
+ //\r
+ // Get MTRR settings from currently executing CPU\r
+ //\r
+ MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);\r
+\r
+ //\r
+ // Get the BSP's data of GDT and IDT\r
+ //\r
+ AsmReadGdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->GdtrProfile);\r
+ AsmReadIdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->IdtrProfile);\r
+\r
+ //\r
+ // Allocate GDT and IDT in ACPI NVS and copy in current GDT and IDT contents\r
+ //\r
+ GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;\r
+ IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;\r
+ Gdt = AllocateAcpiNvsMemoryBelow4G (GdtSize + IdtSize);\r
+ Idt = (VOID *)((UINTN)Gdt + GdtSize);\r
+ CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);\r
+ CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);\r
+ AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;\r
+ AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;\r
+\r
+ //\r
+ // No RegisterTable entries\r
+ //\r
+ AcpiCpuDataEx->RegisterTable.TableLength = 0;\r
+\r
+ //\r
+ // No PreSmmInitRegisterTable entries\r
+ //\r
+ AcpiCpuDataEx->PreSmmInitRegisterTable.TableLength = 0;\r
+\r
+ //\r
+ // Set the base address of CPU S3 data to PcdCpuS3DataAddress\r
+ //\r
+ Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);\r
+ ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+ The entry function for QNCInit driver.\r
+\r
+ This function just call initialization function for PciHostBridge,\r
+ LegacyRegion and QNCSmmAccess module.\r
+\r
+ @param ImageHandle The driver image handle for GmchInit driver\r
+ @param SystemTable The pointer to System Table\r
+\r
+ @retval EFI_SUCCESS Success to initialize every module for GMCH driver.\r
+ @return EFI_STATUS The status of initialization work.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+QNCInit (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ S3BootScriptSaveInformationAsciiString (\r
+ "QNCInitDxeEntryBegin"\r
+ );\r
+\r
+ gQNCInitImageHandle = ImageHandle;\r
+\r
+ mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables);\r
+\r
+\r
+ //\r
+ // Initialize PCIE root ports\r
+ //\r
+ Status = QncInitRootPorts ();\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "QNC Root Port initialization is failed!\n"));\r
+ return Status;\r
+ }\r
+\r
+ Status = LegacyRegionInit ();\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "QNC LegacyRegion initialization is failed!\n"));\r
+ return Status;\r
+ }\r
+\r
+\r
+ Status = InitializeQNCPolicy ();\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "QNC Policy initialization is failed!\n"));\r
+ return Status;\r
+ }\r
+\r
+ Status = InitializeQNCSmbus (ImageHandle,SystemTable);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "QNC Smbus driver is failed!\n"));\r
+ return Status;\r
+ }\r
+\r
+ QNCInitializeResource ();\r
+\r
+ SaveCpuS3Data ();\r
+\r
+ S3BootScriptSaveInformationAsciiString (\r
+ "QNCInitDxeEntryEnd"\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Reserve I/O or memory space in GCD\r
+\r
+ @param IoOrMemory Switch of I/O or memory.\r
+ @param GcdType Type of the space.\r
+ @param BaseAddress Base address of the space.\r
+ @param Length Length of the space.\r
+ @param Alignment Align with 2^Alignment\r
+ @param RuntimeOrNot For runtime usage or not\r
+ @param ImageHandle Handle for the image of this driver.\r
+\r
+ @retval EFI_SUCCESS Reserve successful\r
+**/\r
+EFI_STATUS\r
+QNCReserveSpaceInGcd(\r
+ IN UINTN IoOrMemory,\r
+ IN UINTN GcdType,\r
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
+ IN UINT64 Length,\r
+ IN UINTN Alignment,\r
+ IN BOOLEAN RuntimeOrNot,\r
+ IN EFI_HANDLE ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (IoOrMemory == QNC_RESERVED_ITEM_MEMORYIO) {\r
+ Status = gDS->AddMemorySpace (\r
+ GcdType,\r
+ BaseAddress,\r
+ Length,\r
+ EFI_MEMORY_UC\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "Failed to add memory space :0x%x 0x%x\n",\r
+ BaseAddress,\r
+ Length\r
+ ));\r
+ }\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = gDS->AllocateMemorySpace (\r
+ EfiGcdAllocateAddress,\r
+ GcdType,\r
+ Alignment,\r
+ Length,\r
+ &BaseAddress,\r
+ ImageHandle,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (RuntimeOrNot) {\r
+ Status = gDS->SetMemorySpaceAttributes (\r
+ BaseAddress,\r
+ Length,\r
+ EFI_MEMORY_RUNTIME | EFI_MEMORY_UC\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ } else {\r
+ Status = gDS->AddIoSpace (\r
+ GcdType,\r
+ BaseAddress,\r
+ Length\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = gDS->AllocateIoSpace (\r
+ EfiGcdAllocateAddress,\r
+ GcdType,\r
+ Alignment,\r
+ Length,\r
+ &BaseAddress,\r
+ ImageHandle,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Initialize the memory and io resource which belong to QNC.\r
+ 1) Report and allocate all BAR's memory to GCD.\r
+ 2) Report PCI memory and I/O space to GCD.\r
+ 3) Set memory attribute for <1M memory space.\r
+**/\r
+VOID\r
+QNCInitializeResource (\r
+ )\r
+{\r
+ EFI_PHYSICAL_ADDRESS BaseAddress;\r
+ EFI_STATUS Status;\r
+ UINT64 ExtraRegionLength;\r
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
+ UINTN Index;\r
+\r
+ // Report TSEG range\r
+ // This range maybe has been reportted in PEI phase via Resource Hob.\r
+ //\r
+ QNCGetTSEGMemoryRange (&BaseAddress, &ExtraRegionLength);\r
+ if (ExtraRegionLength != 0) {\r
+ Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &Descriptor);\r
+ if (Status == EFI_NOT_FOUND) {\r
+ Status = gDS->AddMemorySpace (\r
+ EfiGcdMemoryTypeReserved,\r
+ BaseAddress,\r
+ ExtraRegionLength,\r
+ EFI_MEMORY_UC\r
+ );\r
+ }\r
+ }\r
+\r
+ //\r
+ // < 1M resource setting. The memory ranges <1M has been added into GCD via\r
+ // resource hob produced by PEI phase. Here will set memory attribute of these\r
+ // ranges for DXE phase.\r
+ //\r
+\r
+ //\r
+ // Dos Area (0 ~ 0x9FFFFh)\r
+ //\r
+ Status = gDS->GetMemorySpaceDescriptor (0, &Descriptor);\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "DOS Area Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n",\r
+ Descriptor.BaseAddress,\r
+ Descriptor.Length,\r
+ Descriptor.Attributes\r
+ ));\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = gDS->SetMemorySpaceAttributes(\r
+ 0,\r
+ 0xA0000,\r
+ EFI_MEMORY_WB\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Default SMRAM UnCachable until SMBASE relocated.\r
+ //\r
+ Status = gDS->SetMemorySpaceAttributes(\r
+ 0x30000,\r
+ 0x10000,\r
+ EFI_MEMORY_UC\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Default SMM ABSEG area. (0xA0000 ~ 0xBFFFF)\r
+ //\r
+ Status = gDS->GetMemorySpaceDescriptor (0xA0000, &Descriptor);\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "ABSEG Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n",\r
+ Descriptor.BaseAddress,\r
+ Descriptor.Length,\r
+ Descriptor.Attributes\r
+ ));\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = gDS->SetMemorySpaceAttributes(\r
+ 0xA0000,\r
+ 0x20000,\r
+ EFI_MEMORY_UC\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Expansion BIOS area.\r
+ //\r
+ Status = gDS->GetMemorySpaceDescriptor (0xC0000, &Descriptor);\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "Memory base = 0x%x, length = 0x%x, attribute = 0x%x\n",\r
+ Descriptor.BaseAddress,\r
+ Descriptor.Length,\r
+ Descriptor.Attributes\r
+ ));\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = gDS->SetMemorySpaceAttributes(\r
+ 0xC0000,\r
+ 0x30000,\r
+ EFI_MEMORY_UC\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Report other IO resources from mQNCReservedSpaceTable in GCD\r
+ //\r
+ for (Index = 0; Index < sizeof (mQNCReservedSpaceTable) / sizeof (QNC_SPACE_TABLE_ITEM); Index++) {\r
+ Status = QNCReserveSpaceInGcd (\r
+ mQNCReservedSpaceTable[Index].IoOrMemory,\r
+ mQNCReservedSpaceTable[Index].Type,\r
+ mQNCReservedSpaceTable[Index].BaseAddress,\r
+ mQNCReservedSpaceTable[Index].Length,\r
+ mQNCReservedSpaceTable[Index].Alignment,\r
+ mQNCReservedSpaceTable[Index].RuntimeOrNot,\r
+ gQNCInitImageHandle\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ //\r
+ // Report unused PCIe config space as reserved.\r
+ //\r
+ if (PcdGet64 (PcdPciExpressSize) < SIZE_256MB) {\r
+ Status = QNCReserveSpaceInGcd (\r
+ QNC_RESERVED_ITEM_MEMORYIO,\r
+ EfiGcdMemoryTypeMemoryMappedIo,\r
+ (PcdGet64(PcdPciExpressBaseAddress) + PcdGet64(PcdPciExpressSize)),\r
+ (SIZE_256MB - PcdGet64(PcdPciExpressSize)),\r
+ 0,\r
+ FALSE,\r
+ gQNCInitImageHandle\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+}\r
+\r
+/**\r
+ Use the platform PCD to initialize devices in the QNC\r
+\r
+ @param ImageHandle Handle for the image of this driver.\r
+ @retval EFI_SUCCESS Initialize successful\r
+**/\r
+EFI_STATUS\r
+InitializeQNCPolicy (\r
+ )\r
+{\r
+ UINT8 RevisionID;\r
+ UINT32 PciD31F0RegBase; // LPC\r
+\r
+ RevisionID = LpcPciCfg8(R_QNC_LPC_REV_ID);\r
+\r
+ PciD31F0RegBase = PciDeviceMmBase (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC);\r
+\r
+ //\r
+ // Disable for smbus\r
+ //\r
+ if (mQNCDeviceEnables.Bits.Smbus == DXE_DEVICE_DISABLED) {\r
+ S3MmioAnd32 (PciD31F0RegBase + R_QNC_LPC_SMBUS_BASE, (~B_QNC_LPC_SMBUS_BASE_EN));\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+Header file for QNC Initialization Driver.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+#ifndef _QNC_INITIALIZATION_DRIVER_H_\r
+#define _QNC_INITIALIZATION_DRIVER_H_\r
+\r
+EFI_STATUS\r
+QncInitRootPorts (\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Perform Initialization of the Downstream Root Ports.\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+ EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+SetInitRootPortDownstreamS3Item (\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set an Init Root Port Downstream devices S3 dispatch item, this function may assert if any error happend\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS The function completed successfully\r
+\r
+--*/\r
+;\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Component description file for QNCInit driver.\r
+#\r
+# QNCInit driver implement QuarkNcSocId related drivers, includes:\r
+# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver.\r
+#\r
+# This driver mainly do full initialization for the QNC chipet includes:\r
+# 1. Initialize the PCI Express device.\r
+# 2. Initialize the PciHostBridge, and allocate the I/O and memory space from GCD service.\r
+# 3. Initialize the SmmAccess module and install EFI_SMM_ACCESS_PROTOCOL\r
+# 4. Initialize the LegacyRegion module, install EFI_LEGACY_REGION_PROTOCOL and set below 1M\r
+# memory attribute from MTRR.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = QNCInitDxe\r
+ FILE_GUID = 74D3B506-EE9C-47ed-B749-41261401DA78\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = QNCInit\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ LegacyRegion.h\r
+ LegacyRegion.c\r
+ DxeQNCSmbus.c\r
+ DxeQNCSmbus.h\r
+ QNCSmbusExec.c\r
+ QNCSmbus.h\r
+ QNCInit.c\r
+ QNCInit.h\r
+ CommonHeader.h\r
+ QNCRootPorts.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ UefiCpuPkg/UefiCpuPkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ UefiDriverEntryPoint\r
+ BaseLib\r
+ UefiBootServicesTableLib\r
+ DxeServicesTableLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ PcdLib\r
+ MtrrLib\r
+ IoLib\r
+ SmbusLib\r
+ S3IoLib\r
+ S3BootScriptLib\r
+ IntelQNCLib\r
+ QNCAccessLib\r
+\r
+[Protocols]\r
+ gEfiLegacyRegion2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiSmbusHcProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiQncS3SupportProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+\r
+[FeaturePcd]\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed\r
+\r
+[FixedPcd]\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicSize\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetSize\r
+\r
+[Pcd]\r
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES\r
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress|0x0|UINT64|0x60000010 ## PRODUCES\r
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## CONSUMES\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciExpressSize ## CONSUMES\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrNum\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrTable\r
+\r
+[Depex]\r
+ gEfiPlatformPolicyProtocolGuid AND gEfiQncS3SupportProtocolGuid\r
--- /dev/null
+/** @file\r
+PciHostBridge driver module, part of QNC module.\r
+\r
+Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "CommonHeader.h"\r
+#include "QNCInit.h"\r
+\r
+UINT32 mS3ParameterRootPortDownstream = 0;\r
+EFI_QNC_S3_DISPATCH_ITEM mS3DispatchItem = {\r
+ QncS3ItemTypeInitPcieRootPortDownstream,\r
+ &mS3ParameterRootPortDownstream\r
+ };\r
+\r
+EFI_STATUS\r
+QncInitRootPorts (\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Perform Initialization of the Downstream Root Ports\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS The function completed successfully\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_QNC_S3_SUPPORT_PROTOCOL *QncS3Support;\r
+ VOID *Context;\r
+ VOID *S3DispatchEntryPoint;\r
+\r
+ Status = PciExpressInit ();\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Get the QNC S3 Support Protocol\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiQncS3SupportProtocolGuid,\r
+ NULL,\r
+ (VOID **) &QncS3Support\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get the QNC S3 Support Protocol\r
+ //\r
+ Status = QncS3Support->SetDispatchItem (\r
+ QncS3Support,\r
+ &mS3DispatchItem,\r
+ &S3DispatchEntryPoint,\r
+ &Context\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Save the script dispatch item in the Boot Script\r
+ //\r
+ Status = S3BootScriptSaveDispatch2 (S3DispatchEntryPoint, Context);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+Common definitons for SMBus PEIM/DXE driver. Smbus PEI and DXE\r
+modules share the same version of this file.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _QNC_SMBUS_H_\r
+#define _QNC_SMBUS_H_\r
+\r
+#include "CommonHeader.h"\r
+\r
+//\r
+// Minimum and maximum length for SMBus bus block protocols defined in SMBus spec 2.0.\r
+//\r
+#define MIN_SMBUS_BLOCK_LEN 1\r
+#define MAX_SMBUS_BLOCK_LEN 32\r
+#define ADD_LENGTH(SmbusAddress, Length) ((SmbusAddress) + SMBUS_LIB_ADDRESS (0, 0, (Length), FALSE))\r
+\r
+/**\r
+ Executes an SMBus operation to an SMBus controller. Returns when either the command has been\r
+ executed or an error is encountered in doing the operation.\r
+\r
+ The internal worker function provides a standard way to execute an operation as defined in the\r
+ System Management Bus (SMBus) Specification. The resulting transaction will be either that the\r
+ SMBus slave devices accept this transaction or that this function returns with error.\r
+\r
+ @param SlaveAddress The SMBus slave address of the device with which to communicate.\r
+ @param Command This command is transmitted by the SMBus host controller to the\r
+ SMBus slave device and the interpretation is SMBus slave device\r
+ specific. It can mean the offset to a list of functions inside an\r
+ SMBus slave device. Not all operations or slave devices support\r
+ this command's registers.\r
+ @param Operation Signifies which particular SMBus hardware protocol instance that\r
+ it will use to execute the SMBus transactions. This SMBus\r
+ hardware protocol is defined by the SMBus Specification and is\r
+ not related to EFI.\r
+ @param PecCheck Defines if Packet Error Code (PEC) checking is required for this\r
+ operation.\r
+ @param Length Signifies the number of bytes that this operation will do. The\r
+ maximum number of bytes can be revision specific and operation\r
+ specific. This field will contain the actual number of bytes that\r
+ are executed for this operation. Not all operations require this\r
+ argument.\r
+ @param Buffer Contains the value of data to execute to the SMBus slave device.\r
+ Not all operations require this argument. The length of this\r
+ buffer is identified by Length.\r
+\r
+ @retval EFI_SUCCESS The last data that was returned from the access matched the poll\r
+ exit criteria.\r
+ @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).\r
+ @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is\r
+ determined by the SMBus host controller device.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval EFI_DEVICE_ERROR The request was not completed because a failure that was\r
+ reflected in the Host Status Register bit. Device errors are a\r
+ result of a transaction collision, illegal command field,\r
+ unclaimed cycle (host initiated), or bus errors (collisions).\r
+ @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.\r
+ @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead\r
+ and EfiSmbusQuickWrite. Length is outside the range of valid\r
+ values.\r
+ @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.\r
+ @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.\r
+\r
+**/\r
+EFI_STATUS\r
+Execute (\r
+ IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,\r
+ IN EFI_SMBUS_DEVICE_COMMAND Command,\r
+ IN EFI_SMBUS_OPERATION Operation,\r
+ IN BOOLEAN PecCheck,\r
+ IN OUT UINTN *Length,\r
+ IN OUT VOID *Buffer\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Common code to implement SMBus bus protocols. Smbus PEI and DXE modules\r
+share the same version of this file.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmbus.h"\r
+\r
+/**\r
+ Checks the parameter of SmbusExecute().\r
+\r
+ This function checks the input parameters of SmbusExecute(). If the input parameters are valid\r
+ for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain\r
+ error code based on the input SMBus bus protocol.\r
+\r
+ @param SlaveAddress The SMBus slave address of the device with which to communicate.\r
+ @param Command This command is transmitted by the SMBus host controller to the\r
+ SMBus slave device and the interpretation is SMBus slave device\r
+ specific. It can mean the offset to a list of functions inside an\r
+ SMBus slave device. Not all operations or slave devices support\r
+ this command's registers.\r
+ @param Operation Signifies which particular SMBus hardware protocol instance that\r
+ it will use to execute the SMBus transactions. This SMBus\r
+ hardware protocol is defined by the SMBus Specification and is\r
+ not related to EFI.\r
+ @param PecCheck Defines if Packet Error Code (PEC) checking is required for this\r
+ operation.\r
+ @param Length Signifies the number of bytes that this operation will do. The\r
+ maximum number of bytes can be revision specific and operation\r
+ specific. This field will contain the actual number of bytes that\r
+ are executed for this operation. Not all operations require this\r
+ argument.\r
+ @param Buffer Contains the value of data to execute to the SMBus slave device.\r
+ Not all operations require this argument. The length of this\r
+ buffer is identified by Length.\r
+\r
+ @retval EFI_SUCCESS All the parameters are valid for the corresponding SMBus bus\r
+ protocol.\r
+ @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.\r
+ @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead\r
+ and EfiSmbusQuickWrite. Length is outside the range of valid\r
+ values.\r
+ @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.\r
+ @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.\r
+\r
+**/\r
+EFI_STATUS\r
+QncSmbusExecCheckParameters (\r
+ IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,\r
+ IN EFI_SMBUS_DEVICE_COMMAND Command,\r
+ IN EFI_SMBUS_OPERATION Operation,\r
+ IN BOOLEAN PecCheck,\r
+ IN OUT UINTN *Length,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN RequiredLen;\r
+\r
+ //\r
+ // Set default value to be 2:\r
+ // for SmbusReadWord, SmbusWriteWord and SmbusProcessCall.\r
+ //\r
+ RequiredLen = 2;\r
+ Status = EFI_SUCCESS;\r
+ switch (Operation) {\r
+ case EfiSmbusQuickRead:\r
+ case EfiSmbusQuickWrite:\r
+ if (PecCheck || Command != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ break;\r
+ case EfiSmbusReceiveByte:\r
+ case EfiSmbusSendByte:\r
+ if (Command != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Cascade to check length parameter.\r
+ //\r
+ case EfiSmbusReadByte:\r
+ case EfiSmbusWriteByte:\r
+ RequiredLen = 1;\r
+ //\r
+ // Cascade to check length parameter.\r
+ //\r
+ case EfiSmbusReadWord:\r
+ case EfiSmbusWriteWord:\r
+ case EfiSmbusProcessCall:\r
+ if (Buffer == NULL || Length == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } else if (*Length < RequiredLen) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ *Length = RequiredLen;\r
+ break;\r
+ case EfiSmbusReadBlock:\r
+ case EfiSmbusWriteBlock:\r
+ if ((Buffer == NULL) ||\r
+ (Length == NULL) ||\r
+ (*Length < MIN_SMBUS_BLOCK_LEN) ||\r
+ (*Length > MAX_SMBUS_BLOCK_LEN)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ break;\r
+ case EfiSmbusBWBRProcessCall:\r
+ return EFI_UNSUPPORTED;\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Executes an SMBus operation to an SMBus controller. Returns when either the command has been\r
+ executed or an error is encountered in doing the operation.\r
+\r
+ The internal worker function provides a standard way to execute an operation as defined in the\r
+ System Management Bus (SMBus) Specification. The resulting transaction will be either that the\r
+ SMBus slave devices accept this transaction or that this function returns with error.\r
+\r
+ @param SlaveAddress The SMBus slave address of the device with which to communicate.\r
+ @param Command This command is transmitted by the SMBus host controller to the\r
+ SMBus slave device and the interpretation is SMBus slave device\r
+ specific. It can mean the offset to a list of functions inside an\r
+ SMBus slave device. Not all operations or slave devices support\r
+ this command's registers.\r
+ @param Operation Signifies which particular SMBus hardware protocol instance that\r
+ it will use to execute the SMBus transactions. This SMBus\r
+ hardware protocol is defined by the SMBus Specification and is\r
+ not related to EFI.\r
+ @param PecCheck Defines if Packet Error Code (PEC) checking is required for this\r
+ operation.\r
+ @param Length Signifies the number of bytes that this operation will do. The\r
+ maximum number of bytes can be revision specific and operation\r
+ specific. This field will contain the actual number of bytes that\r
+ are executed for this operation. Not all operations require this\r
+ argument.\r
+ @param Buffer Contains the value of data to execute to the SMBus slave device.\r
+ Not all operations require this argument. The length of this\r
+ buffer is identified by Length.\r
+\r
+ @retval EFI_SUCCESS The last data that was returned from the access matched the poll\r
+ exit criteria.\r
+ @retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).\r
+ @retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is\r
+ determined by the SMBus host controller device.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval EFI_DEVICE_ERROR The request was not completed because a failure that was\r
+ reflected in the Host Status Register bit. Device errors are a\r
+ result of a transaction collision, illegal command field,\r
+ unclaimed cycle (host initiated), or bus errors (collisions).\r
+ @retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.\r
+ @retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead\r
+ and EfiSmbusQuickWrite. Length is outside the range of valid\r
+ values.\r
+ @retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.\r
+ @retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.\r
+\r
+**/\r
+EFI_STATUS\r
+Execute (\r
+ IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,\r
+ IN EFI_SMBUS_DEVICE_COMMAND Command,\r
+ IN EFI_SMBUS_OPERATION Operation,\r
+ IN BOOLEAN PecCheck,\r
+ IN OUT UINTN *Length,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN SmbusAddress;\r
+ UINTN WorkBufferLen;\r
+ UINT8 WorkBuffer[MAX_SMBUS_BLOCK_LEN];\r
+\r
+ Status = QncSmbusExecCheckParameters (\r
+ SlaveAddress,\r
+ Command,\r
+ Operation,\r
+ PecCheck,\r
+ Length,\r
+ Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SmbusAddress = SMBUS_LIB_ADDRESS (SlaveAddress.SmbusDeviceAddress, Command, *Length, PecCheck);\r
+\r
+ switch (Operation) {\r
+ case EfiSmbusQuickRead:\r
+ SmBusQuickRead (SmbusAddress, &Status);\r
+ break;\r
+ case EfiSmbusQuickWrite:\r
+ SmBusQuickWrite (SmbusAddress, &Status);\r
+ break;\r
+ case EfiSmbusReceiveByte:\r
+ *(UINT8 *) Buffer = SmBusReceiveByte (SmbusAddress, &Status);\r
+ break;\r
+ case EfiSmbusSendByte:\r
+ SmBusSendByte (SmbusAddress, *(UINT8 *) Buffer, &Status);\r
+ break;\r
+ case EfiSmbusReadByte:\r
+ *(UINT8 *) Buffer = SmBusReadDataByte (SmbusAddress, &Status);\r
+ break;\r
+ case EfiSmbusWriteByte:\r
+ SmBusWriteDataByte (SmbusAddress, *(UINT8 *) Buffer, &Status);\r
+ break;\r
+ case EfiSmbusReadWord:\r
+ *(UINT16 *) Buffer = SmBusReadDataWord (SmbusAddress, &Status);\r
+ break;\r
+ case EfiSmbusWriteWord:\r
+ SmBusWriteDataWord (SmbusAddress, *(UINT16 *) Buffer, &Status);\r
+ break;\r
+ case EfiSmbusProcessCall:\r
+ *(UINT16 *) Buffer = SmBusProcessCall (SmbusAddress, *(UINT16 *) Buffer, &Status);\r
+ break;\r
+ case EfiSmbusReadBlock:\r
+ WorkBufferLen = SmBusReadBlock (SmbusAddress, WorkBuffer, &Status);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Read block transaction is complete successfully, and then\r
+ // check whether the output buffer is large enough.\r
+ //\r
+ if (*Length >= WorkBufferLen) {\r
+ CopyMem (Buffer, WorkBuffer, WorkBufferLen);\r
+ } else {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ *Length = WorkBufferLen;\r
+ }\r
+ break;\r
+ case EfiSmbusWriteBlock:\r
+ SmBusWriteBlock (ADD_LENGTH (SmbusAddress, *Length), Buffer, &Status);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+This is the driver that implements the QNC S3 Support protocol\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "QncS3Support.h"\r
+\r
+//\r
+// Global Variables\r
+//\r
+EFI_QNC_S3_SUPPORT_PROTOCOL mQncS3SupportProtocol;\r
+QNC_S3_PARAMETER_HEADER *mS3Parameter;\r
+UINT32 mQncS3ImageEntryPoint;\r
+VOID *mQncS3ImageAddress;\r
+UINTN mQncS3ImageSize;\r
+\r
+extern EFI_GUID gQncS3CodeInLockBoxGuid;\r
+extern EFI_GUID gQncS3ContextInLockBoxGuid;\r
+\r
+/**\r
+\r
+ Create a buffer that is used to store context information for use with\r
+ dispatch functions.\r
+\r
+ @retval EFI_SUCCESS - Buffer allocated and initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateContextBuffer (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ UINT32 ContextStoreSize;\r
+\r
+ ContextStoreSize = EFI_PAGE_SIZE;\r
+\r
+ //\r
+ // Allcoate <4G EfiReservedMemory\r
+ //\r
+ Address = 0xFFFFFFFF;\r
+ Status = gBS->AllocatePages (AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (ContextStoreSize), &Address);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ mS3Parameter = (QNC_S3_PARAMETER_HEADER *) (UINTN) Address;\r
+\r
+ //\r
+ // Determine the maximum number of context entries that can be stored in this\r
+ // table.\r
+ //\r
+ mS3Parameter->MaxContexts = ((ContextStoreSize - sizeof(QNC_S3_PARAMETER_HEADER)) / sizeof(EFI_DISPATCH_CONTEXT_UNION)) + 1;\r
+ mS3Parameter->StorePosition = 0;\r
+\r
+ return Status;\r
+}\r
+\r
+//\r
+// Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+QncS3SupportEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+\r
+ QNC S3 support driver entry point\r
+\r
+ Arguments:\r
+\r
+ ImageHandle - Handle for the image of this driver\r
+ SystemTable - Pointer to the EFI System Table\r
+\r
+ Returns:\r
+\r
+ EFI_STATUS\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *TmpPtr;\r
+ EFI_EVENT Event;\r
+\r
+ //\r
+ // If the protocol is found execution is happening in ACPI NVS memory. If it\r
+ // is not found copy the driver into ACPI NVS memory and pass control to it.\r
+ //\r
+ Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &TmpPtr);\r
+\r
+ //\r
+ // Load the QNC S3 image\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ Status = LoadQncS3Image (SystemTable);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ } else {\r
+ DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - Begin\n"));\r
+ //\r
+ // Allocate and initialize context buffer.\r
+ //\r
+ Status = CreateContextBuffer ();\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Install the QNC S3 Support protocol\r
+ //\r
+ mQncS3SupportProtocol.SetDispatchItem = QncS3SetDispatchItem;\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &ImageHandle,\r
+ &gEfiQncS3SupportProtocolGuid,\r
+ &mQncS3SupportProtocol,\r
+ NULL\r
+ );\r
+\r
+ mQncS3ImageAddress = (VOID *)(UINTN)PcdGet64(PcdQncS3CodeInLockBoxAddress);\r
+ mQncS3ImageSize = (UINTN)PcdGet64(PcdQncS3CodeInLockBoxSize);\r
+ DEBUG ((DEBUG_INFO, "QncS3SupportEntry Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize));\r
+ DEBUG ((DEBUG_INFO, "QncS3SupportEntry Contex = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE));\r
+ ASSERT (mQncS3ImageAddress != 0);\r
+\r
+ //\r
+ // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
+ //\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ QncS3BootEvent,\r
+ NULL,\r
+ &gEfiEndOfDxeEventGroupGuid,\r
+ &Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - End\n"));\r
+ }\r
+\r
+\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+QncS3SetDispatchItem (\r
+ IN EFI_QNC_S3_SUPPORT_PROTOCOL *This,\r
+ IN EFI_QNC_S3_DISPATCH_ITEM *DispatchItem,\r
+ OUT VOID **S3DispatchEntryPoint,\r
+ OUT VOID **Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set an item to be dispatched at S3 resume time. At the same time, the entry point\r
+ of the QNC S3 support image is returned to be used in subsequent boot script save\r
+ call\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the protocol instance.\r
+ DispatchItem - The item to be dispatched.\r
+ S3DispatchEntryPoint - The entry point of the QNC S3 support image.\r
+\r
+Returns:\r
+\r
+ EFI_STATUS - Successfully completed.\r
+ EFI_OUT_OF_RESOURCES - Out of resources.\r
+\r
+--*/\r
+{\r
+\r
+ DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() Start\n"));\r
+\r
+ //\r
+ // Set default values.\r
+ //\r
+ *S3DispatchEntryPoint = NULL;\r
+ *Context = NULL;\r
+\r
+ //\r
+ // Determine if this entry will fit.\r
+ //\r
+ if (mS3Parameter->StorePosition >= mS3Parameter->MaxContexts) {\r
+ DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem exceeds max length - 0x%08x\n", (UINTN)mS3Parameter->MaxContexts));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Calculate the size required;\r
+ // ** Always round up to be 8 byte aligned\r
+ //\r
+ switch (DispatchItem->Type) {\r
+ case QncS3ItemTypeInitPcieRootPortDownstream:\r
+ *S3DispatchEntryPoint = (VOID*) (UINTN)QncS3InitPcieRootPortDownstream;\r
+ *Context = &mS3Parameter->Contexts[mS3Parameter->StorePosition];\r
+ CopyMem (&mS3Parameter->Contexts[mS3Parameter->StorePosition], DispatchItem->Parameter, sizeof(UINT32));\r
+ DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream @ 0x%08x - context 0x%08x\n", (UINTN)*S3DispatchEntryPoint, (UINTN)*Context));\r
+ break;\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+\r
+ }\r
+\r
+ mS3Parameter->StorePosition ++;\r
+ DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() End\n"));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+LoadQncS3Image (\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Load the QNC S3 Image into Efi Reserved Memory below 4G.\r
+\r
+Arguments:\r
+\r
+ ImageEntryPoint the ImageEntryPoint after success loading\r
+\r
+Returns:\r
+\r
+ EFI_STATUS\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *Buffer;\r
+ UINTN BufferSize;\r
+ VOID *FfsBuffer;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+ EFI_HANDLE NewImageHandle;\r
+\r
+ //\r
+ // Install NULL protocol on module file handle to indicate that the entry point\r
+ // has been called for the first time.\r
+ //\r
+ NewImageHandle = NULL;\r
+ Status = gBS->InstallProtocolInterface (\r
+ &NewImageHandle,\r
+ &gEfiCallerIdGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ NULL\r
+ );\r
+\r
+\r
+ //\r
+ // Find this module so it can be loaded again.\r
+ //\r
+ Status = GetSectionFromAnyFv (\r
+ &gEfiCallerIdGuid,\r
+ EFI_SECTION_PE32,\r
+ 0,\r
+ (VOID**) &Buffer,\r
+ &BufferSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+\r
+ //\r
+ // Get information about the image being loaded.\r
+ //\r
+ ImageContext.Handle = Buffer;\r
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+\r
+ //\r
+ // Get information about the image being loaded\r
+ //\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->AllocatePool (\r
+ EfiReservedMemoryType,\r
+ BufferSize + ImageContext.SectionAlignment,\r
+ &FfsBuffer\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for no enough space! \n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ mQncS3ImageAddress = FfsBuffer;\r
+ mQncS3ImageSize = BufferSize + ImageContext.SectionAlignment;\r
+ Status = PcdSet64S (PcdQncS3CodeInLockBoxAddress, (UINT64)(UINTN)mQncS3ImageAddress);\r
+ ASSERT_EFI_ERROR (Status);\r
+ Status = PcdSet64S (PcdQncS3CodeInLockBoxSize, (UINT64)mQncS3ImageSize);\r
+ ASSERT_EFI_ERROR (Status);\r
+ //\r
+ // Align buffer on section boundry\r
+ //\r
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;\r
+ if (ImageContext.SectionAlignment != 0) {\r
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
+ ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
+ }\r
+\r
+ //\r
+ // Load the image to our new buffer\r
+ //\r
+ Status = PeCoffLoaderLoadImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (FfsBuffer);\r
+ DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderLoadImage failure! \n"));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Relocate the image in our new buffer\r
+ //\r
+ Status = PeCoffLoaderRelocateImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ PeCoffLoaderUnloadImage (&ImageContext);\r
+ gBS->FreePool (FfsBuffer);\r
+ DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderRelocateImage failure! \n"));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Invalidate instruction cache and pass control to the image. This will perform\r
+ // the initialization of the module and publish the supporting protocols.\r
+ //\r
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePool (FfsBuffer);\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+EFI_STATUS\r
+QncS3InitPcieRootPortDownstream (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN VOID *Context\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Perform Init Root Port Downstream devices on S3 resume\r
+\r
+ Arguments:\r
+ Parameter Parameters passed in from DXE\r
+\r
+ Returns:\r
+ EFI_STATUS\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() Begin\n"));\r
+\r
+ //\r
+ // Initialize the device behind the root port.\r
+ //\r
+ Status = PciExpressInit ();\r
+\r
+ //\r
+ // Not checking the error status here - downstream device not present does not\r
+ // mean an error of this root port. Our return status of EFI_SUCCESS means this\r
+ // port is enabled and outer function depends on this return status to do\r
+ // subsequent initializations.\r
+ //\r
+\r
+ if (Status != EFI_SUCCESS){\r
+ DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() failed\n"));\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() End\n"));\r
+ return Status;\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+QncS3BootEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // These 2 boxes will be restored by RestoreAllLockBoxInPlace in S3Resume automatically\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize));\r
+ SaveLockBox(&gQncS3CodeInLockBoxGuid, mQncS3ImageAddress, mQncS3ImageSize);\r
+ Status = SetLockBoxAttributes (&gQncS3CodeInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Context = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE));\r
+ SaveLockBox(&gQncS3ContextInLockBoxGuid, (VOID *)mS3Parameter, EFI_PAGE_SIZE);\r
+ Status = SetLockBoxAttributes (&gQncS3ContextInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
+ ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
--- /dev/null
+/** @file\r
+Header file for QNC S3 Support driver\r
+\r
+This file includes package header files, library classes and protocol, PPI & GUID definitions.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef _QNC_S3_SUPPORT_H_\r
+#define _QNC_S3_SUPPORT_H_\r
+\r
+//\r
+// External include files do NOT need to be explicitly specified in real EDKII\r
+// environment\r
+//\r
+//\r
+// Driver Consumed Protocol Prototypes\r
+//\r
+#include <Protocol/FirmwareVolume2.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DxeServicesLib.h>\r
+#include <Library/S3BootScriptLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/LockBoxLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+//\r
+// Driver Produced Protocol Prototypes\r
+//\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/QncS3Support.h>\r
+\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/IntelQNCLib.h>\r
+//\r
+// Define the header of the context region.\r
+//\r
+typedef struct {\r
+ UINT32 MaxContexts;\r
+ UINT32 StorePosition;\r
+ EFI_DISPATCH_CONTEXT_UNION Contexts[1];\r
+} QNC_S3_PARAMETER_HEADER;\r
+//\r
+// Function prototypes\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+QncS3SetDispatchItem (\r
+ IN EFI_QNC_S3_SUPPORT_PROTOCOL *This,\r
+ IN EFI_QNC_S3_DISPATCH_ITEM *DispatchItem,\r
+ OUT VOID **S3DispatchEntryPoint,\r
+ OUT VOID **Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set an item to be dispatched at S3 resume time. At the same time, the entry point\r
+ of the QNC S3 support image is returned to be used in subsequent boot script save\r
+ call\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the protocol instance.\r
+ DispatchItem - The item to be dispatched.\r
+ S3DispatchEntryPoint - The entry point of the QNC S3 support image.\r
+\r
+Returns:\r
+\r
+ EFI_STATUS - Successfully completed.\r
+ EFI_OUT_OF_RESOURCES - Out of resources.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+LoadQncS3Image (\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Load the QNC S3 Image into Efi Reserved Memory below 4G.\r
+\r
+Arguments:\r
+\r
+ ImageEntryPoint the ImageEntryPoint after success loading\r
+\r
+Returns:\r
+\r
+ EFI_STATUS\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+QncS3InitPcieRootPortDownstream (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN VOID *Context\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+QncS3BootEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Component description file for Qnc Initialization driver\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = QncS3Support\r
+ FILE_GUID = C7EA9787-CA0A-43b4-B1E5-25EF87391F8D\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = QncS3SupportEntryPoint\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+ QncS3Support.h\r
+ QncS3Support.c\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ IoLib\r
+ DebugLib\r
+ DxeServicesLib\r
+ BaseMemoryLib\r
+ UefiDriverEntryPoint\r
+ PeCoffLib\r
+ LockBoxLib\r
+ S3BootScriptLib\r
+ UefiBootServicesTableLib\r
+ UefiRuntimeServicesTableLib\r
+ CacheMaintenanceLib\r
+ IntelQNCLib\r
+\r
+[Protocols]\r
+ gEfiQncS3SupportProtocolGuid ## PRODUCES\r
+ gEfiLoadPeImageProtocolGuid ## CONSUMES\r
+ gEfiFirmwareVolume2ProtocolGuid ## CONSUMES\r
+\r
+[Guids]\r
+ gQncS3CodeInLockBoxGuid\r
+ gQncS3ContextInLockBoxGuid\r
+ gEfiEndOfDxeEventGroupGuid\r
+\r
+[Pcd]\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxSize\r
+\r
+[Depex]\r
+ gEfiFirmwareVolume2ProtocolGuid AND\r
+ gEfiVariableArchProtocolGuid AND\r
+ gEfiVariableWriteArchProtocolGuid\r
--- /dev/null
+## @file\r
+# Component description file for SmmAccess module\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SmmAccess\r
+ FILE_GUID = 274F0C8F-9E57-41d8-9966-29CCD48D31C2\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = SmmAccessDriverEntryPoint\r
+\r
+[Sources]\r
+ SmmAccessDriver.h\r
+ SmmAccessDriver.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ HobLib\r
+ DebugLib\r
+ UefiLib\r
+ BaseLib\r
+ BaseMemoryLib\r
+ S3BootScriptLib\r
+ UefiDriverEntryPoint\r
+ UefiBootServicesTableLib\r
+ PcdLib\r
+ SmmLib\r
+\r
+[Protocols]\r
+ gEfiPciRootBridgeIoProtocolGuid\r
+ gEfiSmmAccess2ProtocolGuid\r
+\r
+[Guids]\r
+ gEfiSmmPeiSmramMemoryReserveGuid\r
+\r
+[Depex]\r
+ gEfiPciRootBridgeIoProtocolGuid\r
--- /dev/null
+/** @file\r
+This is the driver that publishes the SMM Access Protocol\r
+instance for the Tylersburg chipset.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SmmAccessDriver.h"\r
+\r
+\r
+\r
+SMM_ACCESS_PRIVATE_DATA mSmmAccess;\r
+\r
+VOID\r
+SmmAccessOnBoot (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+);\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAccessDriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Installs an SMM Access Protocol.\r
+\r
+Arguments:\r
+\r
+ ImageHandle - Handle for the image of this driver.\r
+ SystemTable - Pointer to the EFI System Table.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Protocol successfully started and installed.\r
+ EFI_UNSUPPORTED - Protocol can't be started.\r
+ EFI_NOT_FOUND - Protocol not found.\r
+--*/\r
+{\r
+\r
+ EFI_STATUS Status;\r
+ EFI_EVENT BootEvent;\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+ UINTN Index;\r
+ EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+\r
+\r
+ //\r
+ // Initialize private data\r
+ //\r
+ ZeroMem (&mSmmAccess, sizeof (mSmmAccess));\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiPciRootBridgeIoProtocolGuid,\r
+ NULL,\r
+ (VOID **) &PciRootBridgeIo\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Build SMM related information\r
+ //\r
+ mSmmAccess.Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE;\r
+ mSmmAccess.Handle = NULL;\r
+ mSmmAccess.PciRootBridgeIo = PciRootBridgeIo;\r
+\r
+ //\r
+ // Get Hob list\r
+ //\r
+ GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);\r
+ DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);\r
+ ASSERT (DescriptorBlock);\r
+\r
+\r
+ //\r
+ // Get CPU Max bus number\r
+ //\r
+ mSmmAccess.MaxBusNumber = PCI_BUS_NUMBER_QNC;\r
+ for (Index = 0; Index < MAX_CPU_SOCKET; Index++) {\r
+ mSmmAccess.SocketPopulated[Index] = TRUE;\r
+ }\r
+\r
+ //\r
+ // Use the hob to publish SMRAM capabilities\r
+ //\r
+ ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES);\r
+ for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {\r
+ mSmmAccess.SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart;\r
+ mSmmAccess.SmramDesc[Index].CpuStart = DescriptorBlock->Descriptor[Index].CpuStart;\r
+ mSmmAccess.SmramDesc[Index].PhysicalSize = DescriptorBlock->Descriptor[Index].PhysicalSize;\r
+ mSmmAccess.SmramDesc[Index].RegionState = DescriptorBlock->Descriptor[Index].RegionState;\r
+ DEBUG ((EFI_D_INFO, "SM RAM index[%d] startaddr:%08X Size :%08X\n", Index, mSmmAccess.SmramDesc[Index].CpuStart,\r
+ mSmmAccess.SmramDesc[Index].PhysicalSize));\r
+ }\r
+\r
+ mSmmAccess.NumberRegions = Index;\r
+ mSmmAccess.SmmAccess.Open = Open;\r
+ mSmmAccess.SmmAccess.Close = Close;\r
+ mSmmAccess.SmmAccess.Lock = Lock;\r
+ mSmmAccess.SmmAccess.GetCapabilities = GetCapabilities;\r
+ mSmmAccess.SmmAccess.LockState = FALSE;\r
+ mSmmAccess.SmmAccess.OpenState = FALSE;\r
+ mSmmAccess.SMMRegionState = EFI_SMRAM_CLOSED;\r
+\r
+ //\r
+ // Install our protocol interfaces on the device's handle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mSmmAccess.Handle,\r
+ &gEfiSmmAccess2ProtocolGuid,\r
+ &mSmmAccess.SmmAccess,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DEBUG ((EFI_D_INFO, "SMM Base: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalStart)));\r
+ DEBUG ((EFI_D_INFO, "SMM Size: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize)));\r
+\r
+ mSmmAccess.TsegSize = (UINT8)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize);\r
+ //\r
+ // T Seg setting done in QPI RC\r
+ //\r
+\r
+ //\r
+ // Prior ReadyToBoot, lock CSEG\r
+ //\r
+ Status = EfiCreateEventReadyToBootEx(\r
+ TPL_NOTIFY,\r
+ SmmAccessOnBoot,\r
+ NULL,\r
+ &BootEvent );\r
+ ASSERT (!EFI_ERROR (Status));\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Open (\r
+ IN EFI_SMM_ACCESS2_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine accepts a request to "open" a region of SMRAM. The\r
+ region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.\r
+ The use of "open" means that the memory is visible from all boot-service\r
+ and SMM agents.\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Open.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully opened.\r
+ EFI_DEVICE_ERROR - The region could not be opened because locked by\r
+ chipset.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+{\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {\r
+ DEBUG ((EFI_D_ERROR, "Cannot open a locked SMRAM region\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Open TSEG\r
+ //\r
+ if (!QNCOpenSmramRegion ()) {\r
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ mSmmAccess.SMMRegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED);\r
+ SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~(EFI_SMRAM_CLOSED | EFI_ALLOCATED)));\r
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_OPEN;\r
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_OPEN);\r
+ SmmAccess->SmmAccess.OpenState = TRUE;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Close (\r
+ IN EFI_SMM_ACCESS2_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine accepts a request to "close" a region of SMRAM. This is valid for\r
+ compatible SMRAM region.\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Close.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully closed.\r
+ EFI_DEVICE_ERROR - The region could not be closed because locked by\r
+ chipset.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+{\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+ BOOLEAN OpenState;\r
+ UINTN Index;\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {\r
+ //\r
+ // Cannot close a "locked" region\r
+ //\r
+ DEBUG ((EFI_D_WARN, "Cannot close the locked SMRAM Region\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (mSmmAccess.SMMRegionState & EFI_SMRAM_CLOSED) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Close TSEG\r
+ //\r
+ if (!QNCCloseSmramRegion ()) {\r
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ mSmmAccess.SMMRegionState &= ~EFI_SMRAM_OPEN;\r
+ SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~EFI_SMRAM_OPEN));\r
+ mSmmAccess.SMMRegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED);\r
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_CLOSED | EFI_ALLOCATED);\r
+\r
+ //\r
+ // Find out if any regions are still open\r
+ //\r
+ OpenState = FALSE;\r
+ for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {\r
+ if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) {\r
+ OpenState = TRUE;\r
+ }\r
+ }\r
+\r
+ SmmAccess->SmmAccess.OpenState = OpenState;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Lock (\r
+ IN EFI_SMM_ACCESS2_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine accepts a request to "lock" SMRAM. The\r
+ region could be legacy AB or TSEG near top of physical memory.\r
+ The use of "lock" means that the memory can no longer be opened\r
+ to BS state..\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Lock.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully locked.\r
+ EFI_DEVICE_ERROR - The region could not be locked because at least\r
+ one range is still open.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+{\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (SmmAccess->SmmAccess.OpenState) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;\r
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_LOCKED);\r
+ SmmAccess->SmmAccess.LockState = TRUE;\r
+\r
+ //\r
+ // Lock TSEG\r
+ //\r
+ QNCLockSmramRegion ();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+GetCapabilities (\r
+ IN CONST EFI_SMM_ACCESS2_PROTOCOL *This,\r
+ IN OUT UINTN *SmramMapSize,\r
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine services a user request to discover the SMRAM\r
+ capabilities of this platform. This will report the possible\r
+ ranges that are possible for SMRAM access, based upon the\r
+ memory controller capabilities.\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the SMRAM Access Interface.\r
+ SmramMapSize - Pointer to the variable containing size of the\r
+ buffer to contain the description information.\r
+ SmramMap - Buffer containing the data describing the Smram\r
+ region descriptors.\r
+Returns:\r
+\r
+ EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer.\r
+ EFI_SUCCESS - The user provided a sufficiently-sized buffer.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+ UINTN BufferSize;\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+ BufferSize = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR);\r
+\r
+ if (*SmramMapSize < BufferSize) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+ CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize);\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ *SmramMapSize = BufferSize;\r
+\r
+ return Status;\r
+}\r
+\r
+VOID\r
+SmmAccessOnBoot (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+)\r
+{\r
+\r
+}\r
+VOID\r
+SyncRegionState2SmramDesc(\r
+ IN BOOLEAN OrAnd,\r
+ IN UINT64 Value\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {\r
+ if (OrAnd) {\r
+ mSmmAccess.SmramDesc[Index].RegionState |= Value;\r
+ } else {\r
+ mSmmAccess.SmramDesc[Index].RegionState &= Value;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+Header file for SMM Access Driver.\r
+\r
+This file includes package header files, library classes and protocol, PPI & GUID definitions.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef _SMM_ACCESS_DRIVER_H\r
+#define _SMM_ACCESS_DRIVER_H\r
+\r
+#include <PiDxe.h>\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include <Library/HobLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+//\r
+// Driver Consumed Protocol Prototypes\r
+//\r
+#include <Protocol/PciRootBridgeIo.h>\r
+\r
+//\r
+// Driver Consumed GUID Prototypes\r
+//\r
+#include <Guid/SmramMemoryReserve.h>\r
+\r
+//\r
+// Driver produced protocol\r
+//\r
+#include <Protocol/SmmAccess2.h>\r
+\r
+#include <Library/QNCSmmLib.h>\r
+#include <QNCAccess.h>\r
+\r
+#define MAX_CPU_SOCKET 1\r
+#define MAX_SMRAM_RANGES 4\r
+\r
+//\r
+// Private data structure\r
+//\r
+#define SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', 's', 'm', 'a')\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EFI_HANDLE Handle;\r
+ EFI_SMM_ACCESS2_PROTOCOL SmmAccess;\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+ UINTN NumberRegions;\r
+ EFI_SMRAM_DESCRIPTOR SmramDesc[MAX_SMRAM_RANGES];\r
+ UINT8 TsegSize;\r
+ UINT8 MaxBusNumber;\r
+ UINT8 SocketPopulated[MAX_CPU_SOCKET];\r
+ UINT64 SMMRegionState;\r
+ UINT8 ActualNLIioBusNumber;\r
+} SMM_ACCESS_PRIVATE_DATA;\r
+\r
+\r
+#define SMM_ACCESS_PRIVATE_DATA_FROM_THIS(a) \\r
+ CR ( \\r
+ a, \\r
+ SMM_ACCESS_PRIVATE_DATA, \\r
+ SmmAccess, \\r
+ SMM_ACCESS_PRIVATE_DATA_SIGNATURE \\r
+ )\r
+\r
+\r
+//\r
+// Prototypes\r
+// Driver model protocol interface\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAccessDriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This is the standard EFI driver point that detects\r
+ whether there is an proper chipset in the system\r
+ and if so, installs an SMM Access Protocol.\r
+\r
+Arguments:\r
+\r
+ ImageHandle - Handle for the image of this driver.\r
+ SystemTable - Pointer to the EFI System Table.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Protocol successfully started and installed.\r
+ EFI_UNSUPPORTED - Protocol can't be started.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Open (\r
+ IN EFI_SMM_ACCESS2_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine accepts a request to "open" a region of SMRAM. The\r
+ region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.\r
+ The use of "open" means that the memory is visible from all boot-service\r
+ and SMM agents.\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Open.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully opened.\r
+ EFI_DEVICE_ERROR - The region could not be opened because locked by\r
+ chipset.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Close (\r
+ IN EFI_SMM_ACCESS2_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine accepts a request to "close" a region of SMRAM. This is valid for\r
+ compatible SMRAM region.\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Close.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully closed.\r
+ EFI_DEVICE_ERROR - The region could not be closed because locked by\r
+ chipset.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Lock (\r
+ IN EFI_SMM_ACCESS2_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine accepts a request to "lock" SMRAM. The\r
+ region could be legacy AB or TSEG near top of physical memory.\r
+ The use of "lock" means that the memory can no longer be opened\r
+ to BS state..\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Lock.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully locked.\r
+ EFI_DEVICE_ERROR - The region could not be locked because at least\r
+ one range is still open.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+GetCapabilities (\r
+ IN CONST EFI_SMM_ACCESS2_PROTOCOL *This,\r
+ IN OUT UINTN *SmramMapSize,\r
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine services a user request to discover the SMRAM\r
+ capabilities of this platform. This will report the possible\r
+ ranges that are possible for SMRAM access, based upon the\r
+ memory controller capabilities.\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the SMRAM Access Interface.\r
+ SmramMapSize - Pointer to the variable containing size of the\r
+ buffer to contain the description information.\r
+ SmramMap - Buffer containing the data describing the Smram\r
+ region descriptors.\r
+\r
+Returns:\r
+\r
+ EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer.\r
+ EFI_SUCCESS - The user provided a sufficiently-sized buffer.\r
+\r
+--*/\r
+;\r
+VOID\r
+SyncRegionState2SmramDesc(\r
+ IN BOOLEAN OrAnd,\r
+ IN UINT64 Value\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This module produces the SMM COntrol2 Protocol for QNC\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Protocol/SmmControl2.h>\r
+#include <IndustryStandard/Pci.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PciLib.h>\r
+#include <IntelQNCDxe.h>\r
+#include <Library/QNCAccessLib.h>\r
+#include <Uefi/UefiBaseType.h>\r
+\r
+#define EFI_INTERNAL_POINTER 0x00000004\r
+\r
+extern EFI_GUID gEfiEventVirtualAddressChangeGuid;\r
+\r
+/**\r
+ Generates an SMI using the parameters passed in.\r
+\r
+ @param This A pointer to an instance of\r
+ EFI_SMM_CONTROL2_PROTOCOL\r
+ @param ArgumentBuffer The argument buffer\r
+ @param ArgumentBufferSize The size of the argument buffer\r
+ @param Periodic TRUE to indicate a periodical SMI\r
+ @param ActivationInterval Interval of the periodical SMI\r
+\r
+ @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1\r
+ @return Return value from SmmTrigger().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Activate (\r
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,\r
+ IN OUT UINT8 *CommandPort OPTIONAL,\r
+ IN OUT UINT8 *DataPort OPTIONAL,\r
+ IN BOOLEAN Periodic OPTIONAL,\r
+ IN EFI_SMM_PERIOD ActivationInterval OPTIONAL\r
+ );\r
+\r
+/**\r
+ Clears an SMI.\r
+\r
+ @param This Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL\r
+ @param Periodic TRUE to indicate a periodical SMI\r
+\r
+ @return Return value from SmmClear()\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Deactivate (\r
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,\r
+ IN BOOLEAN Periodic OPTIONAL\r
+ );\r
+\r
+///\r
+/// Handle for the SMM Control2 Protocol\r
+///\r
+EFI_HANDLE mSmmControl2Handle = NULL;\r
+\r
+///\r
+/// SMM COntrol2 Protocol instance\r
+///\r
+EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {\r
+ Activate,\r
+ Deactivate,\r
+ 0\r
+};\r
+\r
+VOID\r
+EFIAPI\r
+SmmControlVirtualddressChangeEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Fixup internal data pointers so that the services can be called in virtual mode.\r
+\r
+Arguments:\r
+\r
+ Event The event registered.\r
+ Context Event context.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Trigger));\r
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Clear));\r
+}\r
+\r
+/**\r
+ Clear SMI related chipset status and re-enable SMI by setting the EOS bit.\r
+\r
+ @retval EFI_SUCCESS The requested operation has been carried out successfully\r
+ @retval EFI_DEVICE_ERROR The EOS bit could not be set.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmClear (\r
+ VOID\r
+ )\r
+{\r
+ UINT16 PM1BLK_Base;\r
+ UINT16 GPE0BLK_Base;\r
+\r
+ //\r
+ // Get PM1BLK_Base & GPE0BLK_Base\r
+ //\r
+ PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);\r
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);\r
+\r
+ //\r
+ // Clear the Power Button Override Status Bit, it gates EOS from being set.\r
+ // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.\r
+ //\r
+\r
+ //\r
+ // Clear the APM SMI Status Bit\r
+ //\r
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);\r
+\r
+ //\r
+ // Set the EOS Bit\r
+ //\r
+ IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Generates an SMI using the parameters passed in.\r
+\r
+ @param This A pointer to an instance of\r
+ EFI_SMM_CONTROL_PROTOCOL\r
+ @param ArgumentBuffer The argument buffer\r
+ @param ArgumentBufferSize The size of the argument buffer\r
+ @param Periodic TRUE to indicate a periodical SMI\r
+ @param ActivationInterval Interval of the periodical SMI\r
+\r
+ @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1\r
+ @retval EFI_SUCCESS SMI generated\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Activate (\r
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,\r
+ IN OUT UINT8 *CommandPort OPTIONAL,\r
+ IN OUT UINT8 *DataPort OPTIONAL,\r
+ IN BOOLEAN Periodic OPTIONAL,\r
+ IN EFI_SMM_PERIOD ActivationInterval OPTIONAL\r
+ )\r
+{\r
+ UINT16 GPE0BLK_Base;\r
+ UINT32 NewValue;\r
+\r
+ //\r
+ // Get GPE0BLK_Base\r
+ //\r
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);\r
+\r
+ if (Periodic) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Clear any pending the APM SMI\r
+ //\r
+ if (EFI_ERROR (SmmClear())) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Enable the APMC SMI\r
+ //\r
+ IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);\r
+\r
+ //\r
+ // Enable SMI globally\r
+ //\r
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
+ NewValue |= SMI_EN;\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);\r
+\r
+\r
+ //\r
+ // Set APMC_STS\r
+ //\r
+ if (DataPort == NULL) {\r
+ IoWrite8 (PcdGet16 (PcdSmmDataPort), 0xFF);\r
+ } else {\r
+ IoWrite8 (PcdGet16 (PcdSmmDataPort), *DataPort);\r
+ }\r
+\r
+ //\r
+ // Generate the APMC SMI\r
+ //\r
+ if (CommandPort == NULL) {\r
+ IoWrite8 (PcdGet16 (PcdSmmActivationPort), 0xFF);\r
+ } else {\r
+ IoWrite8 (PcdGet16 (PcdSmmActivationPort), *CommandPort);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Clears an SMI.\r
+\r
+ @param This Pointer to an instance of EFI_SMM_CONTROL_PROTOCOL\r
+ @param Periodic TRUE to indicate a periodical SMI\r
+\r
+ @return Return value from SmmClear()\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Deactivate (\r
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,\r
+ IN BOOLEAN Periodic\r
+ )\r
+{\r
+ if (Periodic) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return SmmClear();\r
+}\r
+\r
+/**\r
+ This is the constructor for the SMM Control protocol.\r
+\r
+ This function installs EFI_SMM_CONTROL2_PROTOCOL.\r
+\r
+ @param ImageHandle Handle for the image of this driver\r
+ @param SystemTable Pointer to the EFI System Table\r
+\r
+ @retval EFI_UNSUPPORTED There's no Intel ICH on this platform\r
+ @return The status returned from InstallProtocolInterface().\r
+\r
+--*/\r
+EFI_STATUS\r
+SmmControl2Init (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Event;\r
+ UINT16 PM1BLK_Base;\r
+ UINT16 GPE0BLK_Base;\r
+ BOOLEAN SciEn;\r
+ UINT32 NewValue;\r
+\r
+ //\r
+ // Get PM1BLK_Base & GPE0BLK_Base\r
+ //\r
+ PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);\r
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);\r
+\r
+ //\r
+ // Install our protocol interfaces on the device's handle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mSmmControl2Handle,\r
+ &gEfiSmmControl2ProtocolGuid, &mSmmControl2,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Determine whether an ACPI OS is present (via the SCI_EN bit)\r
+ //\r
+ SciEn = (BOOLEAN)((IoRead16 (PM1BLK_Base + R_QNC_PM1BLK_PM1C) & B_QNC_PM1BLK_PM1C_SCIEN) != 0);\r
+ if (!SciEn) {\r
+ //\r
+ // Clear any SMIs that double as SCIs (when SCI_EN==0)\r
+ //\r
+ IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1S), B_QNC_PM1BLK_PM1S_ALL);\r
+ IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1E), 0x00000000);\r
+ IoWrite32 ((PM1BLK_Base + R_QNC_PM1BLK_PM1C), 0x00000000);\r
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0S), B_QNC_GPE0BLK_GPE0S_ALL);\r
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0E), 0x00000000);\r
+ }\r
+\r
+ //\r
+ // Clear and disable all SMIs that are unaffected by SCI_EN\r
+ // Set EOS\r
+ //\r
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), 0x00000000);\r
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), (B_QNC_GPE0BLK_SMIS_EOS + B_QNC_GPE0BLK_SMIS_ALL));\r
+\r
+ //\r
+ // Enable SMI globally\r
+ //\r
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
+ NewValue |= SMI_EN;\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);\r
+\r
+ //\r
+ // Make sure to write this register last -- EOS re-enables SMIs for the QNC\r
+ //\r
+ IoAndThenOr32 (\r
+ GPE0BLK_Base + R_QNC_GPE0BLK_SMIE,\r
+ (UINT32)(~B_QNC_GPE0BLK_SMIE_ALL),\r
+ B_QNC_GPE0BLK_SMIE_APM\r
+ );\r
+\r
+ //\r
+ // Make sure EOS bit cleared\r
+ //\r
+ DEBUG_CODE_BEGIN ();\r
+ if (IoRead32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS) & B_QNC_GPE0BLK_SMIS_EOS) {\r
+ DEBUG ((\r
+ EFI_D_ERROR,\r
+ "******************************************************************************\n"\r
+ "BIG ERROR: SmmControl constructor couldn't properly initialize the ACPI table.\n"\r
+ " SmmControl->Clear will probably hang. \n"\r
+ " NOTE: SCI_EN = %d \n"\r
+ "******************************************************************************\n",\r
+ SciEn\r
+ ));\r
+\r
+ //\r
+ // If we want the system to stop, then keep the ASSERT(FALSE).\r
+ // Otherwise, comment it out.\r
+ //\r
+ ASSERT (FALSE);\r
+ }\r
+ DEBUG_CODE_END ();\r
+\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ SmmControlVirtualddressChangeEvent,\r
+ NULL,\r
+ &gEfiEventVirtualAddressChangeGuid,\r
+ &Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+## @file\r
+# QNC SmmControl driver to install EFI_SMM_CONTROL_PROTOCOL.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SmmControlDxe\r
+ FILE_GUID = A03A9429-C570-4ef9-9E00-C7A673976E5F\r
+ MODULE_TYPE = DXE_RUNTIME_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = SmmControl2Init\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+ SmmControlDriver.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ UefiDriverEntryPoint\r
+ DebugLib\r
+ UefiBootServicesTableLib\r
+ UefiRuntimeServicesTableLib\r
+ PcdLib\r
+ IoLib\r
+ PciLib\r
+ QNCAccessLib\r
+\r
+[Protocols]\r
+ gEfiSmmControl2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+\r
+[Pcd]\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress\r
+\r
+[Guids]\r
+ gEfiEventVirtualAddressChangeGuid\r
+\r
+[Depex]\r
+ TRUE\r
--- /dev/null
+/** @file\r
+Common header file shared by all source files.\r
+\r
+This file includes package header files, library classes and protocol, PPI & GUID definitions.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef __COMMON_HEADER_H_\r
+#define __COMMON_HEADER_H_\r
+\r
+\r
+\r
+#include <PiSmm.h>\r
+#include <IntelQNCDxe.h>\r
+\r
+#include <Protocol/SmmUsbDispatch2.h>\r
+#include <Protocol/SmmPeriodicTimerDispatch2.h>\r
+#include <Protocol/SmmIchnDispatch2.h>\r
+#include <Protocol/SmmPowerButtonDispatch2.h>\r
+#include <Protocol/SmmGpiDispatch2.h>\r
+#include <Protocol/SmmSxDispatch2.h>\r
+#include <Protocol/SmmSwDispatch2.h>\r
+#include <Protocol/SmmIoTrapDispatch2.h>\r
+#include <Protocol/SmmCpu.h>\r
+\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/SmmServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/S3IoLib.h>\r
+#include <Library/QNCAccessLib.h>\r
+\r
+#include <Uefi/UefiBaseType.h>\r
+#endif\r
--- /dev/null
+/** @file\r
+File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmmHelpers.h"\r
+\r
+CONST QNC_SMM_SOURCE_DESC GPI_SOURCE_DESC = {\r
+ QNC_SMM_NO_FLAGS,\r
+ {\r
+ {\r
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_GPIO\r
+ },\r
+ NULL_BIT_DESC_INITIALIZER\r
+ },\r
+ {\r
+ {\r
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_GPIO\r
+ }\r
+ }\r
+};\r
+\r
--- /dev/null
+/** @file\r
+\r
+This driver is responsible for the registration of child drivers\r
+and the abstraction of the QNC SMI sources.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmmHelpers.h"\r
+\r
+//\r
+// Help handle porting bit shifts to IA-64.\r
+//\r
+#define BIT_ZERO 0x00000001\r
+\r
+\r
+VOID\r
+QNCSmmPublishDispatchProtocols(\r
+ VOID\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Install protocol interfaces.\r
+ //\r
+ for (Index = 0; Index < NUM_PROTOCOLS; Index++) {\r
+ Status = gSmst->SmmInstallProtocolInterface (\r
+ &mPrivateData.InstallMultProtHandle,\r
+ mPrivateData.Protocols[Index].Guid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &mPrivateData.Protocols[Index].Protocols.Generic\r
+ );\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+}\r
+}\r
+\r
+EFI_STATUS\r
+QNCSmmInitHardware(\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize bits that aren't necessarily related to an SMI source.\r
+\r
+Dependencies:\r
+\r
+ gSmst - SMM System Table; contains an entry for SMM CPU IO\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS. Asserts, otherwise.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Clear all SMIs\r
+ //\r
+ QNCSmmClearSmi();\r
+\r
+ Status = QNCSmmEnableGlobalSmiBit ();\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Be *really* sure to clear all SMIs\r
+ //\r
+ QNCSmmClearSmi ();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+QNCSmmEnableGlobalSmiBit (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Enables the QNC to generate SMIs. Note that no SMIs will be generated\r
+ if no SMI sources are enabled. Conversely, no enabled SMI source will\r
+ generate SMIs if SMIs are not globally enabled. This is the main\r
+ switchbox for SMI generation.\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS.\r
+ Asserts, otherwise.\r
+\r
+--*/\r
+{\r
+ UINT32 NewValue;\r
+\r
+ //\r
+ // Enable SMI globally\r
+ //\r
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
+ NewValue |= SMI_EN;\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+QNCSmmClearSmi(\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Clears the SMI after all SMI source have been processed.\r
+ Note that this function will not work correctly (as it is\r
+ written) unless all SMI sources have been processed.\r
+ A revision of this function could manually clear all SMI\r
+ status bits to guarantee success.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS.\r
+ Asserts, otherwise.\r
+\r
+--*/\r
+{\r
+ BOOLEAN EosSet;\r
+ BOOLEAN SciEn;\r
+\r
+ UINT32 Pm1Cnt = 0;\r
+ UINT16 Pm1Sts = 0;\r
+ UINT32 Gpe0Sts = 0;\r
+ UINT32 SmiSts = 0;\r
+\r
+ //\r
+ // Determine whether an ACPI OS is present (via the SCI_EN bit)\r
+ //\r
+ Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);\r
+ SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);\r
+\r
+ if (SciEn == FALSE) {\r
+\r
+ //\r
+ // Clear any SMIs that double as SCIs (when SCI_EN==0)\r
+ //\r
+ 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);\r
+\r
+ Gpe0Sts = B_QNC_GPE0BLK_GPE0S_ALL;\r
+\r
+ IoOr16((PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S), Pm1Sts);\r
+ IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S), Gpe0Sts);\r
+ }\r
+\r
+ //\r
+ // Clear all SMIs that are unaffected by SCI_EN\r
+ //\r
+ SmiSts = IoRead32((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);\r
+ SmiSts |= B_QNC_GPE0BLK_SMIS_ALL;\r
+ IoWrite32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), SmiSts);\r
+\r
+ //\r
+ // Try to clear the EOS bit. ASSERT on an error\r
+ //\r
+ EosSet = QNCSmmSetAndCheckEos();\r
+ ASSERT (EosSet);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+QNCSmmSetAndCheckEos(\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Reset the QNC to generate subsequent SMIs\r
+ //\r
+ IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);\r
+ return TRUE;\r
+}\r
+\r
+BOOLEAN\r
+QNCSmmGetSciEn(\r
+ )\r
+{\r
+ BOOLEAN SciEn;\r
+ UINT32 Pm1Cnt;\r
+\r
+ //\r
+ // Determine whether an ACPI OS is present (via the SCI_EN bit)\r
+ //\r
+ Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);\r
+\r
+ SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);\r
+\r
+ return SciEn;\r
+}\r
+\r
+//\r
+// These may or may not need to change w/ the QNC version; they're highly IA-32 dependent, though.\r
+//\r
+\r
+BOOLEAN\r
+ReadBitDesc (\r
+ CONST QNC_SMM_BIT_DESC *BitDesc\r
+ )\r
+{\r
+ UINT64 Register;\r
+ UINT32 PciBus;\r
+ UINT32 PciDev;\r
+ UINT32 PciFun;\r
+ UINT32 PciReg;\r
+ BOOLEAN BitWasOne;\r
+\r
+ ASSERT (BitDesc != NULL );\r
+ ASSERT (!IS_BIT_DESC_NULL( *BitDesc ) );\r
+\r
+ Register = 0;\r
+ BitWasOne = FALSE;\r
+\r
+ switch (BitDesc->Reg.Type) {\r
+\r
+ case ACPI_ADDR_TYPE:\r
+ //\r
+ // Double check that we correctly read in the acpi base address\r
+ //\r
+ ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1) );\r
+\r
+ switch (BitDesc->SizeInBytes) {\r
+\r
+ case 0:\r
+ //\r
+ // Chances are that this field didn't get initialized.\r
+ // Check your assignments to bit descriptions.\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+\r
+ case 1:\r
+ Register = (UINT64) IoRead8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);\r
+ break;\r
+\r
+ case 2:\r
+ Register = (UINT64) IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);\r
+ break;\r
+\r
+ case 4:\r
+ Register = (UINT64) IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Unsupported or invalid register size\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+ };\r
+\r
+ if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {\r
+ BitWasOne = TRUE;\r
+ } else {\r
+ BitWasOne = FALSE;\r
+ }\r
+ break;\r
+\r
+ case GPE_ADDR_TYPE:\r
+ //\r
+ // Double check that we correctly read in the gpe base address\r
+ //\r
+ ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1) );\r
+\r
+ switch (BitDesc->SizeInBytes) {\r
+\r
+ case 0:\r
+ //\r
+ // Chances are that this field didn't get initialized.\r
+ // Check your assignments to bit descriptions.\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+\r
+ case 1:\r
+ Register = (UINT64) IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);\r
+ break;\r
+\r
+ case 2:\r
+ Register = (UINT64) IoRead16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);\r
+ break;\r
+\r
+ case 4:\r
+ Register = (UINT64) IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Unsupported or invalid register size\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+ };\r
+\r
+ if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {\r
+ BitWasOne = TRUE;\r
+ } else {\r
+ BitWasOne = FALSE;\r
+ }\r
+ break;\r
+\r
+ case MEMORY_MAPPED_IO_ADDRESS_TYPE:\r
+ //\r
+ // Read the register, and it with the bit to read\r
+ //\r
+\r
+ //\r
+ // This code does not support reads greater then 64 bits\r
+ //\r
+ ASSERT (BitDesc->SizeInBytes <= 8);\r
+ CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);\r
+ Register &= LShiftU64 (BIT0, BitDesc->Bit);\r
+ if (Register) {\r
+ BitWasOne = TRUE;\r
+ } else {\r
+ BitWasOne = FALSE;\r
+ }\r
+ break;\r
+\r
+ case PCI_ADDR_TYPE:\r
+ PciBus = BitDesc->Reg.Data.pci.Fields.Bus;\r
+ PciDev = BitDesc->Reg.Data.pci.Fields.Dev;\r
+ PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;\r
+ PciReg = BitDesc->Reg.Data.pci.Fields.Reg;\r
+ switch (BitDesc->SizeInBytes) {\r
+\r
+ case 0:\r
+ //\r
+ // Chances are that this field didn't get initialized.\r
+ // Check your assignments to bit descriptions.\r
+ ASSERT (FALSE );\r
+ break;\r
+\r
+ case 1:\r
+ Register = (UINT64) PciRead8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));\r
+ break;\r
+\r
+ case 2:\r
+ Register = (UINT64) PciRead16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));\r
+ break;\r
+\r
+ case 4:\r
+ Register = (UINT64) PciRead32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Unsupported or invalid register size\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+ };\r
+\r
+ if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {\r
+ BitWasOne = TRUE;\r
+ } else {\r
+ BitWasOne = FALSE;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // This address type is not yet implemented\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+ };\r
+\r
+ return BitWasOne;\r
+}\r
+\r
+VOID\r
+WriteBitDesc (\r
+ CONST QNC_SMM_BIT_DESC *BitDesc,\r
+ CONST BOOLEAN ValueToWrite\r
+ )\r
+{\r
+ UINT64 Register;\r
+ UINT64 AndVal;\r
+ UINT64 OrVal;\r
+ UINT32 PciBus;\r
+ UINT32 PciDev;\r
+ UINT32 PciFun;\r
+ UINT32 PciReg;\r
+\r
+ ASSERT (BitDesc != NULL);\r
+ ASSERT (!IS_BIT_DESC_NULL(*BitDesc));\r
+\r
+ AndVal = ~(BIT_ZERO << (BitDesc->Bit));\r
+ OrVal = ((UINT32)ValueToWrite) << (BitDesc->Bit);\r
+\r
+ switch (BitDesc->Reg.Type) {\r
+\r
+ case ACPI_ADDR_TYPE:\r
+ //\r
+ // Double check that we correctly read in the acpi base address\r
+ //\r
+ ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1));\r
+\r
+ switch (BitDesc->SizeInBytes) {\r
+\r
+ case 0:\r
+ //\r
+ // Chances are that this field didn't get initialized.\r
+ // Check your assignments to bit descriptions.\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+\r
+ case 1:\r
+ IoAndThenOr8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT8)AndVal, (UINT8)OrVal);\r
+ break;\r
+\r
+ case 2:\r
+ IoAndThenOr16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT16)AndVal, (UINT16)OrVal);\r
+ break;\r
+\r
+ case 4:\r
+ IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT32)AndVal, (UINT32)OrVal);\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Unsupported or invalid register size\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+ };\r
+ break;\r
+\r
+ case GPE_ADDR_TYPE:\r
+ //\r
+ // Double check that we correctly read in the gpe base address\r
+ //\r
+ ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1));\r
+\r
+ switch (BitDesc->SizeInBytes) {\r
+\r
+ case 0:\r
+ //\r
+ // Chances are that this field didn't get initialized.\r
+ // Check your assignments to bit descriptions.\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+\r
+ case 1:\r
+ IoAndThenOr8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT8)AndVal, (UINT8)OrVal);\r
+ break;\r
+\r
+ case 2:\r
+ IoAndThenOr16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT16)AndVal, (UINT16)OrVal);\r
+ break;\r
+\r
+ case 4:\r
+ IoAndThenOr32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT32)AndVal, (UINT32)OrVal);\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Unsupported or invalid register size\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+ };\r
+ break;\r
+\r
+ case MEMORY_MAPPED_IO_ADDRESS_TYPE:\r
+ //\r
+ // Read the register, or it with the bit to set, then write it back.\r
+ //\r
+\r
+ //\r
+ // This code does not support writes greater then 64 bits\r
+ //\r
+ ASSERT (BitDesc->SizeInBytes <= 8);\r
+ CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);\r
+ Register &= AndVal;\r
+ Register |= OrVal;\r
+ CopyMem (BitDesc->Reg.Data.Mmio, &Register, BitDesc->SizeInBytes);\r
+ break;\r
+\r
+ case PCI_ADDR_TYPE:\r
+ PciBus = BitDesc->Reg.Data.pci.Fields.Bus;\r
+ PciDev = BitDesc->Reg.Data.pci.Fields.Dev;\r
+ PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;\r
+ PciReg = BitDesc->Reg.Data.pci.Fields.Reg;\r
+ switch (BitDesc->SizeInBytes) {\r
+\r
+ case 0:\r
+ //\r
+ // Chances are that this field didn't get initialized -- check your assignments\r
+ // to bit descriptions.\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+\r
+ case 1:\r
+ PciAndThenOr8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT8) AndVal, (UINT8) OrVal);\r
+ break;\r
+\r
+ case 2:\r
+ PciAndThenOr16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT16) AndVal, (UINT16) OrVal);\r
+ break;\r
+\r
+ case 4:\r
+ PciAndThenOr32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT32) AndVal, (UINT32) OrVal);\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Unsupported or invalid register size\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+ };\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // This address type is not yet implemented\r
+ //\r
+ ASSERT (FALSE );\r
+ break;\r
+ };\r
+}\r
--- /dev/null
+/** @file\r
+File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmmHelpers.h"\r
+\r
+typedef enum {\r
+ PERIODIC_TIMER = 0,\r
+ NUM_TIMERS\r
+} SUPPORTED_TIMER;\r
+\r
+typedef struct _TIMER_INTERVAL\r
+{\r
+ UINT64 Interval;\r
+ UINT8 AssociatedTimer;\r
+} TIMER_INTERVAL;\r
+\r
+//\r
+// Time constants, in 100 nano-second units\r
+//\r
+#define TIME_64s 640000000 /* 64 s */\r
+#define TIME_32s 320000000 /* 32 s */\r
+#define TIME_16s 160000000 /* 16 s */\r
+#define TIME_8s 80000000 /* 8 s */\r
+#define TIME_64ms 640000 /* 64 ms */\r
+#define TIME_32ms 320000 /* 32 ms */\r
+#define TIME_16ms 160000 /* 16 ms */\r
+#define TIME_1_5ms 15000 /* 1.5 ms */\r
+\r
+// PMCW (GPE+28h) [2:0] Periodic SMI Rate selection\r
+// 000 1.5ms\r
+// 001 16ms\r
+// 010 32ms\r
+// 011 64ms\r
+// 100 8s\r
+// 101 16s\r
+// 110 32s\r
+// 111 64s\r
+\r
+typedef enum {\r
+ INDEX_TIME_1_5ms = 0,\r
+ INDEX_TIME_16ms,\r
+ INDEX_TIME_32ms,\r
+ INDEX_TIME_64ms,\r
+ INDEX_TIME_8s,\r
+ INDEX_TIME_16s,\r
+ INDEX_TIME_32s,\r
+ INDEX_TIME_64s,\r
+ INDEX_TIME_MAX\r
+} TIMER_INTERVAL_INDEX;\r
+\r
+TIMER_INTERVAL mSmmPeriodicTimerIntervals[INDEX_TIME_MAX] = {\r
+ {TIME_1_5ms, PERIODIC_TIMER},\r
+ {TIME_16ms, PERIODIC_TIMER},\r
+ {TIME_32ms, PERIODIC_TIMER},\r
+ {TIME_64ms, PERIODIC_TIMER},\r
+ { TIME_8s, PERIODIC_TIMER },\r
+ {TIME_16s, PERIODIC_TIMER},\r
+ {TIME_32s, PERIODIC_TIMER},\r
+ {TIME_64s, PERIODIC_TIMER}\r
+};\r
+\r
+typedef struct _TIMER_INFO {\r
+ UINTN NumChildren; // number of children using this timer\r
+ UINT64 MinReqInterval; // minimum interval required by children\r
+ UINTN CurrentSetting; // interval this timer is set at right now (index into interval table)\r
+} TIMER_INFO;\r
+\r
+TIMER_INFO mTimers[NUM_TIMERS];\r
+\r
+QNC_SMM_SOURCE_DESC mTIMER_SOURCE_DESCS[NUM_TIMERS] = {\r
+ {\r
+ QNC_SMM_NO_FLAGS,\r
+ {\r
+ {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SWT},\r
+ NULL_BIT_DESC_INITIALIZER\r
+ },\r
+ {\r
+ {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SWT}\r
+ }\r
+ }\r
+};\r
+\r
+VOID\r
+QNCSmmPeriodicTimerProgramTimers(\r
+ VOID\r
+ );\r
+\r
+\r
+TIMER_INTERVAL *\r
+ContextToTimerInterval (\r
+ IN QNC_SMM_CONTEXT *RegisterContext\r
+ )\r
+{\r
+ UINTN loopvar;\r
+\r
+ //\r
+ // Determine which timer this child is using\r
+ //\r
+ for (loopvar = 0; loopvar < INDEX_TIME_MAX; loopvar++) {\r
+ if (((RegisterContext->PeriodicTimer.SmiTickInterval == 0) && (RegisterContext->PeriodicTimer.Period >= mSmmPeriodicTimerIntervals[loopvar].Interval)) ||\r
+ (RegisterContext->PeriodicTimer.SmiTickInterval == mSmmPeriodicTimerIntervals[loopvar].Interval)\r
+ ) {\r
+ return &mSmmPeriodicTimerIntervals[loopvar];\r
+ }\r
+ }\r
+\r
+ //\r
+ // If this assertion fires, then either:\r
+ // (1) the context contains an invalid interval\r
+ // (2) the timer interval table is corrupt\r
+ //\r
+ // ASSERT (FALSE);\r
+\r
+ return NULL;\r
+}\r
+\r
+EFI_STATUS\r
+MapPeriodicTimerToSrcDesc (\r
+ IN QNC_SMM_CONTEXT *RegisterContext,\r
+ OUT QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+{\r
+ TIMER_INTERVAL *TimerInterval;\r
+\r
+ //\r
+ // Figure out which timer the child is requesting and\r
+ // send back the source description\r
+ //\r
+ TimerInterval = ContextToTimerInterval (RegisterContext);\r
+ if (TimerInterval == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ CopyMem (SrcDesc, &mTIMER_SOURCE_DESCS[TimerInterval->AssociatedTimer], sizeof (QNC_SMM_SOURCE_DESC));;\r
+\r
+ //\r
+ // Program the value of the interval into hardware\r
+ //\r
+ QNCSmmPeriodicTimerProgramTimers ();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+PeriodicTimerGetContext (\r
+ IN DATABASE_RECORD *Record,\r
+ OUT QNC_SMM_CONTEXT *HwContext\r
+ )\r
+{\r
+ TIMER_INTERVAL *TimerInterval;\r
+\r
+ ASSERT (Record->ProtocolType == PeriodicTimerType);\r
+\r
+ TimerInterval = ContextToTimerInterval (&Record->ChildContext);\r
+\r
+ if (TimerInterval != NULL) {\r
+ //\r
+ // Ignore the hardware context. It's not required for this protocol.\r
+ // Instead, just increment the child's context.\r
+ // Update the elapsed time w/ the data from our tables\r
+ //\r
+ Record->CommBuffer.PeriodicTimer.ElapsedTime += TimerInterval->Interval;\r
+ *HwContext = Record->ChildContext;\r
+ }\r
+}\r
+\r
+BOOLEAN\r
+PeriodicTimerCmpContext (\r
+ IN QNC_SMM_CONTEXT *HwContext,\r
+ IN QNC_SMM_CONTEXT *ChildContext\r
+ )\r
+{\r
+ DATABASE_RECORD *Record;\r
+\r
+ Record = DATABASE_RECORD_FROM_CONTEXT (ChildContext);\r
+\r
+ if (Record->CommBuffer.PeriodicTimer.ElapsedTime >= ChildContext->PeriodicTimer.Period) {\r
+ //\r
+ // This child should be dispatched\r
+ // The timer will be restarted on the "ClearSource" call.\r
+ //\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+VOID\r
+PeriodicTimerGetBuffer (\r
+ IN DATABASE_RECORD * Record\r
+ )\r
+{\r
+ //\r
+ // CommBuffer has been updated by PeriodicTimerGetContext, so return directly\r
+ //\r
+ return;\r
+}\r
+\r
+VOID\r
+QNCSmmPeriodicTimerProgramTimers (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 GpePmcwValue;\r
+ SUPPORTED_TIMER Timer;\r
+ DATABASE_RECORD *RecordInDb;\r
+ LIST_ENTRY *LinkInDb;\r
+ TIMER_INTERVAL *TimerInterval;\r
+\r
+ //\r
+ // Find the minimum required interval for each timer\r
+ //\r
+ for (Timer = (SUPPORTED_TIMER)0; Timer < NUM_TIMERS; Timer++) {\r
+ mTimers[Timer].MinReqInterval = ~(UINT64)0x0;\r
+ mTimers[Timer].NumChildren = 0;\r
+ }\r
+ LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
+ while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
+ RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
+ if (RecordInDb->ProtocolType == PeriodicTimerType) {\r
+ //\r
+ // This child is registerd with the PeriodicTimer protocol\r
+ //\r
+ TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext);\r
+\r
+ if(TimerInterval != NULL) {\r
+ Timer = (SUPPORTED_TIMER)((TIMER_INTERVAL *) (TimerInterval))->AssociatedTimer;\r
+\r
+ ASSERT (Timer >= 0 && Timer < NUM_TIMERS);\r
+\r
+ if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) {\r
+ mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval;\r
+ }\r
+ mTimers[Timer].NumChildren++;\r
+ }\r
+ }\r
+ LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
+ }\r
+\r
+ //\r
+ // Program the hardware\r
+ //\r
+ GpePmcwValue = 0;\r
+ if (mTimers[PERIODIC_TIMER].NumChildren > 0) {\r
+ switch (mTimers[PERIODIC_TIMER].MinReqInterval) {\r
+\r
+ case TIME_64s:\r
+ GpePmcwValue = INDEX_TIME_64s;\r
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s;\r
+ break;\r
+\r
+ case TIME_32s:\r
+ GpePmcwValue = INDEX_TIME_32s;\r
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s;\r
+ break;\r
+\r
+ case TIME_16s:\r
+ GpePmcwValue = INDEX_TIME_16s;\r
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s;\r
+ break;\r
+\r
+ case TIME_8s:\r
+ GpePmcwValue = INDEX_TIME_8s;\r
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s;\r
+ break;\r
+\r
+ case TIME_64ms:\r
+ GpePmcwValue = INDEX_TIME_64ms;\r
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64ms;\r
+ break;\r
+\r
+ case TIME_32ms:\r
+ GpePmcwValue = INDEX_TIME_32ms;\r
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32ms;\r
+ break;\r
+\r
+ case TIME_16ms:\r
+ GpePmcwValue = INDEX_TIME_16ms;\r
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16ms;\r
+ break;\r
+\r
+ case TIME_1_5ms:\r
+ GpePmcwValue = INDEX_TIME_1_5ms;\r
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_1_5ms;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ };\r
+\r
+ GpePmcwValue |= B_QNC_GPE0BLK_PMCW_PSE;\r
+\r
+ IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMCW), GpePmcwValue);\r
+\r
+ //\r
+ // Restart the timer here, just need to clear the SMI\r
+ //\r
+ QNCSmmClearSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);\r
+ } else {\r
+ QNCSmmDisableSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);\r
+ }\r
+}\r
+\r
+EFI_STATUS\r
+QNCSmmPeriodicTimerDispatchGetNextShorterInterval (\r
+ IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,\r
+ IN OUT UINT64 **SmiTickInterval\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This services returns the next SMI tick period that is supported by the chipset.\r
+ The order returned is from longest to shortest interval period.\r
+\r
+Arguments:\r
+\r
+ This - Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance.\r
+ SmiTickInterval - Pointer to pointer of the next shorter SMI interval period that is supported by the child.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The service returned successfully.\r
+ EFI_INVALID_PARAMETER - The parameter SmiTickInterval is invalid.\r
+\r
+--*/\r
+{\r
+ TIMER_INTERVAL *IntervalPointer;\r
+\r
+ ASSERT (SmiTickInterval != NULL);\r
+\r
+ IntervalPointer = (TIMER_INTERVAL*)*SmiTickInterval;\r
+\r
+ if (IntervalPointer == NULL) {\r
+ //\r
+ // The first time child requesting an interval\r
+ //\r
+ IntervalPointer = &mSmmPeriodicTimerIntervals[0];\r
+ } else if (IntervalPointer == &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1]) {\r
+ //\r
+ // At end of the list\r
+ //\r
+ IntervalPointer = NULL;\r
+ } else {\r
+ if ((IntervalPointer >= &mSmmPeriodicTimerIntervals[0]) &&\r
+ (IntervalPointer < &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1])) {\r
+ //\r
+ // Get the next interval in the list\r
+ //\r
+ IntervalPointer++;\r
+ } else {\r
+ //\r
+ // Input is out of range\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ if (IntervalPointer != NULL) {\r
+ *SmiTickInterval = &IntervalPointer->Interval;\r
+ } else {\r
+ *SmiTickInterval = NULL;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+QNCSmmPeriodicTimerClearSource (\r
+ IN QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function is responsible for calculating and enabling any timers that are required\r
+ to dispatch messages to children. The SrcDesc argument isn't acutally used.\r
+\r
+Arguments:\r
+\r
+ SrcDesc - Pointer to the QNC_SMM_SOURCE_DESC instance.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ DATABASE_RECORD *RecordInDb;\r
+ LIST_ENTRY *LinkInDb;\r
+\r
+ QNCSmmPeriodicTimerProgramTimers ();\r
+\r
+ //\r
+ // Reset Elapsed time\r
+ //\r
+ LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
+ while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
+ RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
+ if (RecordInDb->ProtocolType == PeriodicTimerType) {\r
+ //\r
+ // This child is registerd with the PeriodicTimer protocol and Callback\r
+ // has been invoked, so reset the ElapsedTime to 0\r
+ //\r
+ if (RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime >= RecordInDb->ChildContext.PeriodicTimer.Period) {\r
+ RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime = 0;\r
+ }\r
+ }\r
+ LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
+ }\r
+}\r
+\r
--- /dev/null
+/** @file\r
+File to contain all the hardware specific stuff for the Smm QNCn dispatch protocol.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmmHelpers.h"\r
+\r
+QNC_SMM_SOURCE_DESC QNCN_SOURCE_DESCS[NUM_ICHN_TYPES] = {\r
+\r
+ // QNCnMch (0)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnPme (1)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnRtcAlarm (2)\r
+ {\r
+ QNC_SMM_NO_FLAGS,\r
+ {\r
+ {{ACPI_ADDR_TYPE, {R_QNC_PM1BLK_PM1E}}, S_QNC_PM1BLK_PM1E, N_QNC_PM1BLK_PM1E_RTC},\r
+ NULL_BIT_DESC_INITIALIZER\r
+ },\r
+ {\r
+ {{ACPI_ADDR_TYPE, {R_QNC_PM1BLK_PM1S}}, S_QNC_PM1BLK_PM1S, N_QNC_PM1BLK_PM1S_RTC}\r
+ }\r
+ },\r
+\r
+ // QNCnRingIndicate (3)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnAc97Wake (4)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnSerialIrq (5)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnY2KRollover (6)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnTcoTimeout (7)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnOsTco (8)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnNmi (9)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnIntruderDetect (10)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnBiosWp (11)\r
+ {\r
+ QNC_SMM_CLEAR_WITH_ZERO,\r
+ {\r
+ {\r
+ {\r
+ PCI_ADDR_TYPE,\r
+ {\r
+ (\r
+ (PCI_BUS_NUMBER_QNC << 24) |\r
+ (PCI_DEVICE_NUMBER_QNC_LPC << 16) |\r
+ (PCI_FUNCTION_NUMBER_QNC_LPC << 8) |\r
+ R_QNC_LPC_BIOS_CNTL\r
+ )\r
+ }\r
+ },\r
+ S_QNC_LPC_BIOS_CNTL,\r
+ N_QNC_LPC_BIOS_CNTL_BLE\r
+ },\r
+ NULL_BIT_DESC_INITIALIZER\r
+ },\r
+ {\r
+ {\r
+ {\r
+ PCI_ADDR_TYPE,\r
+ {\r
+ (\r
+ (PCI_BUS_NUMBER_QNC << 24) |\r
+ (PCI_DEVICE_NUMBER_QNC_LPC << 16) |\r
+ (PCI_FUNCTION_NUMBER_QNC_LPC << 8) |\r
+ R_QNC_LPC_BIOS_CNTL\r
+ )\r
+ }\r
+ },\r
+ S_QNC_LPC_BIOS_CNTL,\r
+ N_QNC_LPC_BIOS_CNTL_BIOSWE\r
+ }\r
+ }\r
+ },\r
+\r
+ // QNCnMcSmi (12)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnPmeB0 (13)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnThrmSts (14)\r
+ {\r
+ QNC_SMM_SCI_EN_DEPENDENT,\r
+ {\r
+ {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_GPE0E}}, S_QNC_GPE0BLK_GPE0E, N_QNC_GPE0BLK_GPE0E_THRM},\r
+ NULL_BIT_DESC_INITIALIZER\r
+ },\r
+ {\r
+ {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_GPE0S}}, S_QNC_GPE0BLK_GPE0S, N_QNC_GPE0BLK_GPE0S_THRM}\r
+ }\r
+ },\r
+\r
+ // QNCnSmBus (15)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnIntelUsb2 (16)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnMonSmi7 (17)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnMonSmi6 (18)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnMonSmi5 (19)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnMonSmi4 (20)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap13 (21)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap12 (22)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap11 (23)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap10 (24)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap9 (25)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap8 (26)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap7 (27)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap6 (28)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap5 (29)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap3 (30)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap2 (31)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap1 (32)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnDevTrap0 (33)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnIoTrap3 (34)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnIoTrap2 (35)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnIoTrap1 (36)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnIoTrap0 (37)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnPciExpress (38)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnMonitor (39)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnSpi (40)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnQRT (41)\r
+ NULL_SOURCE_DESC_INITIALIZER,\r
+\r
+ // QNCnGpioUnlock (42)\r
+ NULL_SOURCE_DESC_INITIALIZER\r
+};\r
+\r
+VOID\r
+QNCSmmQNCnClearSource(\r
+ QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+{\r
+ QNCSmmClearSource (SrcDesc);\r
+}\r
--- /dev/null
+/** @file\r
+File to contain all the hardware specific stuff for the Smm Sw dispatch protocol.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmmHelpers.h"\r
+\r
+EFI_SMM_CPU_PROTOCOL *mSmmCpu = NULL;\r
+\r
+CONST QNC_SMM_SOURCE_DESC SW_SOURCE_DESC = {\r
+ QNC_SMM_NO_FLAGS,\r
+ {\r
+ {\r
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_APM\r
+ },\r
+ NULL_BIT_DESC_INITIALIZER\r
+ },\r
+ {\r
+ {\r
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_APM\r
+ }\r
+ }\r
+};\r
+\r
+VOID\r
+SwGetContext(\r
+ IN DATABASE_RECORD *Record,\r
+ OUT QNC_SMM_CONTEXT *Context\r
+ )\r
+{\r
+ Context->Sw.SwSmiInputValue = IoRead8 (R_APM_CNT);\r
+}\r
+\r
+BOOLEAN\r
+SwCmpContext (\r
+ IN QNC_SMM_CONTEXT *Context1,\r
+ IN QNC_SMM_CONTEXT *Context2\r
+ )\r
+{\r
+ return (BOOLEAN)( Context1->Sw.SwSmiInputValue == Context2->Sw.SwSmiInputValue );\r
+}\r
+\r
+VOID\r
+SwGetBuffer (\r
+ IN DATABASE_RECORD * Record\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINTN CpuIndex;\r
+ EFI_SMM_SAVE_STATE_IO_INFO IoState;\r
+\r
+ //\r
+ // Locate SMM CPU protocol to retrieve the CPU save state\r
+ //\r
+ if (mSmmCpu == NULL) {\r
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ //\r
+ // Find the CPU which generated the software SMI\r
+ //\r
+ CpuIndex = 0;\r
+ for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {\r
+ Status = mSmmCpu->ReadSaveState (\r
+ mSmmCpu,\r
+ sizeof (EFI_SMM_SAVE_STATE_IO_INFO),\r
+ EFI_SMM_SAVE_STATE_REGISTER_IO,\r
+ Index,\r
+ &IoState\r
+ );\r
+ if (!EFI_ERROR (Status) && (IoState.IoPort == R_APM_CNT)) {\r
+ CpuIndex = Index;\r
+ break;\r
+ }\r
+ }\r
+\r
+ Record->CommBuffer.Sw.SwSmiCpuIndex = CpuIndex;\r
+}\r
--- /dev/null
+/** @file\r
+File to contain all the hardware specific stuff for the Smm Sx dispatch protocol.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmmHelpers.h"\r
+\r
+CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC = {\r
+ QNC_SMM_NO_FLAGS,\r
+ {\r
+ {\r
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SLP\r
+ },\r
+ NULL_BIT_DESC_INITIALIZER\r
+ },\r
+ {\r
+ {\r
+ {GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SLP\r
+ }\r
+ }\r
+};\r
+\r
+VOID\r
+SxGetContext(\r
+ IN DATABASE_RECORD *Record,\r
+ OUT QNC_SMM_CONTEXT *Context\r
+ )\r
+{\r
+ UINT32 Pm1Cnt;\r
+\r
+ Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);\r
+\r
+ //\r
+ // By design, the context phase will always be ENTRY\r
+ //\r
+ Context->Sx.Phase = SxEntry;\r
+\r
+ //\r
+ // Map the PM1_CNT register's SLP_TYP bits to the context type\r
+ //\r
+ switch (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) {\r
+\r
+ case V_S0:\r
+ Context->Sx.Type = SxS0;\r
+ break;\r
+\r
+ case V_S3:\r
+ Context->Sx.Type = SxS3;\r
+ break;\r
+\r
+ case V_S4:\r
+ Context->Sx.Type = SxS4;\r
+ break;\r
+\r
+ case V_S5:\r
+ Context->Sx.Type = SxS5;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ break;\r
+ };\r
+}\r
+\r
+BOOLEAN\r
+SxCmpContext (\r
+ IN QNC_SMM_CONTEXT *Context1,\r
+ IN QNC_SMM_CONTEXT *Context2\r
+ )\r
+{\r
+ return (BOOLEAN)(Context1->Sx.Type == Context2->Sx.Type);\r
+}\r
+\r
+VOID\r
+QNCSmmSxGoToSleep(\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ When we get an SMI that indicates that we are transitioning to a sleep state,\r
+ we need to actually transition to that state. We do this by disabling the\r
+ "SMI on sleep enable" feature, which generates an SMI when the operating system\r
+ tries to put the system to sleep, and then physically putting the system to sleep.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ UINT32 Pm1Cnt;\r
+\r
+ //\r
+ // Flush cache into memory before we go to sleep. It is necessary for S3 sleep\r
+ // because we may update memory in SMM Sx sleep handlers -- the updates are in cache now\r
+ //\r
+ AsmWbinvd();\r
+\r
+ //\r
+ // Disable SMIs\r
+ //\r
+ QNCSmmClearSource (&SX_SOURCE_DESC );\r
+ QNCSmmDisableSource (&SX_SOURCE_DESC);\r
+\r
+ //\r
+ // Clear Sleep Type Enable\r
+ //\r
+ IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIE, (UINT16)(~B_QNC_GPE0BLK_SMIE_SLP));\r
+\r
+ // clear sleep SMI status\r
+ IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, (UINT16)(S_QNC_GPE0BLK_SMIS));\r
+\r
+ //\r
+ // Now that SMIs are disabled, write to the SLP_EN bit again to trigger the sleep\r
+ //\r
+ Pm1Cnt = IoOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, B_QNC_PM1BLK_PM1C_SLPEN);\r
+\r
+ //\r
+ // The system just went to sleep. If the sleep state was S1, then code execution will resume\r
+ // here when the system wakes up.\r
+ //\r
+ Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);\r
+ if ((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == 0) {\r
+ //\r
+ // An ACPI OS isn't present, clear the sleep information\r
+ //\r
+ Pm1Cnt &= ~B_QNC_PM1BLK_PM1C_SLPTP;\r
+ Pm1Cnt |= V_S0;\r
+\r
+ IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Pm1Cnt);\r
+ }\r
+\r
+ QNCSmmClearSource (&SX_SOURCE_DESC);\r
+ QNCSmmEnableSource (&SX_SOURCE_DESC);\r
+}\r
--- /dev/null
+/** @file\r
+Prototypes and defines for the QNC SMM Dispatcher.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef QNC_SMM_H\r
+#define QNC_SMM_H\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmmRegisters.h"\r
+\r
+extern EFI_HANDLE mQNCSmmDispatcherImageHandle;\r
+\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// SUPPORTED PROTOCOLS\r
+//\r
+\r
+//\r
+// Define an enumeration for all the supported protocols\r
+//\r
+typedef enum {\r
+ // UsbType, DELETE:on QuarkNcSocId, there is no usb smi supported\r
+ SxType,\r
+ SwType,\r
+ GpiType,\r
+ QNCnType,\r
+ PowerButtonType,\r
+ PeriodicTimerType,\r
+ NUM_PROTOCOLS\r
+} QNC_SMM_PROTOCOL_TYPE;\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// SPECIFYING A REGISTER\r
+// We want a general way of referring to addresses. For this case, we'll only\r
+// need addresses in the ACPI table (and the TCO entries within the ACPI table).\r
+// However, it's interesting to consider what it would take to support other types\r
+// of addresses. To address Will's concern, I think it prudent to accommodate it\r
+// early on in the design.\r
+//\r
+// Addresses we need to consider:\r
+//\r
+// Type: Required:\r
+// I/O Yes\r
+// ACPI (special case of I/O) Only if we want to\r
+// TCO (special case of ACPI) Only if we want to\r
+// Memory (or Memory Mapped I/O) Only if we want to\r
+// PCI Yes, for BiosWp\r
+//\r
+typedef enum {\r
+ //\r
+ // IO_ADDR_TYPE, // unimplemented\r
+ //\r
+ ACPI_ADDR_TYPE,\r
+ GPE_ADDR_TYPE,\r
+ //\r
+ // MEMORY_ADDR_TYPE, // unimplemented\r
+ //\r
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,\r
+ PCI_ADDR_TYPE,\r
+ NUM_ADDR_TYPES, // count of items in this enum\r
+ QNC_SMM_ADDR_TYPE_NULL = -1 // sentinel to indicate NULL or to signal end of arrays\r
+} ADDR_TYPE;\r
+\r
+//\r
+// Assumption: 32-bits -- enum's evaluate to integer\r
+// Assumption: This code will only run on IA-32. Justification: IA-64 doesn't have SMIs.\r
+// We don't have to worry about 64-bit addresses.\r
+// Typedef the size of addresses in case the numbers I'm using are wrong or in case\r
+// this changes. This is a good idea because PCI_ADDR will change, for example, when\r
+// we add support for PciExpress.\r
+//\r
+typedef UINT16 IO_ADDR;\r
+typedef IO_ADDR ACPI_ADDR; // can omit\r
+typedef IO_ADDR GPE_ADDR; // can omit\r
+typedef IO_ADDR TCO_ADDR; // can omit\r
+typedef VOID *MEM_ADDR;\r
+typedef MEM_ADDR MEMORY_MAPPED_IO_ADDRESS;\r
+typedef union {\r
+ UINT32 Raw;\r
+ struct {\r
+ UINT8 Reg;\r
+ UINT8 Fnc;\r
+ UINT8 Dev;\r
+ UINT8 Bus;\r
+ } Fields;\r
+} PCI_ADDR;\r
+\r
+typedef struct {\r
+ ADDR_TYPE Type;\r
+ union {\r
+ //\r
+ // used to initialize during declaration/definition\r
+ //\r
+ UINTN raw;\r
+\r
+ //\r
+ // used to access useful data\r
+ //\r
+ IO_ADDR io;\r
+ ACPI_ADDR acpi;\r
+ GPE_ADDR gpe;\r
+ TCO_ADDR tco;\r
+ MEM_ADDR mem;\r
+ MEMORY_MAPPED_IO_ADDRESS Mmio;\r
+ PCI_ADDR pci;\r
+\r
+ } Data;\r
+\r
+} QNC_SMM_ADDRESS;\r
+//\r
+// Assumption: total size is 64 bits (32 for type and 32 for data) or 8 bytes\r
+//\r
+#define EFI_PCI_ADDRESS_PORT 0xcf8\r
+#define EFI_PCI_DATA_PORT 0xcfc\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// SPECIFYING BITS WITHIN A REGISTER\r
+// Here's a struct that helps us specify a source or enable bit.\r
+//\r
+typedef struct {\r
+ QNC_SMM_ADDRESS Reg;\r
+ UINT8 SizeInBytes; // of the register\r
+ UINT8 Bit;\r
+} QNC_SMM_BIT_DESC;\r
+\r
+//\r
+// Sometimes, we'll have bit descriptions that are unused. It'd be great to have a\r
+// way to easily identify them:\r
+//\r
+#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type == QNC_SMM_ADDR_TYPE_NULL) // "returns" true when BitDesc is NULL\r
+#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = QNC_SMM_ADDR_TYPE_NULL) // will "return" an integer w/ value of 0\r
+#define NULL_BIT_DESC_INITIALIZER \\r
+ { \\r
+ { \\r
+ QNC_SMM_ADDR_TYPE_NULL, \\r
+ { \\r
+ 0 \\r
+ } \\r
+ }, \\r
+ 0, 0 \\r
+ }\r
+//\r
+// I'd like a type to specify the callback's Sts & En bits because they'll\r
+// be commonly used together:\r
+//\r
+#define NUM_EN_BITS 2\r
+#define NUM_STS_BITS 1\r
+\r
+//\r
+// Flags\r
+//\r
+typedef UINT8 QNC_SMM_SOURCE_FLAGS;\r
+\r
+//\r
+// Flags required today\r
+//\r
+#define QNC_SMM_NO_FLAGS 0\r
+#define QNC_SMM_SCI_EN_DEPENDENT (BIT0)\r
+#define QNC_SMM_CLEAR_WITH_ZERO (BIT6)\r
+\r
+//\r
+// Flags that might be required tomorrow\r
+// #define QNC_SMM_CLEAR_WITH_ONE 2 // may need to support bits that clear by writing 0\r
+// #define QNC_SMM_MULTIBIT_FIELD 3 // may need to support status/enable fields 2 bits wide\r
+//\r
+typedef struct {\r
+ QNC_SMM_SOURCE_FLAGS Flags;\r
+ QNC_SMM_BIT_DESC En[NUM_EN_BITS];\r
+ QNC_SMM_BIT_DESC Sts[NUM_STS_BITS];\r
+} QNC_SMM_SOURCE_DESC;\r
+//\r
+// 31 bytes, I think\r
+//\r
+#define NULL_SOURCE_DESC_INITIALIZER \\r
+ { \\r
+ QNC_SMM_NO_FLAGS, \\r
+ { \\r
+ NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \\r
+ }, \\r
+ { \\r
+ NULL_BIT_DESC_INITIALIZER \\r
+ } \\r
+ }\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// CHILD CONTEXTS\r
+// To keep consistent w/ the architecture, we'll need to provide the context\r
+// to the child when we call its callback function. After talking with Will,\r
+// we agreed that we'll need functions to "dig" the context out of the hardware\r
+// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those\r
+// contexts to prevent unnecessary dispatches. I'd like a general type for these\r
+// "GetContext" functions, so I'll need a union of all the protocol contexts for\r
+// our internal use:\r
+//\r
+typedef union {\r
+ //\r
+ // (in no particular order)\r
+ //\r
+ EFI_SMM_ICHN_REGISTER_CONTEXT QNCn;\r
+ EFI_SMM_SX_REGISTER_CONTEXT Sx;\r
+ EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer;\r
+ EFI_SMM_SW_REGISTER_CONTEXT Sw;\r
+ EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton;\r
+ // EFI_SMM_USB_REGISTER_CONTEXT Usb; DELETE:on QuarkNcSocId, there is no usb smi supported\r
+ EFI_SMM_GPI_REGISTER_CONTEXT Gpi;\r
+} QNC_SMM_CONTEXT;\r
+\r
+typedef union {\r
+ //\r
+ // (in no particular order)\r
+ //\r
+ EFI_SMM_SW_CONTEXT Sw;\r
+ EFI_SMM_PERIODIC_TIMER_CONTEXT PeriodicTimer;\r
+} QNC_SMM_BUFFER;\r
+\r
+//\r
+// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes\r
+//\r
+typedef struct _DATABASE_RECORD DATABASE_RECORD;\r
+\r
+typedef\r
+VOID\r
+(EFIAPI *GET_CONTEXT) (\r
+ IN DATABASE_RECORD * Record,\r
+ OUT QNC_SMM_CONTEXT * Context\r
+ );\r
+//\r
+// Assumption: the GET_CONTEXT function will be as small and simple as possible.\r
+// Assumption: We don't need to pass in an enumeration for the protocol because each\r
+// GET_CONTEXT function is written for only one protocol.\r
+// We also need a function to compare contexts to see if the child should be dispatched\r
+//\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *CMP_CONTEXT) (\r
+ IN QNC_SMM_CONTEXT * Context1,\r
+ IN QNC_SMM_CONTEXT * Context2\r
+ );\r
+\r
+/*\r
+ Returns: True when contexts are equivalent; False otherwise\r
+*/\r
+\r
+//\r
+// This function is used to get the content of CommBuffer that will be passed\r
+// to Callback function\r
+//\r
+typedef\r
+VOID\r
+(EFIAPI *GET_BUFFER) (\r
+ IN DATABASE_RECORD * Record\r
+ );\r
+\r
+//\r
+// Finally, every protocol will require a "Get Context", "Compare Context"\r
+// and "Get CommBuffer" call, so we may as well wrap that up in a table, too.\r
+//\r
+typedef struct {\r
+ GET_CONTEXT GetContext;\r
+ CMP_CONTEXT CmpContext;\r
+ GET_BUFFER GetBuffer;\r
+} CONTEXT_FUNCTIONS;\r
+\r
+extern CONTEXT_FUNCTIONS ContextFunctions[NUM_PROTOCOLS];\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// MAPPING CONTEXT TO BIT DESCRIPTIONS\r
+// I'd like to have a general approach to mapping contexts to bit descriptions.\r
+// Sometimes, we'll find that we can use table lookups or CONSTant assignments;\r
+// other times, we'll find that we'll need to use a function to perform the mapping.\r
+// If we define a macro to mask that process, we'll never have to change the code.\r
+// I don't know if this is desirable or not -- if it isn't, then we can get rid\r
+// of the macros and just use function calls or variable assignments. Doesn't matter\r
+// to me.\r
+// Mapping complex contexts requires a function\r
+//\r
+// DELETE:on QuarkNcSocId, there is no usb smi supported\r
+//EFI_STATUS\r
+//EFIAPI\r
+//MapUsbToSrcDesc (\r
+// IN QNC_SMM_CONTEXT *RegisterContext,\r
+// OUT QNC_SMM_SOURCE_DESC *SrcDesc\r
+// )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ RegisterContext - GC_TODO: add argument description\r
+ SrcDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+MapPeriodicTimerToSrcDesc (\r
+ IN QNC_SMM_CONTEXT *RegisterContext,\r
+ OUT QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ RegisterContext - GC_TODO: add argument description\r
+ SrcDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+//\r
+// Mapping simple contexts can be done by assignment or lookup table\r
+//\r
+extern CONST QNC_SMM_SOURCE_DESC SW_SOURCE_DESC;\r
+extern CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC;\r
+\r
+//\r
+// With the changes we've made to the protocols, we can now use table\r
+// lookups for the following protocols:\r
+//\r
+extern CONST QNC_SMM_SOURCE_DESC GPI_SOURCE_DESC;\r
+\r
+extern QNC_SMM_SOURCE_DESC QNCN_SOURCE_DESCS[NUM_ICHN_TYPES];\r
+\r
+\r
+//\r
+// For QNCx, APMC is UINT8 port, so the MAX SWI Value is 0xFF.\r
+//\r
+#define MAXIMUM_SWI_VALUE 0xFF\r
+\r
+\r
+//\r
+// Open: Need to make sure this kind of type cast will actually work.\r
+// May need an intermediate form w/ two VOID* arguments. I'll figure\r
+// that out when I start compiling.\r
+\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+typedef\r
+VOID\r
+(EFIAPI *QNC_SMM_CLEAR_SOURCE) (\r
+ QNC_SMM_SOURCE_DESC * SrcDesc\r
+ );\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// "DATABASE" RECORD\r
+// Linked list data structures\r
+//\r
+#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C')\r
+\r
+struct _DATABASE_RECORD {\r
+ UINT32 Signature;\r
+ LIST_ENTRY Link;\r
+\r
+ //\r
+ // Status and Enable bit description\r
+ //\r
+ QNC_SMM_SOURCE_DESC SrcDesc;\r
+\r
+ //\r
+ // Callback function\r
+ //\r
+ EFI_SMM_HANDLER_ENTRY_POINT2 Callback;\r
+ QNC_SMM_CONTEXT ChildContext;\r
+ QNC_SMM_BUFFER CommBuffer;\r
+ UINTN BufferSize;\r
+\r
+ //\r
+ // Special handling hooks -- init them to NULL if unused/unneeded\r
+ //\r
+ QNC_SMM_CLEAR_SOURCE ClearSource; // needed for SWSMI timer\r
+ // Functions required to make callback code general\r
+ //\r
+ CONTEXT_FUNCTIONS ContextFunctions;\r
+\r
+ //\r
+ // The protocol that this record dispatches\r
+ //\r
+ QNC_SMM_PROTOCOL_TYPE ProtocolType;\r
+\r
+};\r
+\r
+#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE)\r
+#define DATABASE_RECORD_FROM_CONTEXT(_record) CR (_record, DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE)\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// HOOKING INTO THE ARCHITECTURE\r
+//\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *QNC_SMM_GENERIC_REGISTER) (\r
+ IN VOID **This,\r
+ IN VOID *DispatchFunction,\r
+ IN VOID *RegisterContext,\r
+ OUT EFI_HANDLE * DispatchHandle\r
+ );\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *QNC_SMM_GENERIC_UNREGISTER) (\r
+ IN VOID **This,\r
+ IN EFI_HANDLE DispatchHandle\r
+ );\r
+\r
+//\r
+// Define a memory "stamp" equivalent in size and function to most of the protocols\r
+//\r
+typedef struct {\r
+ QNC_SMM_GENERIC_REGISTER Register;\r
+ QNC_SMM_GENERIC_UNREGISTER Unregister;\r
+ UINTN Extra1;\r
+ UINTN Extra2; // may not need this one\r
+} QNC_SMM_GENERIC_PROTOCOL;\r
+\r
+EFI_STATUS\r
+QNCSmmCoreRegister (\r
+ IN QNC_SMM_GENERIC_PROTOCOL *This,\r
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,\r
+ IN QNC_SMM_CONTEXT *RegisterContext,\r
+ OUT EFI_HANDLE *DispatchHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ This - GC_TODO: add argument description\r
+ DispatchFunction - GC_TODO: add argument description\r
+ RegisterContext - GC_TODO: add argument description\r
+ DispatchHandle - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+EFI_STATUS\r
+QNCSmmCoreUnRegister (\r
+ IN QNC_SMM_GENERIC_PROTOCOL *This,\r
+ IN EFI_HANDLE DispatchHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ This - GC_TODO: add argument description\r
+ DispatchHandle - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+typedef union {\r
+ QNC_SMM_GENERIC_PROTOCOL Generic;\r
+\r
+ // EFI_SMM_USB_DISPATCH2_PROTOCOL Usb; DELETE:on QuarkNcSocId, there is no usb smi supported\r
+ EFI_SMM_SX_DISPATCH2_PROTOCOL Sx;\r
+ EFI_SMM_SW_DISPATCH2_PROTOCOL Sw;\r
+ EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi;\r
+ EFI_SMM_ICHN_DISPATCH2_PROTOCOL QNCn;\r
+ EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton;\r
+ EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer;\r
+} QNC_SMM_PROTOCOL;\r
+\r
+//\r
+// Define a structure to help us identify the generic protocol\r
+//\r
+#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T')\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+\r
+ QNC_SMM_PROTOCOL_TYPE Type;\r
+ EFI_GUID *Guid;\r
+ QNC_SMM_PROTOCOL Protocols;\r
+} QNC_SMM_QUALIFIED_PROTOCOL;\r
+\r
+#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \\r
+ CR (_generic, \\r
+ QNC_SMM_QUALIFIED_PROTOCOL, \\r
+ Protocols, \\r
+ PROTOCOL_SIGNATURE \\r
+ )\r
+\r
+//\r
+// Create private data for the protocols that we'll publish\r
+//\r
+typedef struct {\r
+ LIST_ENTRY CallbackDataBase;\r
+ EFI_HANDLE SmiHandle;\r
+ EFI_HANDLE InstallMultProtHandle;\r
+ QNC_SMM_QUALIFIED_PROTOCOL Protocols[NUM_PROTOCOLS];\r
+} PRIVATE_DATA;\r
+\r
+extern PRIVATE_DATA mPrivateData;\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+//\r
+VOID\r
+EFIAPI\r
+SwGetContext (\r
+ IN DATABASE_RECORD *Record,\r
+ OUT QNC_SMM_CONTEXT *Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Record - GC_TODO: add argument description\r
+ Context - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+EFIAPI\r
+SwCmpContext (\r
+ IN QNC_SMM_CONTEXT *Context1,\r
+ IN QNC_SMM_CONTEXT *Context2\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Context1 - GC_TODO: add argument description\r
+ Context2 - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+SwGetBuffer (\r
+ IN DATABASE_RECORD * Record\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Record - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+EFIAPI\r
+SxGetContext (\r
+ IN DATABASE_RECORD *Record,\r
+ OUT QNC_SMM_CONTEXT *Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Record - GC_TODO: add argument description\r
+ Context - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+EFIAPI\r
+SxCmpContext (\r
+ IN QNC_SMM_CONTEXT *Context1,\r
+ IN QNC_SMM_CONTEXT *Context2\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Context1 - GC_TODO: add argument description\r
+ Context2 - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+EFIAPI\r
+PeriodicTimerGetContext (\r
+ IN DATABASE_RECORD *Record,\r
+ OUT QNC_SMM_CONTEXT *Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Record - GC_TODO: add argument description\r
+ Context - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+EFIAPI\r
+PeriodicTimerCmpContext (\r
+ IN QNC_SMM_CONTEXT *Context1,\r
+ IN QNC_SMM_CONTEXT *Context2\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Context1 - GC_TODO: add argument description\r
+ Context2 - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+PeriodicTimerGetBuffer (\r
+ IN DATABASE_RECORD * Record\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Record - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+EFIAPI\r
+PowerButtonGetContext (\r
+ IN DATABASE_RECORD *Record,\r
+ OUT QNC_SMM_CONTEXT *Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Record - GC_TODO: add argument description\r
+ Context - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+EFIAPI\r
+PowerButtonCmpContext (\r
+ IN QNC_SMM_CONTEXT *Context1,\r
+ IN QNC_SMM_CONTEXT *Context2\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Context1 - GC_TODO: add argument description\r
+ Context2 - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+//\r
+VOID\r
+EFIAPI\r
+QNCSmmPeriodicTimerClearSource (\r
+ QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SrcDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+QNCSmmPeriodicTimerDispatchGetNextShorterInterval (\r
+ IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,\r
+ IN OUT UINT64 **SmiTickInterval\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ This - GC_TODO: add argument description\r
+ SmiTickInterval - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+QNCSmmSxGoToSleep (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+EFIAPI\r
+QNCSmmQNCnClearSource (\r
+ QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SrcDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This driver is responsible for the registration of child drivers\r
+and the abstraction of the QNC SMI sources.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmm.h"\r
+#include "QNCSmmHelpers.h"\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// MODULE / GLOBAL DATA\r
+//\r
+// Module variables used by the both the main dispatcher and the source dispatchers\r
+// Declared in QNCSmmSources.h\r
+//\r
+UINT32 mPciData;\r
+UINT32 mPciAddress;\r
+\r
+PRIVATE_DATA mPrivateData = { // for the structure\r
+ {\r
+ NULL\r
+ }, // CallbackDataBase linked list head\r
+ NULL, // Handler returned whan calling SmiHandlerRegister\r
+ NULL, // EFI handle returned when calling InstallMultipleProtocolInterfaces\r
+ { // protocol arrays\r
+ // elements within the array\r
+ //\r
+ {\r
+ PROTOCOL_SIGNATURE,\r
+ SxType,\r
+ &gEfiSmmSxDispatch2ProtocolGuid,\r
+ {\r
+ {\r
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
+ }\r
+ }\r
+ },\r
+ {\r
+ PROTOCOL_SIGNATURE,\r
+ SwType,\r
+ &gEfiSmmSwDispatch2ProtocolGuid,\r
+ {\r
+ {\r
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
+ (UINTN) MAXIMUM_SWI_VALUE\r
+ }\r
+ }\r
+ },\r
+ {\r
+ PROTOCOL_SIGNATURE,\r
+ GpiType,\r
+ &gEfiSmmGpiDispatch2ProtocolGuid,\r
+ {\r
+ {\r
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
+ (UINTN) 1\r
+ }\r
+ }\r
+ },\r
+ {\r
+ PROTOCOL_SIGNATURE,\r
+ QNCnType,\r
+ &gEfiSmmIchnDispatch2ProtocolGuid,\r
+ {\r
+ {\r
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
+ }\r
+ }\r
+ },\r
+ {\r
+ PROTOCOL_SIGNATURE,\r
+ PowerButtonType,\r
+ &gEfiSmmPowerButtonDispatch2ProtocolGuid,\r
+ {\r
+ {\r
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister\r
+ }\r
+ }\r
+ },\r
+ {\r
+ PROTOCOL_SIGNATURE,\r
+ PeriodicTimerType,\r
+ &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,\r
+ {\r
+ {\r
+ (QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,\r
+ (QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,\r
+ (UINTN) QNCSmmPeriodicTimerDispatchGetNextShorterInterval\r
+ }\r
+ }\r
+ },\r
+ }\r
+};\r
+\r
+CONTEXT_FUNCTIONS mContextFunctions[NUM_PROTOCOLS] = {\r
+ {\r
+ SxGetContext,\r
+ SxCmpContext,\r
+ NULL\r
+ },\r
+ {\r
+ SwGetContext,\r
+ SwCmpContext,\r
+ SwGetBuffer\r
+ },\r
+ {\r
+ NULL,\r
+ NULL,\r
+ NULL\r
+ },\r
+ {\r
+ NULL,\r
+ NULL,\r
+ NULL\r
+ },\r
+ {\r
+ NULL,\r
+ NULL,\r
+ NULL\r
+ },\r
+ {\r
+ PeriodicTimerGetContext,\r
+ PeriodicTimerCmpContext,\r
+ PeriodicTimerGetBuffer,\r
+ },\r
+};\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// PROTOTYPES\r
+//\r
+// Functions use only in this file\r
+//\r
+EFI_STATUS\r
+QNCSmmCoreDispatcher (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *Context, OPTIONAL\r
+ IN OUT VOID *CommBuffer, OPTIONAL\r
+ IN OUT UINTN *CommBufferSize OPTIONAL\r
+ );\r
+\r
+\r
+UINTN\r
+DevicePathSize (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ );\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// FUNCTIONS\r
+//\r
+// Driver entry point\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeQNCSmmDispatcher (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initializes the QNC SMM Dispatcher\r
+\r
+Arguments:\r
+\r
+ ImageHandle - Pointer to the loaded image protocol for this driver\r
+ SystemTable - Pointer to the EFI System Table\r
+\r
+Returns:\r
+ Status - EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ QNCSmmPublishDispatchProtocols ();\r
+\r
+ //\r
+ // Register a callback function to handle subsequent SMIs. This callback\r
+ // will be called by SmmCoreDispatcher.\r
+ //\r
+ Status = gSmst->SmiHandlerRegister (QNCSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Initialize Callback DataBase\r
+ //\r
+ InitializeListHead (&mPrivateData.CallbackDataBase);\r
+\r
+ //\r
+ // Enable SMIs on the QNC now that we have a callback\r
+ //\r
+ QNCSmmInitHardware ();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+SaveState (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Save Index registers to avoid corrupting the foreground environment\r
+\r
+Arguments:\r
+ None\r
+\r
+Returns:\r
+ Status - EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+ mPciAddress = IoRead32 (EFI_PCI_ADDRESS_PORT);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+RestoreState (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Restore Index registers to avoid corrupting the foreground environment\r
+\r
+Arguments:\r
+ None\r
+\r
+Returns:\r
+ Status - EFI_SUCCESS\r
+\r
+--*/\r
+{\r
+ IoWrite32 (EFI_PCI_ADDRESS_PORT, mPciAddress);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+SmiInputValueDuplicateCheck (\r
+ UINTN FedSwSmiInputValue\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Check the Fed SwSmiInputValue to see if there is a duplicated one in the database\r
+\r
+Arguments:\r
+ None\r
+\r
+Returns:\r
+ Status - EFI_SUCCESS, EFI_INVALID_PARAMETER\r
+\r
+--*/\r
+// GC_TODO: FedSwSmiInputValue - add argument and description to function comment\r
+{\r
+\r
+ DATABASE_RECORD *RecordInDb;\r
+ LIST_ENTRY *LinkInDb;\r
+\r
+ LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
+ while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
+ RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
+\r
+ if (RecordInDb->ProtocolType == SwType) {\r
+ if (RecordInDb->ChildContext.Sw.SwSmiInputValue == FedSwSmiInputValue) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+QNCSmmCoreRegister (\r
+ IN QNC_SMM_GENERIC_PROTOCOL *This,\r
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,\r
+ IN QNC_SMM_CONTEXT *RegisterContext,\r
+ OUT EFI_HANDLE *DispatchHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+// GC_TODO: This - add argument and description to function comment\r
+// GC_TODO: DispatchFunction - add argument and description to function comment\r
+// GC_TODO: RegisterContext - add argument and description to function comment\r
+// GC_TODO: DispatchHandle - add argument and description to function comment\r
+// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
+// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
+// GC_TODO: EFI_SUCCESS - add return value to function comment\r
+// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
+{\r
+ EFI_STATUS Status;\r
+ DATABASE_RECORD *Record;\r
+ QNC_SMM_QUALIFIED_PROTOCOL *Qualified;\r
+ INTN Index;\r
+\r
+ //\r
+ // Check for invalid parameter\r
+ //\r
+ if (This == NULL || RegisterContext == NULL || DispatchHandle == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Create database record and add to database\r
+ //\r
+ Record = (DATABASE_RECORD *) AllocateZeroPool (sizeof (DATABASE_RECORD));\r
+ if (Record == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Gather information about the registration request\r
+ //\r
+ Record->Callback = DispatchFunction;\r
+ Record->ChildContext = *RegisterContext;\r
+\r
+ Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This);\r
+\r
+ Record->ProtocolType = Qualified->Type;\r
+\r
+ CopyMem (&Record->ContextFunctions, &mContextFunctions[Qualified->Type], sizeof (Record->ContextFunctions));\r
+ //\r
+ // Perform linked list housekeeping\r
+ //\r
+ Record->Signature = DATABASE_RECORD_SIGNATURE;\r
+\r
+ switch (Qualified->Type) {\r
+ //\r
+ // By the end of this switch statement, we'll know the\r
+ // source description the child is registering for\r
+ //\r
+ case SxType:\r
+ //\r
+ // Check the validity of Context Type and Phase\r
+ //\r
+ if ((Record->ChildContext.Sx.Type < SxS0) ||\r
+ (Record->ChildContext.Sx.Type >= EfiMaximumSleepType) ||\r
+ (Record->ChildContext.Sx.Phase < SxEntry) ||\r
+ (Record->ChildContext.Sx.Phase >= EfiMaximumPhase)\r
+ ) {\r
+ goto Error;\r
+ }\r
+\r
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
+ CopyMem (&Record->SrcDesc, &SX_SOURCE_DESC, sizeof (Record->SrcDesc));\r
+ //\r
+ // use default clear source function\r
+ //\r
+ break;\r
+\r
+ case SwType:\r
+ if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {\r
+ //\r
+ // If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure.\r
+ //\r
+ Status = EFI_NOT_FOUND;\r
+ for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {\r
+ Status = SmiInputValueDuplicateCheck (Index);\r
+ if (!EFI_ERROR (Status)) {\r
+ RegisterContext->Sw.SwSmiInputValue = Index;\r
+ break;\r
+ }\r
+ }\r
+ if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {\r
+ Status = gSmst->SmmFreePool (Record);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Update ChildContext again as SwSmiInputValue has been changed\r
+ //\r
+ Record->ChildContext = *RegisterContext;\r
+ }\r
+\r
+ //\r
+ // Check the validity of Context Value\r
+ //\r
+ if (Record->ChildContext.Sw.SwSmiInputValue > MAXIMUM_SWI_VALUE) {\r
+ goto Error;\r
+ }\r
+\r
+ if (EFI_ERROR (SmiInputValueDuplicateCheck (Record->ChildContext.Sw.SwSmiInputValue))) {\r
+ goto Error;\r
+ }\r
+\r
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
+ CopyMem (&Record->SrcDesc, &SW_SOURCE_DESC, sizeof (Record->SrcDesc));\r
+ Record->BufferSize = sizeof (EFI_SMM_SW_REGISTER_CONTEXT);\r
+ //\r
+ // use default clear source function\r
+ //\r
+ break;\r
+\r
+ case GpiType:\r
+\r
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
+ CopyMem (&Record->SrcDesc, &GPI_SOURCE_DESC, sizeof (Record->SrcDesc));\r
+ //\r
+ // use default clear source function\r
+ //\r
+ break;\r
+\r
+ case QNCnType:\r
+ //\r
+ // Check the validity of Context Type\r
+ //\r
+ if ((Record->ChildContext.QNCn.Type < IchnMch) || (Record->ChildContext.QNCn.Type >= NUM_ICHN_TYPES)) {\r
+ goto Error;\r
+ }\r
+\r
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
+ CopyMem (&Record->SrcDesc, &QNCN_SOURCE_DESCS[Record->ChildContext.QNCn.Type], sizeof (Record->SrcDesc));\r
+ Record->ClearSource = QNCSmmQNCnClearSource;\r
+ break;\r
+\r
+ case PeriodicTimerType:\r
+\r
+ Status = MapPeriodicTimerToSrcDesc (RegisterContext, &(Record->SrcDesc));\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+\r
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);\r
+ Record->BufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);\r
+ Record->ClearSource = QNCSmmPeriodicTimerClearSource;\r
+ break;\r
+\r
+ default:\r
+ goto Error;\r
+ break;\r
+ };\r
+\r
+ if (Record->ClearSource == NULL) {\r
+ //\r
+ // Clear the SMI associated w/ the source using the default function\r
+ //\r
+ QNCSmmClearSource (&Record->SrcDesc);\r
+ } else {\r
+ //\r
+ // This source requires special handling to clear\r
+ //\r
+ Record->ClearSource (&Record->SrcDesc);\r
+ }\r
+\r
+ QNCSmmEnableSource (&Record->SrcDesc);\r
+\r
+ //\r
+ // Child's handle will be the address linked list link in the record\r
+ //\r
+ *DispatchHandle = (EFI_HANDLE) (&Record->Link);\r
+\r
+ return EFI_SUCCESS;\r
+\r
+Error:\r
+ FreePool (Record);\r
+ //\r
+ // DEBUG((EFI_D_ERROR,"Free pool status %d\n", Status ));\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+}\r
+\r
+EFI_STATUS\r
+QNCSmmCoreUnRegister (\r
+ IN QNC_SMM_GENERIC_PROTOCOL *This,\r
+ IN EFI_HANDLE DispatchHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+// GC_TODO: This - add argument and description to function comment\r
+// GC_TODO: DispatchHandle - add argument and description to function comment\r
+// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
+// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
+// GC_TODO: EFI_SUCCESS - add return value to function comment\r
+{\r
+ BOOLEAN SafeToDisable;\r
+ DATABASE_RECORD *RecordToDelete;\r
+ DATABASE_RECORD *RecordInDb;\r
+ LIST_ENTRY *LinkInDb;\r
+\r
+ if (DispatchHandle == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);\r
+\r
+ RemoveEntryList (&RecordToDelete->Link);\r
+ RecordToDelete->Signature = 0;\r
+\r
+ //\r
+ // See if we can disable the source, reserved for future use since this might\r
+ // not be the only criteria to disable\r
+ //\r
+ SafeToDisable = TRUE;\r
+ LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
+ while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
+ RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
+ if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) {\r
+ SafeToDisable = FALSE;\r
+ break;\r
+ }\r
+ LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
+ }\r
+ if (SafeToDisable) {\r
+ QNCSmmDisableSource( &RecordToDelete->SrcDesc );\r
+}\r
+\r
+ FreePool (RecordToDelete);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is the main entry point for an SMM handler dispatch\r
+ or communicate-based callback.\r
+\r
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
+ @param RegisterContext Points to an optional handler context which was specified when the handler was registered.\r
+ @param CommBuffer A pointer to a collection of data in memory that will\r
+ be conveyed from a non-SMM environment into an SMM environment.\r
+ @param CommBufferSize The size of the CommBuffer.\r
+\r
+ @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+QNCSmmCoreDispatcher (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *RegisterContext,\r
+ IN OUT VOID *CommBuffer,\r
+ IN OUT UINTN *CommBufferSize\r
+ )\r
+{\r
+ //\r
+ // Used to prevent infinite loops\r
+ //\r
+ UINTN EscapeCount;\r
+\r
+ BOOLEAN ContextsMatch;\r
+ BOOLEAN ResetListSearch;\r
+ BOOLEAN EosSet;\r
+ BOOLEAN SxChildWasDispatched;\r
+ BOOLEAN ChildWasDispatched;\r
+\r
+ DATABASE_RECORD *RecordInDb;\r
+ LIST_ENTRY *LinkInDb;\r
+ DATABASE_RECORD *RecordToExhaust;\r
+ LIST_ENTRY *LinkToExhaust;\r
+\r
+ QNC_SMM_CONTEXT Context;\r
+ VOID *CommunicationBuffer;\r
+ UINTN BufferSize;\r
+\r
+ EFI_STATUS Status;\r
+ UINT32 NewValue;\r
+\r
+ QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER;\r
+\r
+ EscapeCount = 100;\r
+ ContextsMatch = FALSE;\r
+ ResetListSearch = FALSE;\r
+ EosSet = FALSE;\r
+ SxChildWasDispatched = FALSE;\r
+ Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
+ ChildWasDispatched = FALSE;\r
+\r
+ //\r
+ // Preserve Index registers\r
+ //\r
+ SaveState ();\r
+\r
+ if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {\r
+ //\r
+ // We have children registered w/ us -- continue\r
+ //\r
+ while ((!EosSet) && (EscapeCount > 0)) {\r
+ EscapeCount--;\r
+\r
+ //\r
+ // Reset this flag in order to be able to process multiple SMI Sources in one loop.\r
+ //\r
+ ResetListSearch = FALSE;\r
+\r
+ LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
+\r
+ while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) {\r
+ RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
+\r
+ //\r
+ // look for the first active source\r
+ //\r
+ if (!SourceIsActive (&RecordInDb->SrcDesc)) {\r
+ //\r
+ // Didn't find the source yet, keep looking\r
+ //\r
+ LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
+\r
+ } else {\r
+ //\r
+ // We found a source. If this is a sleep type, we have to go to\r
+ // appropriate sleep state anyway.No matter there is sleep child or not\r
+ //\r
+ if (RecordInDb->ProtocolType == SxType) {\r
+ SxChildWasDispatched = TRUE;\r
+ }\r
+ //\r
+ // "cache" the source description and don't query I/O anymore\r
+ //\r
+ CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource));\r
+ LinkToExhaust = LinkInDb;\r
+\r
+ //\r
+ // exhaust the rest of the queue looking for the same source\r
+ //\r
+ while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {\r
+ RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust);\r
+\r
+ if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {\r
+ //\r
+ // These source descriptions are equal, so this callback should be\r
+ // dispatched.\r
+ //\r
+ if (RecordToExhaust->ContextFunctions.GetContext != NULL) {\r
+ //\r
+ // This child requires that we get a calling context from\r
+ // hardware and compare that context to the one supplied\r
+ // by the child.\r
+ //\r
+ ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL);\r
+\r
+ //\r
+ // Make sure contexts match before dispatching event to child\r
+ //\r
+ RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context);\r
+ ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext);\r
+\r
+ } else {\r
+ //\r
+ // This child doesn't require any more calling context beyond what\r
+ // it supplied in registration. Simply pass back what it gave us.\r
+ //\r
+ ASSERT (RecordToExhaust->Callback != NULL);\r
+ Context = RecordToExhaust->ChildContext;\r
+ ContextsMatch = TRUE;\r
+ }\r
+\r
+ if (ContextsMatch) {\r
+\r
+ if (RecordToExhaust->BufferSize != 0) {\r
+ ASSERT (RecordToExhaust->ContextFunctions.GetBuffer != NULL);\r
+\r
+ RecordToExhaust->ContextFunctions.GetBuffer (RecordToExhaust);\r
+\r
+ CommunicationBuffer = &RecordToExhaust->CommBuffer;\r
+ BufferSize = RecordToExhaust->BufferSize;\r
+ } else {\r
+ CommunicationBuffer = NULL;\r
+ BufferSize = 0;\r
+ }\r
+\r
+ ASSERT (RecordToExhaust->Callback != NULL);\r
+\r
+ RecordToExhaust->Callback (\r
+ (EFI_HANDLE) & RecordToExhaust->Link,\r
+ &Context,\r
+ CommunicationBuffer,\r
+ &BufferSize\r
+ );\r
+\r
+ ChildWasDispatched = TRUE;\r
+ if (RecordToExhaust->ProtocolType == SxType) {\r
+ SxChildWasDispatched = TRUE;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Get next record in DB\r
+ //\r
+ LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, &RecordToExhaust->Link);\r
+ }\r
+\r
+ if (RecordInDb->ClearSource == NULL) {\r
+ //\r
+ // Clear the SMI associated w/ the source using the default function\r
+ //\r
+ QNCSmmClearSource (&ActiveSource);\r
+ } else {\r
+ //\r
+ // This source requires special handling to clear\r
+ //\r
+ RecordInDb->ClearSource (&ActiveSource);\r
+ }\r
+\r
+ if (ChildWasDispatched) {\r
+ //\r
+ // The interrupt was handled and quiesced\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ //\r
+ // The interrupt was not handled but quiesced\r
+ //\r
+ Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
+ }\r
+\r
+ //\r
+ // Queue is empty, reset the search\r
+ //\r
+ ResetListSearch = TRUE;\r
+\r
+ }\r
+ }\r
+ EosSet = QNCSmmSetAndCheckEos ();\r
+ }\r
+ }\r
+ //\r
+ // If you arrive here, there are two possible reasons:\r
+ // (1) you've got problems with clearing the SMI status bits in the\r
+ // ACPI table. If you don't properly clear the SMI bits, then you won't be able to set the\r
+ // EOS bit. If this happens too many times, the loop exits.\r
+ // (2) there was a SMM communicate for callback messages that was received prior\r
+ // to this driver.\r
+ // If there is an asynchronous SMI that occurs while processing the Callback, let\r
+ // all of the drivers (including this one) have an opportunity to scan for the SMI\r
+ // and handle it.\r
+ // If not, we don't want to exit and have the foreground app. clear EOS without letting\r
+ // these other sources get serviced.\r
+ //\r
+ ASSERT (EscapeCount > 0);\r
+\r
+ //\r
+ // Restore Index registers\r
+ //\r
+ RestoreState ();\r
+\r
+ if (SxChildWasDispatched) {\r
+ //\r
+ // A child of the SmmSxDispatch protocol was dispatched during this call;\r
+ // put the system to sleep.\r
+ //\r
+ QNCSmmSxGoToSleep ();\r
+ }\r
+\r
+ //\r
+ // Ensure that SMI signal pin indicator is clear at the end of SMM handling.\r
+ //\r
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG);\r
+ NewValue &= ~(HLEGACY_SMI_PIN_VALUE);\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG, NewValue);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+## @file\r
+# Component description file for QuarkNcSocId SmmDispatcher module.\r
+#\r
+# This driver is responsible for the registration of child drivers\r
+# and the abstraction of the ICH SMI sources.\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = QNCSmmDispatcher\r
+ FILE_GUID = 2480271C-09C6-4f36-AD75-5E1390BD9929\r
+ MODULE_TYPE = DXE_SMM_DRIVER\r
+ VERSION_STRING = 1.0\r
+ PI_SPECIFICATION_VERSION = 0x0001000A\r
+ ENTRY_POINT = InitializeQNCSmmDispatcher\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ QNC/QNCSmmPeriodicTimer.c\r
+ QNC/QNCSmmQncn.c\r
+ QNC/QNCSmmSx.c\r
+ QNC/QNCSmmSw.c\r
+ QNC/QNCSmmGpi.c\r
+ QNC/QNCSmmHelpers.c\r
+ QNCSmmHelpers.c\r
+ QNCSmmCore.c\r
+ QNCSmmHelpers.h\r
+ QNCxSmmHelpers.h\r
+ QNCSmmRegisters.h\r
+ QNCSmm.h\r
+ CommonHeader.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+\r
+[LibraryClasses]\r
+ UefiDriverEntryPoint\r
+ SmmServicesTableLib\r
+ UefiBootServicesTableLib\r
+ DxeServicesTableLib\r
+ MemoryAllocationLib\r
+ PciLib\r
+ PcdLib\r
+ BaseMemoryLib\r
+ DebugLib\r
+ BaseLib\r
+ IoLib\r
+ DevicePathLib\r
+ S3IoLib\r
+ QNCAccessLib\r
+\r
+[Protocols]\r
+ gEfiSmmCpuProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiSmmReadyToLockProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiSmmPeriodicTimerDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiSmmPowerButtonDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiSmmIchnDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiSmmGpiDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiSmmSwDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiSmmSxDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiSmmUsbDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiSmmIoTrapDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+\r
+[Pcd]\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress\r
+\r
+[Depex]\r
+ gEfiSmmCpuProtocolGuid AND gEfiPciRootBridgeIoProtocolGuid\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmm.h"\r
+#include "QNCSmmHelpers.h"\r
+\r
+//\r
+// #define BIT_ZERO 0x00000001\r
+//\r
+CONST UINT32 BIT_ZERO = 0x00000001;\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// SUPPORT / HELPER FUNCTIONS (QNC version-independent)\r
+//\r
+BOOLEAN\r
+CompareEnables (\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src2\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Src1 - GC_TODO: add argument description\r
+ Src2 - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ BOOLEAN IsEqual;\r
+ UINTN loopvar;\r
+\r
+ IsEqual = TRUE;\r
+ for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {\r
+ //\r
+ // It's okay to compare a NULL bit description to a non-NULL bit description.\r
+ // They are unequal and these tests will generate the correct result.\r
+ //\r
+ if (Src1->En[loopvar].Bit != Src2->En[loopvar].Bit ||\r
+ Src1->En[loopvar].Reg.Type != Src2->En[loopvar].Reg.Type ||\r
+ Src1->En[loopvar].Reg.Data.raw != Src2->En[loopvar].Reg.Data.raw\r
+ ) {\r
+ IsEqual = FALSE;\r
+ break;\r
+ //\r
+ // out of for loop\r
+ //\r
+ }\r
+ }\r
+\r
+ return IsEqual;\r
+}\r
+\r
+BOOLEAN\r
+CompareStatuses (\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src2\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Src1 - GC_TODO: add argument description\r
+ Src2 - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ BOOLEAN IsEqual;\r
+ UINTN loopvar;\r
+\r
+ IsEqual = TRUE;\r
+\r
+ for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {\r
+ //\r
+ // It's okay to compare a NULL bit description to a non-NULL bit description.\r
+ // They are unequal and these tests will generate the correct result.\r
+ //\r
+ if (Src1->Sts[loopvar].Bit != Src2->Sts[loopvar].Bit ||\r
+ Src1->Sts[loopvar].Reg.Type != Src2->Sts[loopvar].Reg.Type ||\r
+ Src1->Sts[loopvar].Reg.Data.raw != Src2->Sts[loopvar].Reg.Data.raw\r
+ ) {\r
+ IsEqual = FALSE;\r
+ break;\r
+ //\r
+ // out of for loop\r
+ //\r
+ }\r
+ }\r
+\r
+ return IsEqual;\r
+}\r
+\r
+BOOLEAN\r
+CompareSources (\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src2\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Src1 - GC_TODO: add argument description\r
+ Src2 - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses (Src1, Src2));\r
+}\r
+\r
+BOOLEAN\r
+SourceIsActive (\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Src - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ BOOLEAN IsActive;\r
+ UINTN loopvar;\r
+\r
+ BOOLEAN SciEn;\r
+\r
+ IsActive = TRUE;\r
+\r
+ SciEn = QNCSmmGetSciEn ();\r
+\r
+ if ((Src->Flags & QNC_SMM_SCI_EN_DEPENDENT) && (SciEn)) {\r
+ //\r
+ // This source is dependent on SciEn, and SciEn == 1. An ACPI OS is present,\r
+ // so we shouldn't do anything w/ this source until SciEn == 0.\r
+ //\r
+ IsActive = FALSE;\r
+\r
+ } else {\r
+ //\r
+ // Read each bit desc from hardware and make sure it's a one\r
+ //\r
+ for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {\r
+\r
+ if (!IS_BIT_DESC_NULL (Src->En[loopvar])) {\r
+\r
+ if (ReadBitDesc (&Src->En[loopvar]) == 0) {\r
+ IsActive = FALSE;\r
+ break;\r
+ //\r
+ // out of for loop\r
+ //\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ if (IsActive) {\r
+ //\r
+ // Read each bit desc from hardware and make sure it's a one\r
+ //\r
+ for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {\r
+\r
+ if (!IS_BIT_DESC_NULL (Src->Sts[loopvar])) {\r
+\r
+ if (ReadBitDesc (&Src->Sts[loopvar]) == 0) {\r
+ IsActive = FALSE;\r
+ break;\r
+ //\r
+ // out of for loop\r
+ //\r
+ }\r
+\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return IsActive;\r
+}\r
+\r
+VOID\r
+QNCSmmEnableSource (\r
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SrcDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ UINTN loopvar;\r
+\r
+ //\r
+ // Set enables to 1 by writing a 1\r
+ //\r
+ for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {\r
+ if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) {\r
+ WriteBitDesc (&SrcDesc->En[loopvar], 1);\r
+ }\r
+ }\r
+\r
+ QNCSmmClearSource (SrcDesc);\r
+\r
+}\r
+\r
+VOID\r
+QNCSmmDisableSource (\r
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SrcDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ UINTN loopvar;\r
+\r
+ for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {\r
+ if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) {\r
+ WriteBitDesc (&SrcDesc->En[loopvar], 0);\r
+ }\r
+ }\r
+}\r
+\r
+VOID\r
+QNCSmmClearSource (\r
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SrcDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ UINTN loopvar;\r
+ BOOLEAN ValueToWrite;\r
+\r
+ ValueToWrite =\r
+ ((SrcDesc->Flags & QNC_SMM_CLEAR_WITH_ZERO) == 0) ? TRUE : FALSE;\r
+\r
+ for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {\r
+ if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) {\r
+ WriteBitDesc (&SrcDesc->Sts[loopvar], ValueToWrite);\r
+ }\r
+ }\r
+}\r
+\r
+VOID\r
+QNCSmmClearSourceAndBlock (\r
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+// GC_TODO: function comment should start with '/*++'\r
+/*\r
+ Sets the source to a 1 or 0 and then waits for it to clear.\r
+ Be very careful when calling this function -- it will not\r
+ ASSERT. An acceptable case to call the function is when\r
+ waiting for the NEWCENTURY_STS bit to clear (which takes\r
+ 3 RTCCLKs).\r
+*/\r
+// GC_TODO: function comment should end with '--*/'\r
+// GC_TODO: function comment is missing 'Routine Description:'\r
+// GC_TODO: function comment is missing 'Arguments:'\r
+// GC_TODO: function comment is missing 'Returns:'\r
+// GC_TODO: SrcDesc - add argument and description to function comment\r
+{\r
+ UINTN loopvar;\r
+ BOOLEAN IsSet;\r
+ BOOLEAN ValueToWrite;\r
+\r
+ ValueToWrite =\r
+ ((SrcDesc->Flags & QNC_SMM_CLEAR_WITH_ZERO) == 0) ? TRUE : FALSE;\r
+\r
+ for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {\r
+\r
+ if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) {\r
+ //\r
+ // Write the bit\r
+ //\r
+ WriteBitDesc (&SrcDesc->Sts[loopvar], ValueToWrite);\r
+\r
+ //\r
+ // Don't return until the bit actually clears.\r
+ //\r
+ IsSet = TRUE;\r
+ while (IsSet) {\r
+ IsSet = ReadBitDesc (&SrcDesc->Sts[loopvar]);\r
+ //\r
+ // IsSet will eventually clear -- or else we'll have\r
+ // an infinite loop.\r
+ //\r
+ }\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef QNC_SMM_HELPERS_H\r
+#define QNC_SMM_HELPERS_H\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmm.h"\r
+#include "QNCxSmmHelpers.h"\r
+\r
+//\r
+// /////////////////////////////////////////////////////////////////////////////\r
+// SUPPORT / HELPER FUNCTIONS (QNC version-independent)\r
+//\r
+VOID\r
+QNCSmmPublishDispatchProtocols (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+CompareEnables (\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src2\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Src1 - GC_TODO: add argument description\r
+ Src2 - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+CompareStatuses (\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src2\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Src1 - GC_TODO: add argument description\r
+ Src2 - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+CompareSources (\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src1,\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src2\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Src1 - GC_TODO: add argument description\r
+ Src2 - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+SourceIsActive (\r
+ CONST IN QNC_SMM_SOURCE_DESC *Src\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Src - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+QNCSmmEnableSource (\r
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SrcDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+QNCSmmDisableSource (\r
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SrcDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+QNCSmmClearSource (\r
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SrcDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+QNCSmmClearSourceAndBlock (\r
+ CONST QNC_SMM_SOURCE_DESC *SrcDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SrcDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef QNC_SMM_REGISTERS_H\r
+#define QNC_SMM_REGISTERS_H\r
+#include "CommonHeader.h"\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef QNCX_SMM_HELPERS_H\r
+#define QNCX_SMM_HELPERS_H\r
+\r
+//\r
+// Include common header file for this module.\r
+//\r
+#include "CommonHeader.h"\r
+\r
+#include "QNCSmm.h"\r
+\r
+EFI_STATUS\r
+QNCSmmInitHardware (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+QNCSmmEnableGlobalSmiBit (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Enables the QNC to generate SMIs. Note that no SMIs will be generated\r
+ if no SMI sources are enabled. Conversely, no enabled SMI source will\r
+ generate SMIs if SMIs are not globally enabled. This is the main\r
+ switchbox for SMI generation.\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS.\r
+ Asserts, otherwise.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+QNCSmmClearSmi (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+QNCSmmSetAndCheckEos (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+QNCSmmGetSciEn (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+//\r
+// ///////////////////////////////////////////////////////////////////////////\r
+//\r
+// These may or may not need to change w/ the QNC version;\r
+// they're here because they're highly IA-32 dependent.\r
+//\r
+BOOLEAN\r
+ReadBitDesc (\r
+ CONST QNC_SMM_BIT_DESC *BitDesc\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ BitDesc - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+WriteBitDesc (\r
+ CONST QNC_SMM_BIT_DESC *BitDesc,\r
+ CONST BOOLEAN ValueToWrite\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ BitDesc - GC_TODO: add argument description\r
+ ValueToWrite - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This is the driver that publishes the SMM Access Ppi\r
+instance for the Quark SOC.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include <PiPei.h>\r
+#include <Ppi/SmmAccess.h>\r
+#include <Guid/SmramMemoryReserve.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/QNCSmmLib.h>\r
+#include <QNCAccess.h>\r
+\r
+#define SMM_ACCESS_PRIVATE_DATA_FROM_THIS(a) \\r
+ CR ( \\r
+ a, \\r
+ SMM_ACCESS_PRIVATE_DATA, \\r
+ SmmAccess, \\r
+ SMM_ACCESS_PRIVATE_DATA_SIGNATURE \\r
+ )\r
+\r
+#define MAX_CPU_SOCKET 1\r
+#define MAX_SMRAM_RANGES 4\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EFI_HANDLE Handle;\r
+ PEI_SMM_ACCESS_PPI SmmAccess;\r
+ UINTN NumberRegions;\r
+ EFI_SMRAM_DESCRIPTOR SmramDesc[MAX_SMRAM_RANGES];\r
+ UINT8 TsegSize;\r
+ UINT8 MaxBusNumber;\r
+ UINT8 SocketPopulated[MAX_CPU_SOCKET];\r
+ UINT8 SocketBusNum[MAX_CPU_SOCKET];\r
+} SMM_ACCESS_PRIVATE_DATA;\r
+\r
+#define SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', 's', 'm', 'a')\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Open (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_SMM_ACCESS_PPI *This,\r
+ IN UINTN DescriptorIndex\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine accepts a request to "open" a region of SMRAM. The\r
+ region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.\r
+ The use of "open" means that the memory is visible from all PEIM\r
+ and SMM agents.\r
+\r
+Arguments:\r
+\r
+ PeiServices - General purpose services available to every PEIM.\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Open.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully opened.\r
+ EFI_DEVICE_ERROR - The region could not be opened because locked by\r
+ chipset.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+{\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (DescriptorIndex >= SmmAccess->NumberRegions) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Open TSEG\r
+ //\r
+ if (!QNCOpenSmramRegion ()) {\r
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED);\r
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_OPEN;\r
+ SmmAccess->SmmAccess.OpenState = TRUE;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Close (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_SMM_ACCESS_PPI *This,\r
+ IN UINTN DescriptorIndex\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine accepts a request to "close" a region of SMRAM. This is valid for\r
+ compatible SMRAM region.\r
+\r
+Arguments:\r
+\r
+ PeiServices - General purpose services available to every PEIM.\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Close.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully closed.\r
+ EFI_DEVICE_ERROR - The region could not be closed because locked by\r
+ chipset.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+{\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+ BOOLEAN OpenState;\r
+ UINTN Index;\r
+\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (DescriptorIndex >= SmmAccess->NumberRegions) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_CLOSED) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Close TSEG\r
+ //\r
+ if (!QNCCloseSmramRegion ()) {\r
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~EFI_SMRAM_OPEN;\r
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED);\r
+\r
+ //\r
+ // Find out if any regions are still open\r
+ //\r
+ OpenState = FALSE;\r
+ for (Index = 0; Index < SmmAccess->NumberRegions; Index++) {\r
+ if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) {\r
+ OpenState = TRUE;\r
+ }\r
+ }\r
+\r
+ SmmAccess->SmmAccess.OpenState = OpenState;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+Lock (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_SMM_ACCESS_PPI *This,\r
+ IN UINTN DescriptorIndex\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine accepts a request to "lock" SMRAM. The\r
+ region could be legacy AB or TSEG near top of physical memory.\r
+ The use of "lock" means that the memory can no longer be opened\r
+ to PEIM.\r
+\r
+Arguments:\r
+\r
+ PeiServices - General purpose services available to every PEIM.\r
+ This - Pointer to the SMM Access Interface.\r
+ DescriptorIndex - Region of SMRAM to Lock.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The region was successfully locked.\r
+ EFI_DEVICE_ERROR - The region could not be locked because at least\r
+ one range is still open.\r
+ EFI_INVALID_PARAMETER - The descriptor index was out of bounds.\r
+\r
+--*/\r
+{\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (DescriptorIndex >= SmmAccess->NumberRegions) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } else if (SmmAccess->SmmAccess.OpenState) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;\r
+ SmmAccess->SmmAccess.LockState = TRUE;\r
+\r
+ //\r
+ // Lock TSEG\r
+ //\r
+ QNCLockSmramRegion ();\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+GetCapabilities (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_SMM_ACCESS_PPI *This,\r
+ IN OUT UINTN *SmramMapSize,\r
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This routine services a user request to discover the SMRAM\r
+ capabilities of this platform. This will report the possible\r
+ ranges that are possible for SMRAM access, based upon the\r
+ memory controller capabilities.\r
+\r
+Arguments:\r
+\r
+ PeiServices - General purpose services available to every PEIM.\r
+ This - Pointer to the SMRAM Access Interface.\r
+ SmramMapSize - Pointer to the variable containing size of the\r
+ buffer to contain the description information.\r
+ SmramMap - Buffer containing the data describing the Smram\r
+ region descriptors.\r
+Returns:\r
+\r
+ EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer.\r
+ EFI_SUCCESS - The user provided a sufficiently-sized buffer.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccess;\r
+ UINTN BufferSize;\r
+\r
+ SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);\r
+ BufferSize = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR);\r
+\r
+ if (*SmramMapSize < BufferSize) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+ CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize);\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ *SmramMapSize = BufferSize;\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAccessPeiEntryPoint (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This is the constructor for the SMM Access Ppi\r
+\r
+Arguments:\r
+\r
+ FfsHeader - FfsHeader.\r
+ PeiServices - General purpose services available to every PEIM.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Protocol successfully started and installed.\r
+ EFI_UNSUPPORTED - Protocol can't be started.\r
+--*/\r
+{\r
+\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;\r
+ SMM_ACCESS_PRIVATE_DATA *SmmAccessPrivate;\r
+ EFI_PEI_PPI_DESCRIPTOR *PpiList;\r
+ EFI_HOB_GUID_TYPE *GuidHob;\r
+\r
+ //\r
+ // Initialize private data\r
+ //\r
+ SmmAccessPrivate = AllocatePool (sizeof(*SmmAccessPrivate));\r
+ ASSERT(SmmAccessPrivate);\r
+\r
+ PpiList = AllocatePool (sizeof(*PpiList));\r
+ ASSERT (PpiList);\r
+\r
+ //\r
+ // Build SMM related information\r
+ //\r
+ SmmAccessPrivate->Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE;\r
+\r
+ //\r
+ // Get Hob list\r
+ //\r
+ GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);\r
+ DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);\r
+ ASSERT (DescriptorBlock);\r
+\r
+ // Get CPU Max bus number\r
+\r
+ SmmAccessPrivate->MaxBusNumber = PCI_BUS_NUMBER_QNC;\r
+ for (Index = 0; Index < MAX_CPU_SOCKET; Index++) {\r
+ SmmAccessPrivate->SocketPopulated[Index] = TRUE;\r
+ SmmAccessPrivate->SocketBusNum[Index] = PCI_BUS_NUMBER_QNC;\r
+ }\r
+\r
+ //\r
+ // Use the hob to publish SMRAM capabilities\r
+ //\r
+ ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES);\r
+ for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {\r
+ SmmAccessPrivate->SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart;\r
+ SmmAccessPrivate->SmramDesc[Index].CpuStart = DescriptorBlock->Descriptor[Index].CpuStart;\r
+ SmmAccessPrivate->SmramDesc[Index].PhysicalSize = DescriptorBlock->Descriptor[Index].PhysicalSize;\r
+ SmmAccessPrivate->SmramDesc[Index].RegionState = DescriptorBlock->Descriptor[Index].RegionState;\r
+ }\r
+\r
+ SmmAccessPrivate->NumberRegions = Index;\r
+ SmmAccessPrivate->SmmAccess.Open = Open;\r
+ SmmAccessPrivate->SmmAccess.Close = Close;\r
+ SmmAccessPrivate->SmmAccess.Lock = Lock;\r
+ SmmAccessPrivate->SmmAccess.GetCapabilities = GetCapabilities;\r
+ SmmAccessPrivate->SmmAccess.LockState = FALSE;\r
+ SmmAccessPrivate->SmmAccess.OpenState = FALSE;\r
+\r
+ PpiList->Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ PpiList->Guid = &gPeiSmmAccessPpiGuid;\r
+ PpiList->Ppi = &SmmAccessPrivate->SmmAccess;\r
+\r
+ Status = (**PeiServices).InstallPpi (PeiServices, PpiList);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ DEBUG (\r
+ (EFI_D_INFO, "SMM Base:Size %08X:%08X\n",\r
+ (UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalStart),\r
+ (UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize)\r
+ ));\r
+\r
+ SmmAccessPrivate->TsegSize = (UINT8)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
--- /dev/null
+## @file\r
+# Component description file for SmmAccessPei module\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+INF_VERSION = 0x00010005\r
+BASE_NAME = SmmAccessPei\r
+FILE_GUID = B4E0CDFC-30CD-4b29-A445-B0AA95A532E4\r
+MODULE_TYPE = PEIM\r
+VERSION_STRING = 1.0\r
+ENTRY_POINT = SmmAccessPeiEntryPoint\r
+\r
+[Sources]\r
+ SmmAccessPei.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ PeimEntryPoint\r
+ BaseMemoryLib\r
+ MemoryAllocationLib\r
+ DebugLib\r
+ HobLib\r
+ PeiServicesLib\r
+ PciLib\r
+ SmmLib\r
+\r
+[Guids]\r
+ gEfiSmmPeiSmramMemoryReserveGuid # ALWAYS_CONSUMED\r
+\r
+[Ppis]\r
+ gPeiSmmAccessPpiGuid # ALWAYS_PRODUCED\r
+ gEfiPeiMemoryDiscoveredPpiGuid # ALWAYS_CONSUMED\r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid\r
--- /dev/null
+/** @file\r
+This module provides an implementation of the SMM Control PPI for use with\r
+the QNC.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/SmmControl.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PciLib.h>\r
+\r
+#include <IntelQNCPeim.h>\r
+#include <Library/QNCAccessLib.h>\r
+#include <Uefi/UefiBaseType.h>\r
+\r
+/**\r
+ Generates an SMI using the parameters passed in.\r
+\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param This A pointer to an instance of\r
+ EFI_SMM_CONTROL_PPI\r
+ @param ArgumentBuffer The argument buffer\r
+ @param ArgumentBufferSize The size of the argument buffer\r
+ @param Periodic TRUE to indicate a periodical SMI\r
+ @param ActivationInterval Interval of the periodical SMI\r
+\r
+ @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1\r
+ @retval EFI_SUCCESS SMI generated\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiActivate (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_SMM_CONTROL_PPI *This,\r
+ IN OUT INT8 *ArgumentBuffer OPTIONAL,\r
+ IN OUT UINTN *ArgumentBufferSize OPTIONAL,\r
+ IN BOOLEAN Periodic OPTIONAL,\r
+ IN UINTN ActivationInterval OPTIONAL\r
+ );\r
+\r
+/**\r
+ Clears an SMI.\r
+\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param This Pointer to an instance of EFI_SMM_CONTROL_PPI\r
+ @param Periodic TRUE to indicate a periodical SMI\r
+\r
+ @return Return value from SmmClear()\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiDeactivate (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_SMM_CONTROL_PPI *This,\r
+ IN BOOLEAN Periodic OPTIONAL\r
+ );\r
+\r
+PEI_SMM_CONTROL_PPI mSmmControlPpi = {\r
+ PeiActivate,\r
+ PeiDeactivate\r
+};\r
+\r
+EFI_PEI_PPI_DESCRIPTOR mPpiList = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gPeiSmmControlPpiGuid,\r
+ &mSmmControlPpi\r
+};\r
+\r
+/**\r
+ Clear SMI related chipset status and re-enable SMI by setting the EOS bit.\r
+\r
+ @retval EFI_SUCCESS The requested operation has been carried out successfully\r
+ @retval EFI_DEVICE_ERROR The EOS bit could not be set.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmClear (\r
+ VOID\r
+ )\r
+{\r
+ UINT16 PM1BLK_Base;\r
+ UINT16 GPE0BLK_Base;\r
+\r
+ //\r
+ // Get PM1BLK_Base & GPE0BLK_Base\r
+ //\r
+ PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);\r
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);\r
+\r
+ //\r
+ // Clear the Power Button Override Status Bit, it gates EOS from being set.\r
+ // In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.\r
+ //\r
+\r
+ //\r
+ // Clear the APM SMI Status Bit\r
+ //\r
+ IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);\r
+\r
+ //\r
+ // Set the EOS Bit\r
+ //\r
+ IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SmmTrigger (\r
+ IN UINT8 Data\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Trigger the software SMI\r
+\r
+Arguments:\r
+\r
+ Data The value to be set on the software SMI data port\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Function completes successfully\r
+\r
+--*/\r
+{\r
+ UINT16 GPE0BLK_Base;\r
+ UINT32 NewValue;\r
+\r
+ //\r
+ // Get GPE0BLK_Base\r
+ //\r
+ GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);\r
+\r
+ //\r
+ // Enable the APMC SMI\r
+ //\r
+ IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);\r
+\r
+ //\r
+ // Enable SMI globally\r
+ //\r
+ NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
+ NewValue |= SMI_EN;\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);\r
+\r
+\r
+ //\r
+ // Generate the APMC SMI\r
+ //\r
+ IoWrite8 (PcdGet16 (PcdSmmActivationPort), Data);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Generates an SMI using the parameters passed in.\r
+\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param This A pointer to an instance of\r
+ EFI_SMM_CONTROL_PPI\r
+ @param ArgumentBuffer The argument buffer\r
+ @param ArgumentBufferSize The size of the argument buffer\r
+ @param Periodic TRUE to indicate a periodical SMI\r
+ @param ActivationInterval Interval of the periodical SMI\r
+\r
+ @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1\r
+ @retval EFI_SUCCESS SMI generated\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiActivate (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_SMM_CONTROL_PPI *This,\r
+ IN OUT INT8 *ArgumentBuffer OPTIONAL,\r
+ IN OUT UINTN *ArgumentBufferSize OPTIONAL,\r
+ IN BOOLEAN Periodic OPTIONAL,\r
+ IN UINTN ActivationInterval OPTIONAL\r
+ )\r
+{\r
+ INT8 Data;\r
+ EFI_STATUS Status;\r
+ //\r
+ // Periodic SMI not supported.\r
+ //\r
+ if (Periodic) {\r
+ DEBUG ((DEBUG_WARN, "Invalid parameter\n"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (ArgumentBuffer == NULL) {\r
+ Data = 0xFF;\r
+ } else {\r
+ if (ArgumentBufferSize == NULL || *ArgumentBufferSize != 1) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Data = *ArgumentBuffer;\r
+ }\r
+ //\r
+ // Clear any pending the APM SMI\r
+ //\r
+ Status = SmmClear ();\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return SmmTrigger (Data);\r
+}\r
+\r
+/**\r
+ Clears an SMI.\r
+\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+ @param This Pointer to an instance of EFI_SMM_CONTROL_PPI\r
+ @param Periodic TRUE to indicate a periodical SMI\r
+\r
+ @return Return value from SmmClear()\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiDeactivate (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_SMM_CONTROL_PPI *This,\r
+ IN BOOLEAN Periodic OPTIONAL\r
+ )\r
+{\r
+ if (Periodic) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ return SmmClear ();\r
+}\r
+\r
+/**\r
+ This is the constructor for the SMM Control Ppi.\r
+\r
+ This function installs EFI_SMM_CONTROL_PPI.\r
+\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_UNSUPPORTED There's no Intel ICH on this platform\r
+ @return The status returned from InstallPpi().\r
+\r
+--*/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmControlPeiEntry (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+## @file\r
+# Component description file for SmmControlPei module.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SmmControlPei\r
+ FILE_GUID = 60EC7720-512B-4490-9FD1-A336769AE01F\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = SmmControlPeiEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+ SmmControlPei.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ PeimEntryPoint\r
+ DebugLib\r
+ PeiServicesLib\r
+ PcdLib\r
+ IoLib\r
+ PciLib\r
+ QNCAccessLib\r
+\r
+[Ppis]\r
+ gPeiSmmControlPpiGuid # ALWAYS_PRODUCED\r
+\r
+[Pcd]\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort\r
+\r
+[Depex]\r
+ TRUE\r
--- /dev/null
+/** @file\r
+PCH SPI Common Driver implements the SPI Host Controller Compatibility Interface.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "PchSpi.h"\r
+\r
+VOID\r
+FillOutPublicInfoStruct (\r
+ SPI_INSTANCE *SpiInstance\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Fillout SpiInstance->InitInfo;\r
+\r
+Arguments:\r
+\r
+ SpiInstance - Pointer to SpiInstance to initialize\r
+\r
+Returns:\r
+\r
+ NONE\r
+\r
+--*/\r
+{\r
+ UINT8 Index;\r
+\r
+ SpiInstance->InitInfo.InitTable = &SpiInstance->SpiInitTable;\r
+\r
+ //\r
+ // Give invalid index in case operation not supported.\r
+ //\r
+ SpiInstance->InitInfo.JedecIdOpcodeIndex = 0xff;\r
+ SpiInstance->InitInfo.OtherOpcodeIndex = 0xff;\r
+ SpiInstance->InitInfo.WriteStatusOpcodeIndex = 0xff;\r
+ SpiInstance->InitInfo.ProgramOpcodeIndex = 0xff;\r
+ SpiInstance->InitInfo.ReadOpcodeIndex = 0xff;\r
+ SpiInstance->InitInfo.EraseOpcodeIndex = 0xff;\r
+ SpiInstance->InitInfo.ReadStatusOpcodeIndex = 0xff;\r
+ SpiInstance->InitInfo.FullChipEraseOpcodeIndex = 0xff;\r
+ for (Index = 0; Index < SPI_NUM_OPCODE; Index++) {\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationJedecId) {\r
+ SpiInstance->InitInfo.JedecIdOpcodeIndex = Index;\r
+ }\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationOther) {\r
+ SpiInstance->InitInfo.OtherOpcodeIndex = Index;\r
+ }\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationWriteStatus) {\r
+ SpiInstance->InitInfo.WriteStatusOpcodeIndex = Index;\r
+ }\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationProgramData_1_Byte ||\r
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationProgramData_64_Byte) {\r
+ SpiInstance->InitInfo.ProgramOpcodeIndex = Index;\r
+ }\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadData ||\r
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFastRead ||\r
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationDualOutputFastRead) {\r
+ SpiInstance->InitInfo.ReadOpcodeIndex = Index;\r
+ }\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_256_Byte ||\r
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_4K_Byte ||\r
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_8K_Byte ||\r
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationErase_64K_Byte) {\r
+ SpiInstance->InitInfo.EraseOpcodeIndex = Index;\r
+ }\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadStatus) {\r
+ SpiInstance->InitInfo.ReadStatusOpcodeIndex = Index;\r
+ }\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFullChipErase) {\r
+ SpiInstance->InitInfo.FullChipEraseOpcodeIndex = Index;\r
+ }\r
+ }\r
+}\r
+\r
+EFI_STATUS\r
+SpiProtocolConstructor (\r
+ SPI_INSTANCE *SpiInstance\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize an SPI protocol instance.\r
+ The function will assert in debug if PCH RCBA has not been initialized\r
+\r
+Arguments:\r
+\r
+ SpiInstance - Pointer to SpiInstance to initialize\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS The protocol instance was properly initialized\r
+ EFI_UNSUPPORTED The PCH is not supported by this module\r
+\r
+--*/\r
+{\r
+ SpiInstance->InitDone = FALSE; // Indicate NOT READY.\r
+\r
+ //\r
+ // Check if the current PCH is known and supported by this code\r
+ //\r
+ if (!IsQncSupported ()) {\r
+ DEBUG ((DEBUG_ERROR, "PCH SPI Protocol not supported due to no proper QNC LPC found!\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Initialize the SPI protocol instance\r
+ //\r
+ SpiInstance->Signature = PCH_SPI_PRIVATE_DATA_SIGNATURE;\r
+ SpiInstance->Handle = NULL;\r
+ SpiInstance->SpiProtocol.Init = SpiProtocolInit;\r
+ SpiInstance->SpiProtocol.Lock = SpiProtocolLock;\r
+ SpiInstance->SpiProtocol.Execute = SpiProtocolExecute;\r
+ SpiInstance->SpiProtocol.Info = SpiProtocolInfo;\r
+\r
+ //\r
+ // Sanity check to ensure PCH RCBA initialization has occurred previously.\r
+ //\r
+ SpiInstance->PchRootComplexBar = MmioRead32 (\r
+ PciDeviceMmBase (PCI_BUS_NUMBER_QNC,\r
+ PCI_DEVICE_NUMBER_QNC_LPC,\r
+ PCI_FUNCTION_NUMBER_QNC_LPC) + R_QNC_LPC_RCBA\r
+ ) & B_QNC_LPC_RCBA_MASK;\r
+ ASSERT (SpiInstance->PchRootComplexBar != 0);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+UnlockFlashComponents (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ IN UINT8 UnlockCmdOpcodeIndex\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Issue unlock command to disable block protection, this only needs to be done once per SPI power on\r
+\r
+Arguments:\r
+\r
+ This A pointer to "EFI_SPI_PROTOCOL" for issuing commands\r
+ UnlockCmdOpcodeIndex The index of the Unlock command\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS UnLock operation succeed.\r
+ EFI_DEVICE_ERROR Device error, operation failed.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ SPI_INSTANCE *SpiInstance;\r
+ UINT8 SpiStatus;\r
+ UINTN PchRootComplexBar;\r
+\r
+ if (UnlockCmdOpcodeIndex >= SPI_NUM_OPCODE) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;\r
+\r
+ //\r
+ // Issue unlock command to disable block protection, this only needs to be done once per SPI power on\r
+ //\r
+ SpiStatus = 0;\r
+ //\r
+ // Issue unlock command to the flash component 1 at first\r
+ //\r
+ Status = SpiProtocolExecute (\r
+ This,\r
+ UnlockCmdOpcodeIndex,\r
+ SpiInstance->SpiInitTable.PrefixOpcode[0] == PCH_SPI_COMMAND_WRITE_ENABLE ? 0 : 1,\r
+ TRUE,\r
+ TRUE,\r
+ TRUE,\r
+ (UINTN) 0,\r
+ sizeof (SpiStatus),\r
+ &SpiStatus,\r
+ EnumSpiRegionAll\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Unlock flash component 1 fail!\n"));\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SpiProtocolInit (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ IN SPI_INIT_TABLE *InitTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize the host controller to execute SPI command.\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+ InitTable Initialization data to be programmed into the SPI host controller.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Initialization completed.\r
+ EFI_ACCESS_DENIED The SPI static configuration interface has been locked-down.\r
+ EFI_INVALID_PARAMETER Bad input parameters.\r
+ EFI_UNSUPPORTED Can't get Descriptor mode VSCC values\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Index;\r
+ UINT16 OpcodeType;\r
+ SPI_INSTANCE *SpiInstance;\r
+ BOOLEAN MultiPartitionIsSupported;\r
+ UINTN PchRootComplexBar;\r
+ UINT8 SFDPCmdOpcodeIndex;\r
+ UINT8 UnlockCmdOpcodeIndex;\r
+ UINT8 ReadDataCmdOpcodeIndex;\r
+ UINT8 FlashPartId[3];\r
+\r
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;\r
+\r
+ if (InitTable != NULL) {\r
+ //\r
+ // Copy table into SPI driver Private data structure\r
+ //\r
+ CopyMem (\r
+ &SpiInstance->SpiInitTable,\r
+ InitTable,\r
+ sizeof (SPI_INIT_TABLE)\r
+ );\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Check if the SPI interface has been locked-down.\r
+ //\r
+ if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {\r
+ ASSERT_EFI_ERROR (EFI_ACCESS_DENIED);\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ //\r
+ // Clear all the status bits for status regs.\r
+ //\r
+ MmioOr16 (\r
+ (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS),\r
+ (UINT16) ((B_QNC_RCRB_SPIS_CDS | B_QNC_RCRB_SPIS_BAS))\r
+ );\r
+ MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS);\r
+\r
+ //\r
+ // Set the Prefix Opcode registers.\r
+ //\r
+ MmioWrite16 (\r
+ PchRootComplexBar + R_QNC_RCRB_SPIPREOP,\r
+ (SpiInstance->SpiInitTable.PrefixOpcode[1] << 8) | InitTable->PrefixOpcode[0]\r
+ );\r
+ MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIPREOP);\r
+\r
+ //\r
+ // Set Opcode Type Configuration registers.\r
+ //\r
+ for (Index = 0, OpcodeType = 0; Index < SPI_NUM_OPCODE; Index++) {\r
+ switch (SpiInstance->SpiInitTable.OpcodeMenu[Index].Type) {\r
+ case EnumSpiOpcodeRead:\r
+ OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_READ << (Index * 2));\r
+ break;\r
+ case EnumSpiOpcodeWrite:\r
+ OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_ADD_WRITE << (Index * 2));\r
+ break;\r
+ case EnumSpiOpcodeWriteNoAddr:\r
+ OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_WRITE << (Index * 2));\r
+ break;\r
+ default:\r
+ OpcodeType |= (UINT16) (B_QNC_RCRB_SPIOPTYPE_NOADD_READ << (Index * 2));\r
+ break;\r
+ }\r
+ }\r
+ MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE, OpcodeType);\r
+ MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIOPTYPE);\r
+\r
+ //\r
+ // Setup the Opcode Menu registers.\r
+ //\r
+ ReadDataCmdOpcodeIndex = SPI_NUM_OPCODE;\r
+ SFDPCmdOpcodeIndex = SPI_NUM_OPCODE;\r
+ UnlockCmdOpcodeIndex = SPI_NUM_OPCODE;\r
+ for (Index = 0; Index < SPI_NUM_OPCODE; Index++) {\r
+ MmioWrite8 (\r
+ PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index,\r
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Code\r
+ );\r
+ MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + Index);\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationJedecId) {\r
+ Status = SpiProtocolExecute (\r
+ This,\r
+ Index,\r
+ 0,\r
+ TRUE,\r
+ TRUE,\r
+ FALSE,\r
+ (UINTN) 0,\r
+ 3,\r
+ FlashPartId,\r
+ EnumSpiRegionDescriptor\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (FlashPartId[0] != SpiInstance->SpiInitTable.VendorId ||\r
+ FlashPartId[1] != SpiInstance->SpiInitTable.DeviceId0 ||\r
+ FlashPartId[2] != SpiInstance->SpiInitTable.DeviceId1) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationReadData ||\r
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationFastRead ||\r
+ SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationDualOutputFastRead) {\r
+ ReadDataCmdOpcodeIndex = Index;\r
+ }\r
+\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationDiscoveryParameters) {\r
+ SFDPCmdOpcodeIndex = Index;\r
+ }\r
+\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[Index].Operation == EnumSpiOperationWriteStatus) {\r
+ UnlockCmdOpcodeIndex = Index;\r
+ }\r
+ }\r
+\r
+ MultiPartitionIsSupported = FALSE;\r
+\r
+ Status = UnlockFlashComponents (\r
+ This,\r
+ UnlockCmdOpcodeIndex\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Unlock flash components fail!\n"));\r
+ }\r
+\r
+ SpiPhaseInit ();\r
+ FillOutPublicInfoStruct (SpiInstance);\r
+ SpiInstance->InitDone = TRUE;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SpiProtocolLock (\r
+ IN EFI_SPI_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Lock the SPI Static Configuration Interface.\r
+ Once locked, the interface can not be changed and can only be clear by system reset.\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Lock operation succeed.\r
+ EFI_DEVICE_ERROR Device error, operation failed.\r
+ EFI_ACCESS_DENIED The interface has already been locked.\r
+\r
+--*/\r
+{\r
+ SPI_INSTANCE *SpiInstance;\r
+ UINTN PchRootComplexBar;\r
+\r
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;\r
+\r
+ //\r
+ // Check if the SPI interface has been locked-down.\r
+ //\r
+ if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) != 0) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ //\r
+ // Lock-down the configuration interface.\r
+ //\r
+ MmioOr16 ((UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS), (UINT16) (B_QNC_RCRB_SPIS_SCL));\r
+\r
+ //\r
+ // Verify if it's really locked.\r
+ //\r
+ if ((MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS) & B_QNC_RCRB_SPIS_SCL) == 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // Save updated register in S3 Boot script.\r
+ //\r
+ S3BootScriptSaveMemWrite (\r
+ S3BootScriptWidthUint16,\r
+ (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS),\r
+ 1,\r
+ (VOID *) (UINTN) (PchRootComplexBar + R_QNC_RCRB_SPIS)\r
+ );\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SpiProtocolExecute (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ IN UINT8 OpcodeIndex,\r
+ IN UINT8 PrefixOpcodeIndex,\r
+ IN BOOLEAN DataCycle,\r
+ IN BOOLEAN Atomic,\r
+ IN BOOLEAN ShiftOut,\r
+ IN UINTN Address,\r
+ IN UINT32 DataByteCount,\r
+ IN OUT UINT8 *Buffer,\r
+ IN SPI_REGION_TYPE SpiRegionType\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Execute SPI commands from the host controller.\r
+ This function would be called by runtime driver, please do not use any MMIO marco here\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+ OpcodeIndex Index of the command in the OpCode Menu.\r
+ PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.\r
+ DataCycle TRUE if the SPI cycle contains data\r
+ Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.\r
+ ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.\r
+ Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform\r
+ Region, this value specifies the offset from the Region Base; for BIOS Region,\r
+ this value specifies the offset from the start of the BIOS Image. In Non\r
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.\r
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor\r
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is\r
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or\r
+ the flash (in Non Descriptor Mode)\r
+ DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the\r
+ data transfer into multiple operations. This function ensures each operation does\r
+ not cross 256 byte flash address boundary.\r
+ *NOTE: if there is some SPI chip that has a stricter address boundary requirement\r
+ (e.g., its write page size is < 256 byte), then the caller cannot rely on this\r
+ function to cut the data transfer at proper address boundaries, and it's the\r
+ caller's reponsibility to pass in a properly cut DataByteCount parameter.\r
+ Buffer Pointer to caller-allocated buffer containing the dada received or sent during the\r
+ SPI cycle.\r
+ SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,\r
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in\r
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode\r
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative\r
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Command succeed.\r
+ EFI_INVALID_PARAMETER The parameters specified are not valid.\r
+ EFI_UNSUPPORTED Command not supported.\r
+ EFI_DEVICE_ERROR Device error, command aborts abnormally.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 BiosCtlSave;\r
+ UINT32 SmiEnSave;\r
+\r
+ BiosCtlSave = 0;\r
+ SmiEnSave = 0;\r
+\r
+ //\r
+ // Check if the parameters are valid.\r
+ //\r
+ if ((OpcodeIndex >= SPI_NUM_OPCODE) || (PrefixOpcodeIndex >= SPI_NUM_PREFIX_OPCODE)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Make sure it's safe to program the command.\r
+ //\r
+ if (!WaitForSpiCycleComplete (This, FALSE)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Acquire access to the SPI interface is not required any more.\r
+ //\r
+ //\r
+ // Disable SMIs to make sure normal mode flash access is not interrupted by an SMI\r
+ // whose SMI handler accesses flash (e.g. for error logging)\r
+ //\r
+ SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));\r
+\r
+ //\r
+ // Save BIOS Ctrl register\r
+ //\r
+ BiosCtlSave = PciRead16 (\r
+ PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,\r
+ PCI_DEVICE_NUMBER_QNC_LPC,\r
+ PCI_FUNCTION_NUMBER_QNC_LPC,\r
+ R_QNC_LPC_BIOS_CNTL)\r
+ ) & (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);\r
+\r
+ //\r
+ // Enable flash writing\r
+ //\r
+ PciOr16 (\r
+ PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,\r
+ PCI_DEVICE_NUMBER_QNC_LPC,\r
+ PCI_FUNCTION_NUMBER_QNC_LPC,\r
+ R_QNC_LPC_BIOS_CNTL),\r
+ (UINT16) (B_QNC_LPC_BIOS_CNTL_BIOSWE | B_QNC_LPC_BIOS_CNTL_SMM_BWP)\r
+ );\r
+\r
+ //\r
+ // If shifts the data out, disable Prefetching and Caching.\r
+ //\r
+ if (ShiftOut) {\r
+ PciAndThenOr16 (\r
+ PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,\r
+ PCI_DEVICE_NUMBER_QNC_LPC,\r
+ PCI_FUNCTION_NUMBER_QNC_LPC,\r
+ R_QNC_LPC_BIOS_CNTL),\r
+ (UINT16) (~(B_QNC_LPC_BIOS_CNTL_BCD | B_QNC_LPC_BIOS_CNTL_PFE)),\r
+ (UINT16) ((B_QNC_LPC_BIOS_CNTL_BCD))\r
+ );\r
+ }\r
+ //\r
+ // Sends the command to the SPI interface to execute.\r
+ //\r
+ Status = SendSpiCmd (\r
+ This,\r
+ OpcodeIndex,\r
+ PrefixOpcodeIndex,\r
+ DataCycle,\r
+ Atomic,\r
+ ShiftOut,\r
+ Address,\r
+ DataByteCount,\r
+ Buffer,\r
+ SpiRegionType\r
+ );\r
+\r
+ //\r
+ // Restore BIOS Ctrl register\r
+ //\r
+ PciAndThenOr16 (\r
+ PCI_LIB_ADDRESS (PCI_BUS_NUMBER_QNC,\r
+ PCI_DEVICE_NUMBER_QNC_LPC,\r
+ PCI_FUNCTION_NUMBER_QNC_LPC,\r
+ R_QNC_LPC_BIOS_CNTL),\r
+ (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)),\r
+ (UINT16) (BiosCtlSave)\r
+ );\r
+ //\r
+ // Restore SMIs.\r
+ //\r
+ QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, SmiEnSave);\r
+\r
+ return Status;\r
+}\r
+\r
+VOID\r
+SpiOffset2Physical (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ IN UINTN SpiRegionOffset,\r
+ IN SPI_REGION_TYPE SpiRegionType,\r
+ OUT UINTN *HardwareSpiAddress,\r
+ OUT UINTN *BaseAddress,\r
+ OUT UINTN *LimitAddress\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Convert SPI offset to Physical address of SPI hardware\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+ SpiRegionOffset In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform\r
+ Region, this value specifies the offset from the Region Base; for BIOS Region,\r
+ this value specifies the offset from the start of the BIOS Image. In Non\r
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.\r
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor\r
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is\r
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or\r
+ the flash (in Non Descriptor Mode)\r
+ BaseAddress Base Address of the region.\r
+ SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,\r
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in\r
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode\r
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative\r
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).\r
+ HardwareSpiAddress Return absolution SPI address (i.e., Flash Linear Address)\r
+ BaseAddress Return base address of the region type\r
+ LimitAddress Return limit address of the region type\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Command succeed.\r
+\r
+--*/\r
+{\r
+ SPI_INSTANCE *SpiInstance;\r
+ UINTN PchRootComplexBar;\r
+\r
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;\r
+\r
+ if (SpiRegionType == EnumSpiRegionAll) {\r
+ //\r
+ // EnumSpiRegionAll indicates address is relative to flash device (i.e., address is Flash\r
+ // Linear Address)\r
+ //\r
+ *HardwareSpiAddress = SpiRegionOffset;\r
+ } else {\r
+ //\r
+ // Otherwise address is relative to BIOS image\r
+ //\r
+ *HardwareSpiAddress = SpiRegionOffset + SpiInstance->SpiInitTable.BiosStartOffset;\r
+ }\r
+}\r
+\r
+EFI_STATUS\r
+SendSpiCmd (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ IN UINT8 OpcodeIndex,\r
+ IN UINT8 PrefixOpcodeIndex,\r
+ IN BOOLEAN DataCycle,\r
+ IN BOOLEAN Atomic,\r
+ IN BOOLEAN ShiftOut,\r
+ IN UINTN Address,\r
+ IN UINT32 DataByteCount,\r
+ IN OUT UINT8 *Buffer,\r
+ IN SPI_REGION_TYPE SpiRegionType\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function sends the programmed SPI command to the slave device.\r
+\r
+Arguments:\r
+\r
+ OpcodeIndex Index of the command in the OpCode Menu.\r
+ PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.\r
+ DataCycle TRUE if the SPI cycle contains data\r
+ Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.\r
+ ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.\r
+ Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform\r
+ Region, this value specifies the offset from the Region Base; for BIOS Region,\r
+ this value specifies the offset from the start of the BIOS Image. In Non\r
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.\r
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor\r
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is\r
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or\r
+ the flash (in Non Descriptor Mode)\r
+ DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the\r
+ data transfer into multiple operations. This function ensures each operation does\r
+ not cross 256 byte flash address boundary.\r
+ *NOTE: if there is some SPI chip that has a stricter address boundary requirement\r
+ (e.g., its write page size is < 256 byte), then the caller cannot rely on this\r
+ function to cut the data transfer at proper address boundaries, and it's the\r
+ caller's reponsibility to pass in a properly cut DataByteCount parameter.\r
+ Buffer Data received or sent during the SPI cycle.\r
+ SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,\r
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in\r
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode\r
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative\r
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS SPI command completes successfully.\r
+ EFI_DEVICE_ERROR Device error, the command aborts abnormally.\r
+ EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode\r
+ EFI_INVALID_PARAMETER The parameters specified are not valid.\r
+\r
+--*/\r
+{\r
+ UINT32 Index;\r
+ SPI_INSTANCE *SpiInstance;\r
+ UINTN HardwareSpiAddr;\r
+ UINTN SpiBiosSize;\r
+ UINTN BaseAddress;\r
+ UINTN LimitAddress;\r
+ UINT32 SpiDataCount;\r
+ UINT8 OpCode;\r
+ SPI_OPERATION Operation;\r
+ UINTN PchRootComplexBar;\r
+\r
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;\r
+ SpiBiosSize = SpiInstance->SpiInitTable.BiosSize;\r
+ Operation = SpiInstance->SpiInitTable.OpcodeMenu[OpcodeIndex].Operation;\r
+ OpCode = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPIOPMENU + OpcodeIndex);\r
+\r
+ //\r
+ // Check if the value of opcode register is 0 or the BIOS Size of SpiInitTable is 0\r
+ //\r
+ if (OpCode == 0 || SpiBiosSize == 0) {\r
+ ASSERT (FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ SpiOffset2Physical (This, Address, SpiRegionType, &HardwareSpiAddr, &BaseAddress, &LimitAddress);\r
+ //\r
+ // Have direct access to BIOS region in Descriptor mode,\r
+ //\r
+ if (SpiInstance->SpiInitTable.OpcodeMenu[OpcodeIndex].Type == EnumSpiOpcodeRead &&\r
+ SpiRegionType == EnumSpiRegionBios) {\r
+ CopyMem (\r
+ Buffer,\r
+ (UINT8 *) ((HardwareSpiAddr - BaseAddress) + (UINT32) (~(SpiBiosSize - 1))),\r
+ DataByteCount\r
+ );\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // DEBUG((EFI_D_ERROR, "SPIADDR %x, %x, %x, %x\n", Address, HardwareSpiAddr, BaseAddress,\r
+ // LimitAddress));\r
+ //\r
+ if ((DataCycle == FALSE) && (DataByteCount > 0)) {\r
+ DataByteCount = 0;\r
+ }\r
+\r
+ do {\r
+ //\r
+ // Trim at 256 byte boundary per operation,\r
+ // - PCH SPI controller requires trimming at 4KB boundary\r
+ // - Some SPI chips require trimming at 256 byte boundary for write operation\r
+ // - Trimming has limited performance impact as we can read / write atmost 64 byte\r
+ // per operation\r
+ //\r
+ if (HardwareSpiAddr + DataByteCount > ((HardwareSpiAddr + BIT8) &~(BIT8 - 1))) {\r
+ SpiDataCount = (((UINT32) (HardwareSpiAddr) + BIT8) &~(BIT8 - 1)) - (UINT32) (HardwareSpiAddr);\r
+ } else {\r
+ SpiDataCount = DataByteCount;\r
+ }\r
+ //\r
+ // Calculate the number of bytes to shift in/out during the SPI data cycle.\r
+ // Valid settings for the number of bytes duing each data portion of the\r
+ // PCH SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48, 56, 64\r
+ //\r
+ if (SpiDataCount >= 64) {\r
+ SpiDataCount = 64;\r
+ } else if ((SpiDataCount &~0x07) != 0) {\r
+ SpiDataCount = SpiDataCount &~0x07;\r
+ }\r
+ //\r
+ // If shifts data out, load data into the SPI data buffer.\r
+ //\r
+ if (ShiftOut) {\r
+ for (Index = 0; Index < SpiDataCount; Index++) {\r
+ MmioWrite8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index, Buffer[Index]);\r
+ MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index);\r
+ }\r
+ }\r
+\r
+ MmioWrite32 (\r
+ (PchRootComplexBar + R_QNC_RCRB_SPIA),\r
+ (UINT32) (HardwareSpiAddr & B_QNC_RCRB_SPIA_MASK)\r
+ );\r
+ MmioRead32 (PchRootComplexBar + R_QNC_RCRB_SPIA);\r
+\r
+ //\r
+ // Execute the command on the SPI compatible mode\r
+ //\r
+\r
+ //\r
+ // Clear error flags\r
+ //\r
+ MmioOr16 ((PchRootComplexBar + R_QNC_RCRB_SPIS), B_QNC_RCRB_SPIS_BAS);\r
+\r
+ //\r
+ // Initialte the SPI cycle\r
+ //\r
+ if (DataCycle) {\r
+ MmioWrite16 (\r
+ (PchRootComplexBar + R_QNC_RCRB_SPIC),\r
+ ( (UINT16) (B_QNC_RCRB_SPIC_DC) | (UINT16) (((SpiDataCount - 1) << 8) & B_QNC_RCRB_SPIC_DBC) |\r
+ (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) |\r
+ (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) |\r
+ (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) |\r
+ (UINT16) (B_QNC_RCRB_SPIC_SCGO)));\r
+ } else {\r
+ MmioWrite16 (\r
+ (PchRootComplexBar + R_QNC_RCRB_SPIC),\r
+ ( (UINT16) ((OpcodeIndex << 4) & B_QNC_RCRB_SPIC_COP) |\r
+ (UINT16) ((PrefixOpcodeIndex << 3) & B_QNC_RCRB_SPIC_SPOP) |\r
+ (UINT16) (Atomic ? B_QNC_RCRB_SPIC_ACS : 0) |\r
+ (UINT16) (B_QNC_RCRB_SPIC_SCGO)));\r
+ }\r
+\r
+ MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIC);\r
+\r
+ //\r
+ // end of command execution\r
+ //\r
+ // Wait the SPI cycle to complete.\r
+ //\r
+ if (!WaitForSpiCycleComplete (This, TRUE)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // If shifts data in, get data from the SPI data buffer.\r
+ //\r
+ if (!ShiftOut) {\r
+ for (Index = 0; Index < SpiDataCount; Index++) {\r
+ Buffer[Index] = MmioRead8 (PchRootComplexBar + R_QNC_RCRB_SPID0 + Index);\r
+ }\r
+ }\r
+\r
+ HardwareSpiAddr += SpiDataCount;\r
+ Buffer += SpiDataCount;\r
+ DataByteCount -= SpiDataCount;\r
+ } while (DataByteCount > 0);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+WaitForSpiCycleComplete (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ IN BOOLEAN ErrorCheck\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Wait execution cycle to complete on the SPI interface. Check both Hardware\r
+ and Software Sequencing status registers\r
+\r
+Arguments:\r
+\r
+ This - The SPI protocol instance\r
+ UseSoftwareSequence - TRUE if this is a Hardware Sequencing operation\r
+ ErrorCheck - TRUE if the SpiCycle needs to do the error check\r
+\r
+Returns:\r
+\r
+ TRUE SPI cycle completed on the interface.\r
+ FALSE Time out while waiting the SPI cycle to complete.\r
+ It's not safe to program the next command on the SPI interface.\r
+\r
+--*/\r
+{\r
+ UINT64 WaitTicks;\r
+ UINT64 WaitCount;\r
+ UINT16 Data16;\r
+ SPI_INSTANCE *SpiInstance;\r
+ UINTN PchRootComplexBar;\r
+\r
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
+ PchRootComplexBar = SpiInstance->PchRootComplexBar;\r
+\r
+ //\r
+ // Convert the wait period allowed into to tick count\r
+ //\r
+ WaitCount = WAIT_TIME / WAIT_PERIOD;\r
+\r
+ //\r
+ // Wait for the SPI cycle to complete.\r
+ //\r
+ for (WaitTicks = 0; WaitTicks < WaitCount; WaitTicks++) {\r
+ Data16 = MmioRead16 (PchRootComplexBar + R_QNC_RCRB_SPIS);\r
+ if ((Data16 & B_QNC_RCRB_SPIS_SCIP) == 0) {\r
+ MmioWrite16 (PchRootComplexBar + R_QNC_RCRB_SPIS, (B_QNC_RCRB_SPIS_BAS | B_QNC_RCRB_SPIS_CDS));\r
+ if ((Data16 & B_QNC_RCRB_SPIS_BAS) && (ErrorCheck == TRUE)) {\r
+ return FALSE;\r
+ } else {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ MicroSecondDelay (WAIT_PERIOD);\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SpiProtocolInfo (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ OUT SPI_INIT_INFO **InitInfoPtr\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Return info about SPI host controller, to help callers usage of Execute\r
+ service.\r
+\r
+ If 0xff is returned as an opcode index in init info struct\r
+ then device does not support the operation.\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+ InitInfoPtr Pointer to init info written to this memory location.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Information returned.\r
+ EFI_INVALID_PARAMETER Invalid parameter.\r
+ EFI_NOT_READY Required resources not setup.\r
+ Others Unexpected error happened.\r
+\r
+--*/\r
+{\r
+ SPI_INSTANCE *SpiInstance;\r
+\r
+ if (This == NULL || InitInfoPtr == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ SpiInstance = SPI_INSTANCE_FROM_SPIPROTOCOL (This);\r
+ if (SpiInstance->Signature != PCH_SPI_PRIVATE_DATA_SIGNATURE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!SpiInstance->InitDone) {\r
+ *InitInfoPtr = NULL;\r
+ return EFI_NOT_READY;\r
+ }\r
+ *InitInfoPtr = &SpiInstance->InitInfo;\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+Header file for the PCH SPI Common Driver.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#ifndef _SPI_COMMON_H_\r
+#define _SPI_COMMON_H_\r
+\r
+#include "Protocol/Spi.h"\r
+#include <Library/PciLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/IntelQNCLib.h>\r
+#include <Library/QNCAccessLib.h>\r
+#include <Uefi/UefiBaseType.h>\r
+\r
+//\r
+// Maximum time allowed while waiting the SPI cycle to complete\r
+// Wait Time = 6 seconds = 6000000 microseconds\r
+// Wait Period = 10 microseconds\r
+//\r
+#define WAIT_TIME 6000000\r
+#define WAIT_PERIOD 10\r
+//\r
+// PCH Required SPI Commands -------- COMMAND SET I ------------\r
+// SPI flash device must support in order to be compatible with PCH\r
+//\r
+#define PCH_SPI_COMMAND_PROGRAM_BYTE 0x02\r
+#define PCH_SPI_COMMAND_READ_DATA 0x03\r
+#define PCH_SPI_COMMAND_WRITE_DISABLE 0x04\r
+#define PCH_SPI_COMMAND_READ_STATUS 0x05\r
+#define PCH_SPI_COMMAND_WRITE_ENABLE 0x06\r
+#define PCH_SPI_COMMAND_FAST_READ 0x0B\r
+#define PCH_SPI_COMMAND_READ_ID 0x9F\r
+#define PCH_SPI_COMMAND_DUAL_FAST_READ 0x3B // Dual Output Fast Read\r
+\r
+//\r
+// Need to support at least one of the following two kinds of size of sector for erasing\r
+//\r
+#define PCH_SPI_COMMAND_4KB_ERASE 0x20\r
+#define PCH_SPI_COMMAND_64KB_ERASE 0xD8\r
+//\r
+// Recommended SPI Commands -------- COMMAND SET II ------------\r
+// SPI flash device best to support\r
+//\r
+#define PCH_SPI_COMMAND_WRITE_STATUS 0x01\r
+#define PCH_SPI_COMMAND_FULL_CHIP_ERASE 0xC7\r
+\r
+//\r
+// Private data structure definitions for the driver\r
+//\r
+#define PCH_SPI_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'S', 'P', 'I')\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EFI_HANDLE Handle;\r
+ EFI_SPI_PROTOCOL SpiProtocol;\r
+ SPI_INIT_TABLE SpiInitTable;\r
+ UINTN PchRootComplexBar;\r
+ BOOLEAN InitDone; // Set to TRUE on SpiProtocolInit SUCCESS.\r
+ SPI_INIT_INFO InitInfo;\r
+} SPI_INSTANCE;\r
+\r
+#define SPI_INSTANCE_FROM_SPIPROTOCOL(a) CR (a, SPI_INSTANCE, SpiProtocol, PCH_SPI_PRIVATE_DATA_SIGNATURE)\r
+\r
+//\r
+// Function prototypes used by the SPI protocol.\r
+//\r
+EFI_STATUS\r
+SpiProtocolConstructor (\r
+ SPI_INSTANCE *SpiInstance\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize an SPI protocol instance.\r
+ The function will assert in debug if PCH RCBA has not been initialized\r
+\r
+Arguments:\r
+\r
+ SpiInstance - Pointer to SpiInstance to initialize\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS The protocol instance was properly initialized\r
+ EFI_UNSUPPORTED The PCH is not supported by this module\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SpiProtocolInit (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ IN SPI_INIT_TABLE *InitTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize the host controller to execute SPI command.\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+ InitTable Initialization data to be programmed into the SPI host controller.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Initialization completed.\r
+ EFI_ACCESS_DENIED The SPI static configuration interface has been locked-down.\r
+ EFI_INVALID_PARAMETER Bad input parameters.\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SpiProtocolLock (\r
+ IN EFI_SPI_PROTOCOL *This\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Lock the SPI Static Configuration Interface.\r
+ Once locked, the interface can not be changed and can only be clear by system reset.\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Lock operation succeed.\r
+ EFI_DEVICE_ERROR Device error, operation failed.\r
+ EFI_ACCESS_DENIED The interface has already been locked.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SpiProtocolExecute (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ IN UINT8 OpcodeIndex,\r
+ IN UINT8 PrefixOpcodeIndex,\r
+ IN BOOLEAN DataCycle,\r
+ IN BOOLEAN Atomic,\r
+ IN BOOLEAN ShiftOut,\r
+ IN UINTN Address,\r
+ IN UINT32 DataByteCount,\r
+ IN OUT UINT8 *Buffer,\r
+ IN SPI_REGION_TYPE SpiRegionType\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Execute SPI commands from the host controller.\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+ OpcodeIndex Index of the command in the OpCode Menu.\r
+ PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.\r
+ DataCycle TRUE if the SPI cycle contains data\r
+ Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.\r
+ ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.\r
+ Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform\r
+ Region, this value specifies the offset from the Region Base; for BIOS Region,\r
+ this value specifies the offset from the start of the BIOS Image. In Non\r
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.\r
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor\r
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is\r
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or\r
+ the flash (in Non Descriptor Mode)\r
+ DataByteCount Number of bytes in the data portion of the SPI cycle.\r
+ Buffer Pointer to caller-allocated buffer containing the dada received or sent during the SPI cycle.\r
+ SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,\r
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in\r
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode\r
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative\r
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Command succeed.\r
+ EFI_INVALID_PARAMETER The parameters specified are not valid.\r
+ EFI_UNSUPPORTED Command not supported.\r
+ EFI_DEVICE_ERROR Device error, command aborts abnormally.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+SendSpiCmd (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ IN UINT8 OpcodeIndex,\r
+ IN UINT8 PrefixOpcodeIndex,\r
+ IN BOOLEAN DataCycle,\r
+ IN BOOLEAN Atomic,\r
+ IN BOOLEAN ShiftOut,\r
+ IN UINTN Address,\r
+ IN UINT32 DataByteCount,\r
+ IN OUT UINT8 *Buffer,\r
+ IN SPI_REGION_TYPE SpiRegionType\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function sends the programmed SPI command to the slave device.\r
+\r
+Arguments:\r
+\r
+ OpcodeIndex Index of the command in the OpCode Menu.\r
+ PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.\r
+ DataCycle TRUE if the SPI cycle contains data\r
+ Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.\r
+ ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.\r
+ Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform\r
+ Region, this value specifies the offset from the Region Base; for BIOS Region,\r
+ this value specifies the offset from the start of the BIOS Image. In Non\r
+ Descriptor Mode, this value specifies the offset from the start of the BIOS Image.\r
+ Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor\r
+ Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is\r
+ supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or\r
+ the flash (in Non Descriptor Mode)\r
+ DataByteCount Number of bytes in the data portion of the SPI cycle. This function may break the\r
+ data transfer into multiple operations. This function ensures each operation does\r
+ not cross 256 byte flash address boundary.\r
+ *NOTE: if there is some SPI chip that has a stricter address boundary requirement\r
+ (e.g., its write page size is < 256 byte), then the caller cannot rely on this\r
+ function to cut the data transfer at proper address boundaries, and it's the\r
+ caller's reponsibility to pass in a properly cut DataByteCount parameter.\r
+ Buffer Data received or sent during the SPI cycle.\r
+ SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,\r
+ EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in\r
+ Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode\r
+ and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative\r
+ to base of the 1st flash device (i.e., it is a Flash Linear Address).\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS SPI command completes successfully.\r
+ EFI_DEVICE_ERROR Device error, the command aborts abnormally.\r
+ EFI_ACCESS_DENIED Some unrecognized command encountered in hardware sequencing mode\r
+ EFI_INVALID_PARAMETER The parameters specified are not valid.\r
+\r
+--*/\r
+;\r
+\r
+BOOLEAN\r
+WaitForSpiCycleComplete (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ IN BOOLEAN ErrorCheck\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Wait execution cycle to complete on the SPI interface. Check both Hardware\r
+ and Software Sequencing status registers\r
+\r
+Arguments:\r
+\r
+ This - The SPI protocol instance\r
+ UseSoftwareSequence - TRUE if this is a Hardware Sequencing operation\r
+ ErrorCheck - TRUE if the SpiCycle needs to do the error check\r
+\r
+Returns:\r
+\r
+ TRUE SPI cycle completed on the interface.\r
+ FALSE Time out while waiting the SPI cycle to complete.\r
+ It's not safe to program the next command on the SPI interface.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SpiProtocolInfo (\r
+ IN EFI_SPI_PROTOCOL *This,\r
+ OUT SPI_INIT_INFO **InitInfoPtr\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Return info about SPI host controller, to help callers usage of Execute\r
+ service.\r
+\r
+ If 0xff is returned as an opcode index in init info struct\r
+ then device does not support the operation.\r
+\r
+Arguments:\r
+\r
+ This Pointer to the EFI_SPI_PROTOCOL instance.\r
+ InitInfoPtr Pointer to init info written to this memory location.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Information returned.\r
+ EFI_INVALID_PARAMETER Invalid parameter.\r
+ EFI_NOT_READY Required resources not setup.\r
+ Others Unexpected error happened.\r
+\r
+--*/\r
+;\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Component description file for the SPI Runtime driver.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+################################################################################\r
+#\r
+# Defines Section - statements that will be processed to create a Makefile.\r
+#\r
+################################################################################\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = PchSpiRuntime\r
+ FILE_GUID = C194C6EA-B68C-4981-B64B-9BD271474B20\r
+ MODULE_TYPE = DXE_RUNTIME_DRIVER\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = InstallPchSpi\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 EBC\r
+################################################################################\r
+#\r
+# Sources Section - list of files that are required for the build to succeed.\r
+#\r
+################################################################################\r
+[Sources]\r
+ RuntimeDxe/PchSpi.h\r
+ RuntimeDxe/PchSpi.c\r
+ Common/SpiCommon.c\r
+ Common/SpiCommon.h\r
+\r
+################################################################################\r
+#\r
+# Package Dependency Section - list of Package files that are required for\r
+# this module.\r
+#\r
+################################################################################\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+################################################################################\r
+#\r
+# Library Class Section - list of Library Classes that are required for\r
+# this module.\r
+#\r
+################################################################################\r
+[LibraryClasses]\r
+ UefiRuntimeServicesTableLib\r
+ UefiRuntimeLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ IntelQNCLib\r
+ QNCAccessLib\r
+ TimerLib\r
+ DxeServicesTableLib\r
+ UefiLib\r
+ DebugLib\r
+ MemoryAllocationLib\r
+ S3BootScriptLib\r
+ PciExpressLib\r
+\r
+################################################################################\r
+#\r
+# Protocol C Name Section - list of Protocol and Protocol Notify C Names\r
+# that this module uses or produces.\r
+#\r
+################################################################################\r
+[Protocols]\r
+ gEfiSpiProtocolGuid\r
+\r
+[Pcd]\r
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioSize\r
+\r
+[Depex]\r
+ TRUE\r
--- /dev/null
+## @file\r
+# Spi smm driver\r
+#\r
+# Component description file for the SPI SMM driver.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = PchSpiSmm\r
+ FILE_GUID = 27F4917B-A707-4aad-9676-26DF168CBF0D\r
+ MODULE_TYPE = DXE_SMM_DRIVER\r
+ VERSION_STRING = 1.0\r
+ PI_SPECIFICATION_VERSION = 0x0001000A\r
+ ENTRY_POINT = InstallPchSpi\r
+\r
+[Sources]\r
+ Smm/PchSpi.h\r
+ Smm/PchSpi.c\r
+ Common/SpiCommon.c\r
+ Common/SpiCommon.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ DebugLib\r
+ IoLib\r
+ IntelQNCLib\r
+ QNCAccessLib\r
+ TimerLib\r
+ S3BootScriptLib\r
+ UefiDriverEntryPoint\r
+ UefiBootServicesTableLib\r
+ BaseLib\r
+ SmmServicesTableLib\r
+\r
+[Protocols]\r
+ gEfiSmmSpiProtocolGuid # PRODUCES\r
+\r
+[Pcd]\r
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress\r
+\r
+[Depex]\r
+ gEfiSmmBase2ProtocolGuid\r
--- /dev/null
+/** @file\r
+PCH SPI Runtime Driver implements the SPI Host Controller Compatibility Interface.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "PchSpi.h"\r
+\r
+extern EFI_GUID gEfiEventVirtualAddressChangeGuid;\r
+\r
+//\r
+// Global variables\r
+//\r
+SPI_INSTANCE *mSpiInstance;\r
+CONST UINT32 mSpiRegister[] = {\r
+ R_QNC_RCRB_SPIS,\r
+ R_QNC_RCRB_SPIPREOP,\r
+ R_QNC_RCRB_SPIOPMENU,\r
+ R_QNC_RCRB_SPIOPMENU + 4\r
+ };\r
+\r
+//\r
+// Function implementations\r
+//\r
+VOID\r
+PchSpiVirtualddressChangeEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Fixup internal data pointers so that the services can be called in virtual mode.\r
+\r
+Arguments:\r
+\r
+ Event The event registered.\r
+ Context Event context. Not used in this event handler.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->PchRootComplexBar));\r
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Init));\r
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Lock));\r
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance->SpiProtocol.Execute));\r
+ gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSpiInstance));\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+InstallPchSpi (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Entry point for the SPI host controller driver.\r
+\r
+Arguments:\r
+\r
+ ImageHandle Image handle of this driver.\r
+ SystemTable Global system service table.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Initialization complete.\r
+ EFI_UNSUPPORTED The chipset is unsupported by this driver.\r
+ EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver.\r
+ EFI_DEVICE_ERROR Device error, driver exits abnormally.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 BaseAddress;\r
+ UINT64 Length;\r
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdMemorySpaceDescriptor;\r
+ UINT64 Attributes;\r
+ EFI_EVENT Event;\r
+\r
+ DEBUG ((DEBUG_INFO, "InstallPchSpi() Start\n"));\r
+\r
+ //\r
+ // Allocate Runtime memory for the SPI protocol instance.\r
+ //\r
+ mSpiInstance = AllocateRuntimeZeroPool (sizeof (SPI_INSTANCE));\r
+ if (mSpiInstance == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Initialize the SPI protocol instance\r
+ //\r
+ Status = SpiProtocolConstructor (mSpiInstance);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Install the EFI_SPI_PROTOCOL interface\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &(mSpiInstance->Handle),\r
+ &gEfiSpiProtocolGuid,\r
+ &(mSpiInstance->SpiProtocol),\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (mSpiInstance);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Set RCBA space in GCD to be RUNTIME so that the range will be supported in\r
+ // virtual address mode in EFI aware OS runtime.\r
+ // It will assert if RCBA Memory Space is not allocated\r
+ // The caller is responsible for the existence and allocation of the RCBA Memory Spaces\r
+ //\r
+ BaseAddress = (EFI_PHYSICAL_ADDRESS) (mSpiInstance->PchRootComplexBar);\r
+ Length = PcdGet64 (PcdRcbaMmioSize);\r
+\r
+ Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdMemorySpaceDescriptor);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Attributes = GcdMemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME;\r
+\r
+ Status = gDS->AddMemorySpace (\r
+ EfiGcdMemoryTypeMemoryMappedIo,\r
+ BaseAddress,\r
+ Length,\r
+ EFI_MEMORY_RUNTIME | EFI_MEMORY_UC\r
+ );\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ Status = gDS->SetMemorySpaceAttributes (\r
+ BaseAddress,\r
+ Length,\r
+ Attributes\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ PchSpiVirtualddressChangeEvent,\r
+ NULL,\r
+ &gEfiEventVirtualAddressChangeGuid,\r
+ &Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DEBUG ((DEBUG_INFO, "InstallPchSpi() End\n"));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+SpiPhaseInit (\r
+ VOID\r
+ )\r
+/*++\r
+Routine Description:\r
+\r
+ This function is a a hook for Spi Dxe phase specific initialization\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ UINTN Index;\r
+\r
+ //\r
+ // Disable SMM BIOS write protect if it's not a SMM protocol\r
+ //\r
+ MmioAnd8 (\r
+ PciDeviceMmBase (PCI_BUS_NUMBER_QNC,\r
+ PCI_DEVICE_NUMBER_QNC_LPC,\r
+ PCI_FUNCTION_NUMBER_QNC_LPC) + R_QNC_LPC_BIOS_CNTL,\r
+ (UINT8) (~B_QNC_LPC_BIOS_CNTL_SMM_BWP)\r
+ );\r
+\r
+ //\r
+ // Save SPI Registers for S3 resume usage\r
+ //\r
+ for (Index = 0; Index < sizeof (mSpiRegister) / sizeof (UINT32); Index++) {\r
+ S3BootScriptSaveMemWrite (\r
+ S3BootScriptWidthUint32,\r
+ (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index]),\r
+ 1,\r
+ (VOID *) (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index])\r
+ );\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+Header file for the PCH SPI Runtime Driver.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PCH_SPI_H_\r
+#define _PCH_SPI_H_\r
+\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiRuntimeLib.h>\r
+#include <Library/S3BootScriptLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Protocol/Spi.h>\r
+#include "SpiCommon.h"\r
+#include <Library/PciExpressLib.h>\r
+#include <IntelQNCRegs.h>\r
+#include <Library/IntelQNCLib.h>\r
+#include <Library/QNCAccessLib.h>\r
+#include <Library/TimerLib.h>\r
+\r
+#define EFI_INTERNAL_POINTER 0x00000004\r
+\r
+\r
+//\r
+// Function prototypes used by the SPI protocol.\r
+//\r
+VOID\r
+PchSpiVirtualddressChangeEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Fixup internal data pointers so that the services can be called in virtual mode.\r
+\r
+Arguments:\r
+\r
+ Event The event registered.\r
+ Context Event context. Not used in this event handler.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+;\r
+\r
+VOID\r
+EFIAPI\r
+SpiPhaseInit (\r
+ VOID\r
+ )\r
+/*++\r
+Routine Description:\r
+\r
+ This function is a hook for Spi Dxe phase specific initialization\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+;\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+PCH SPI SMM Driver implements the SPI Host Controller Compatibility Interface.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+#include "PchSpi.h"\r
+\r
+SPI_INSTANCE *mSpiInstance;\r
+\r
+CONST UINT32 mSpiRegister[] = {\r
+ R_QNC_RCRB_SPIS,\r
+ R_QNC_RCRB_SPIPREOP,\r
+ R_QNC_RCRB_SPIOPMENU,\r
+ R_QNC_RCRB_SPIOPMENU + 4\r
+ };\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+InstallPchSpi (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Entry point for the SPI host controller driver.\r
+\r
+Arguments:\r
+\r
+ ImageHandle Image handle of this driver.\r
+ SystemTable Global system service table.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS Initialization complete.\r
+ EFI_UNSUPPORTED The chipset is unsupported by this driver.\r
+ EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver.\r
+ EFI_DEVICE_ERROR Device error, driver exits abnormally.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Allocate pool for SPI protocol instance\r
+ //\r
+ Status = gSmst->SmmAllocatePool (\r
+ EfiRuntimeServicesData, // MemoryType don't care\r
+ sizeof (SPI_INSTANCE),\r
+ (VOID **) &mSpiInstance\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (mSpiInstance == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ ZeroMem ((VOID *) mSpiInstance, sizeof (SPI_INSTANCE));\r
+ //\r
+ // Initialize the SPI protocol instance\r
+ //\r
+ Status = SpiProtocolConstructor (mSpiInstance);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Install the SMM EFI_SPI_PROTOCOL interface\r
+ //\r
+ Status = gSmst->SmmInstallProtocolInterface (\r
+ &(mSpiInstance->Handle),\r
+ &gEfiSmmSpiProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &(mSpiInstance->SpiProtocol)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gSmst->SmmFreePool (mSpiInstance);\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+SpiPhaseInit (\r
+ VOID\r
+ )\r
+/*++\r
+Routine Description:\r
+\r
+ This function is a a hook for Spi Smm phase specific initialization\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ UINTN Index;\r
+\r
+ //\r
+ // Save SPI Registers for S3 resume usage\r
+ //\r
+ for (Index = 0; Index < sizeof (mSpiRegister) / sizeof (UINT32); Index++) {\r
+ S3BootScriptSaveMemWrite (\r
+ S3BootScriptWidthUint32,\r
+ (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index]),\r
+ 1,\r
+ (VOID *) (UINTN) (mSpiInstance->PchRootComplexBar + mSpiRegister[Index])\r
+ );\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+Header file for the PCH SPI SMM Driver.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PCH_SPI_H_\r
+#define _PCH_SPI_H_\r
+\r
+#include <Library/IoLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/S3BootScriptLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Protocol/Spi.h>\r
+#include "SpiCommon.h"\r
+#include <Library/SmmServicesTableLib.h>\r
+#include <IntelQNCRegs.h>\r
+#include <Library/IntelQNCLib.h>\r
+#include <Library/QNCAccessLib.h>\r
+#include <Library/TimerLib.h>\r
+\r
+VOID\r
+EFIAPI\r
+SpiPhaseInit (\r
+ VOID\r
+ )\r
+/*++\r
+Routine Description:\r
+\r
+ This function is a hook for Spi Smm phase specific initialization\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+;\r
+#endif\r
--- /dev/null
+## @file\r
+# INTEL Quark SoC Module Package Reference Implementations\r
+#\r
+# This Module provides FRAMEWORK reference implementation for INTEL Quark SoC.\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+\r
+################################################################################\r
+#\r
+# Defines Section - statements that will be processed to create a Makefile.\r
+#\r
+################################################################################\r
+\r
+[Defines]\r
+ DEC_SPECIFICATION = 0x00010005\r
+ PACKAGE_NAME = QuarkSocPkg\r
+ PACKAGE_GUID = 28DECF17-6C75-448f-87DC-BDE4BD579919\r
+ PACKAGE_VERSION = 0.1\r
+\r
+\r
+\r
+################################################################################\r
+#\r
+# Include Section - list of Include Paths that are provided by this package.\r
+# Comments are used for Keywords and Module Types.\r
+#\r
+# Supported Module Types:\r
+# SEC PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER BASE\r
+#\r
+################################################################################\r
+[Includes]\r
+ #\r
+ # North Cluster\r
+ #\r
+ QuarkNorthCluster/Include\r
+ QuarkNorthCluster/MemoryInit/Pei\r
+\r
+ #\r
+ # South Cluster\r
+ #\r
+ QuarkSouthCluster/Include\r
+\r
+################################################################################\r
+#\r
+# Library Class Header section - list of Library Class header files that are\r
+# provided by this package.\r
+#\r
+################################################################################\r
+[LibraryClasses]\r
+ #\r
+ # North Cluster\r
+ #\r
+ QNCAccessLib|QuarkNorthCluster/Include/Library/QNCAccessLib.h\r
+ IntelQNCLib|QuarkNorthCluster/Include/Library/IntelQNCLib.h\r
+ IohLib|QuarkSouthCluster/Include/Library/IohLib.h\r
+ I2cLib|QuarkSouthCluster/Include/Library/I2cLib.h\r
+\r
+################################################################################\r
+#\r
+# Global Guid Definition section - list of Global Guid C Name Data Structures\r
+# that are provided by this package.\r
+#\r
+################################################################################\r
+[Guids]\r
+ #\r
+ # North Cluster\r
+ #\r
+ gEfiQuarkNcSocIdTokenSpaceGuid = { 0xca452c6a, 0xdf0c, 0x4dc9, { 0x82, 0xfb, 0xea, 0xe2, 0xab, 0x31, 0x29, 0x46 }}\r
+ gQncS3CodeInLockBoxGuid = { 0x1f18c5b3, 0x29ed, 0x4d9e, {0xa5, 0x4, 0x6d, 0x97, 0x8e, 0x7e, 0xd5, 0x69}}\r
+ gQncS3ContextInLockBoxGuid = { 0xe5769ea9, 0xe706, 0x454b, {0x95, 0x7f, 0xaf, 0xc6, 0xdb, 0x4b, 0x8a, 0xd}}\r
+\r
+ #\r
+ # South Cluster\r
+ #\r
+ gEfiQuarkSCSocIdTokenSpaceGuid = { 0xef251b71, 0xceed, 0x484e, { 0x82, 0xe3, 0x3a, 0x1f, 0x34, 0xf5, 0x12, 0xe2 }}\r
+\r
+################################################################################\r
+#\r
+# Global Ppi Definition section - list of Global Ppi C Name Data Structures\r
+# that are provided by this package.\r
+#\r
+################################################################################\r
+[Ppis]\r
+ #\r
+ # North Cluster\r
+ #\r
+ gQNCMemoryInitPpiGuid = { 0x21ff1fee, 0xd33a, 0x4fce, { 0xa6, 0x5e, 0x95, 0x5e, 0xa3, 0xc4, 0x1f, 0x40}}\r
+\r
+################################################################################\r
+#\r
+# Global Protocols Definition section - list of Global Protocols C Name Data\r
+# Structures that are provided by this package.\r
+#\r
+################################################################################\r
+[Protocols]\r
+ #\r
+ # North Cluster\r
+ #\r
+ gEfiPlatformPolicyProtocolGuid = { 0x2977064F, 0xAB96, 0x4FA9, { 0x85, 0x45, 0xF9, 0xC4, 0x02, 0x51, 0xE0, 0x7F }}\r
+ gEfiSmmIchnDispatch2ProtocolGuid = { 0xadf3a128, 0x416d, 0x4060, { 0x8d, 0xdf, 0x30, 0xa1, 0xd7, 0xaa, 0xb6, 0x99 }}\r
+ gEfiSpiProtocolGuid = { 0x1156efc6, 0xea32, 0x4396, { 0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 }}\r
+ gEfiSmmSpiProtocolGuid = { 0xD9072C35, 0xEB8F, 0x43ad, { 0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 }}\r
+ gEfiQncS3SupportProtocolGuid = { 0xe287d20b, 0xd897, 0x4e1e, { 0xa5, 0xd9, 0x97, 0x77, 0x63, 0x93, 0x6a, 0x4 }}\r
+\r
+ #\r
+ # South Cluster\r
+ #\r
+ gEfiSDHostIoProtocolGuid = {0xb63f8ec7, 0xa9c9, 0x4472, {0xa4, 0xc0, 0x4d, 0x8b, 0xf3, 0x65, 0xcc, 0x51}}\r
+\r
+################################################################################\r
+#\r
+# PCD Declarations section - list of all PCDs Declared by this Package\r
+# Only this package should be providing the\r
+# declaration, other packages should not.\r
+#\r
+################################################################################\r
+\r
+[PcdsFeatureFlag]\r
+ #\r
+ # North Cluster\r
+ #\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed|TRUE|BOOLEAN|0x10000001\r
+\r
+ #\r
+ # South Cluster\r
+ #\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdEhciRecoveryEnabled|FALSE|BOOLEAN|0x10000003\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdI2CFastModeEnabled|FALSE|BOOLEAN|0x10000005\r
+\r
+ #\r
+ # Feature Flag equivalent to linux SDHCI_QUIRK_NO_HISPD_BIT to stop\r
+ # setting of SD HCI hi_spd_en bit in HOST_CTL register.\r
+ #\r
+ # Alway TRUE ie high speed enable bit must never\r
+ # be set so we stay within SD interface Setup/Hold time.\r
+ #\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdSdHciQuirkNoHiSpd|TRUE|BOOLEAN|0x10000004\r
+\r
+[PcdsFixedAtBuild]\r
+ #\r
+ # North Cluster\r
+ #\r
+\r
+ # Values of Io Port Base Address, MMIO base address and space size.\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress|0x1000|UINT16|0x10000200\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoBaseAddress|0x1010|UINT16|0x10000201\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoLVL2|0x1014|UINT16|0x10000202\r
+\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress|0x1080|UINT16|0x10000205\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress|0x1100|UINT16|0x10000206\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress|0x1040|UINT16|0x10000207\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdWdtbaIoBaseAddress|0x1140|UINT16|0x10000209\r
+\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioBaseAddress|0xFED1C000|UINT64|0x1000020B\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicBaseAddress|0xFEC00000|UINT64|0x1000020C\r
+\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicSize|0x1000|UINT64|0x1000020D\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioSize|0x4000|UINT64|0x1000020E\r
+\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciExpressSize|0x02000000|UINT64|0x1000020F\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetBaseAddress|0xFED00000|UINT64|0x10000210\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetSize|0x400|UINT64|0x10000211\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdTSegSize|0x200000|UINT32|0x10000212\r
+\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeIoBase|0x2000|UINT16|0x10000214\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeIoSize|0xE000|UINT16|0x10000215\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory32Base|0x90000000|UINT32|0x1000021B\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory32Size|0x20000000|UINT32|0x1000021C\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory64Base|0xB0000000|UINT64|0x1000021D\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciHostBridgeMemory64Size|0x30000000|UINT64|0x1000021E\r
+\r
+ # Values for programming Interrupt Route Configuration Registers:\r
+ # Indicates which interrupt routing is connected to the INTA/B/C/D pins reported in the\r
+ # "DxIP" register fields. This will be the internal routing, the device interrupt is connected\r
+ # to the interrupt controller.\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent0IR|0x0000|UINT16|0x10000223\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent1IR|0x7654|UINT16|0x10000224\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent2IR|0x0000|UINT16|0x10000225\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkAgent3IR|0x3210|UINT16|0x10000226\r
+\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort|0xb2|UINT16|0x10000232\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort|0xb3|UINT16|0x10000233\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationData|0x55|UINT8|0x10000234\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrNum|0x0|UINT32|0x10000235\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrTable|0x0|UINT64|0x10000236\r
+\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdESramMemorySize|0x00080000|UINT32|0x10000240\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables|0x03|UINT32|0x10000237\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdPcieRootPortConfiguration|{0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00}|VOID*|0x10000239\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQuarkMicrocodeFile |{ 0x8B, 0xEA, 0x5E, 0xD7, 0xD2, 0x23, 0xD4, 0x4E, 0xBC, 0x4F, 0x57, 0x51, 0xD4, 0xA1, 0x8D, 0xCF }|VOID*|0x1000023A\r
+\r
+ #\r
+ # South Cluster\r
+ #\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohI2cMmioBase|0xA001F000|UINT64|0x20000005\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiP2PMemoryBaseAddress|0xA0000000|UINT32|0x20000006\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiQNCUsbControllerMemoryBaseAddress|0xA0010000|UINT32|0x20000007\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioMmioBase|0xA0020000|UINT64|0x20000008\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohMac0MmioBase|0xA0024000|UINT64|0x20000009\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohMac1MmioBase|0xA0028000|UINT64|0x2000000A\r
+\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartBusNumber|0x00|UINT8|0x20000013\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartDevNumber|0x14|UINT8|0x20000014\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartFunctionNumber|0x5|UINT8|0x20000001\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber|0x00|UINT8|0x20000029\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioDevNumber|0x15|UINT8|0x2000002A\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioFunctionNumber|0x2|UINT8|0x2000002B\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBarRegister|0x14|UINT8|0x2000002D\r
+\r
+[PcdsDynamic, PcdsDynamicEx]\r
+ #\r
+ # North Cluster\r
+ #\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxAddress|0|UINT64|0x30000026\r
+ gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxSize|0|UINT64|0x30000027\r
+\r
+ ## Intel(R) Quark(TM) Soc X1000 processor MRC Parameters. Default is for Galileo Gen 2 platform.<BR><BR>\r
+ # @Prompt Intel(R) Quark(TM) Soc X1000 processor MRC Parameters.\r
+ 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\r
+\r
+ #\r
+ # South Cluster\r
+ #\r
+ ## MAC0 address for the Ethernet Controller in Intel(R) Quark(TM) Soc X1000 processor. Default is 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff.<BR><BR>\r
+ # @Prompt Ethernet MAC 0 Address.\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohEthernetMac0|{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}|VOID*|0x50000001\r
+\r
+ ## MAC1 address for the Ethernet Controller in Intel(R) Quark(TM) Soc X1000 processor. Default is 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff.<BR><BR>\r
+ # @Prompt Ethernet MAC 1 Address.\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohEthernetMac1|{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}|VOID*|0x50000002\r
--- /dev/null
+## @file\r
+# INTEL Quark SoC Module Package Reference Implementations\r
+#\r
+# This DSC file is used for Package Level build.\r
+#\r
+# This Module provides FRAMEWORK reference implementation for INTEL Quark SoC.\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+################################################################################\r
+#\r
+# Defines Section - statements that will be processed to create a Makefile.\r
+#\r
+################################################################################\r
+[Defines]\r
+ PLATFORM_NAME = QuarkSocPkg\r
+ PLATFORM_GUID = 5F9864F4-EAFB-4ded-A41A-CA501EE50502\r
+ PLATFORM_VERSION = 0.1\r
+ DSC_SPECIFICATION = 0x00010005\r
+ OUTPUT_DIRECTORY = Build/QuarkSocPkg\r
+ SUPPORTED_ARCHITECTURES = IA32|X64\r
+ BUILD_TARGETS = DEBUG|RELEASE\r
+ SKUID_IDENTIFIER = DEFAULT\r
+\r
+################################################################################\r
+#\r
+# SKU Identification section - list of all SKU IDs supported by this\r
+# Platform.\r
+#\r
+################################################################################\r
+[SkuIds]\r
+ 0|DEFAULT # The entry: 0|DEFAULT is reserved and always required.\r
+\r
+################################################################################\r
+#\r
+# Library Class section - list of all Library Classes needed by this Platform.\r
+#\r
+################################################################################\r
+[LibraryClasses]\r
+ #\r
+ # Entry point\r
+ #\r
+ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf\r
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf\r
+ #\r
+ # Basic\r
+ #\r
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf\r
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLibRepStr/BaseMemoryLibRepStr.inf\r
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf\r
+ CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf\r
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf\r
+ PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf\r
+ PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf\r
+ PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf\r
+ CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf\r
+ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf\r
+!if $(CFG_SOURCE_DEBUG) == 1\r
+ PeCoffExtraActionLib|SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLibDebug.inf\r
+!else\r
+ PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf\r
+!endif\r
+ #\r
+ # UEFI & PI\r
+ #\r
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf\r
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf\r
+ UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf\r
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf\r
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf\r
+ PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLibIdt/PeiServicesTablePointerLibIdt.inf\r
+ PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf\r
+ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf\r
+ DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf\r
+ UefiCpuLib|UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf\r
+ #\r
+ # Framework\r
+ #\r
+ S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf\r
+ S3IoLib|MdePkg/Library/BaseS3IoLib/BaseS3IoLib.inf\r
+ S3PciLib|MdePkg/Library/BaseS3PciLib/BaseS3PciLib.inf\r
+ #\r
+ # Generic Modules\r
+ #\r
+ OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf\r
+\r
+ #\r
+ # CPU\r
+ #\r
+ MtrrLib|QuarkSocPkg/QuarkNorthCluster/Library/MtrrLib/MtrrLib.inf\r
+ #\r
+ # Quark North Cluster\r
+ #\r
+ SmmLib|QuarkSocPkg/QuarkNorthCluster/Library/QNCSmmLib/QNCSmmLib.inf\r
+ SmbusLib|QuarkSocPkg/QuarkNorthCluster/Library/SmbusLib/SmbusLib.inf\r
+ TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.inf\r
+ ResetSystemLib|QuarkSocPkg/QuarkNorthCluster/Library/ResetSystemLib/ResetSystemLib.inf\r
+ IntelQNCLib|QuarkSocPkg/QuarkNorthCluster/Library/IntelQNCLib/IntelQNCLib.inf\r
+ QNCAccessLib|QuarkSocPkg/QuarkNorthCluster/Library/QNCAccessLib/QNCAccessLib.inf\r
+ #\r
+ # Quark South Cluster\r
+ #\r
+ IohLib|QuarkSocPkg/QuarkSouthCluster/Library/IohLib/IohLib.inf\r
+ SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf\r
+ PlatformHookLib|MdeModulePkg/Library/BasePlatformHookLibNull/BasePlatformHookLibNull.inf\r
+ #\r
+ # Misc\r
+ #\r
+ DebugLib|IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf\r
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf\r
+ PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf\r
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf\r
+!if $(CFG_SOURCE_DEBUG) == TRUE\r
+ DebugCommunicationLib|SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.inf\r
+!else\r
+ DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf\r
+!endif\r
+\r
+[LibraryClasses.IA32.PEIM,LibraryClasses.IA32.PEI_CORE]\r
+ #\r
+ # SEC and PEI phase common\r
+ #\r
+ PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf\r
+ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
+ MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf\r
+ ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf\r
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxPeiLib.inf\r
+ PerformanceLib|MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.inf\r
+!if $(CFG_SOURCE_DEBUG) == TRUE\r
+ DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgentLib.inf\r
+!endif\r
+ TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf\r
+\r
+[LibraryClasses.IA32.SEC]\r
+ #\r
+ # SEC specific phase\r
+ #\r
+ ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf\r
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf\r
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf\r
+ TimerLib|PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf\r
+\r
+[LibraryClasses.IA32]\r
+ #\r
+ # DXE phase common\r
+ #\r
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf\r
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf\r
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf\r
+ ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf\r
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf\r
+!if $(CFG_SOURCE_DEBUG) == 1\r
+ DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.inf\r
+!endif\r
+\r
+[LibraryClasses.IA32.DXE_SMM_DRIVER]\r
+ SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf\r
+ ReportStatusCodeLib|MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf\r
+ MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf\r
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxSmmLib.inf\r
+!if $(CFG_SOURCE_DEBUG) == TRUE\r
+ DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/SmmDebugAgentLib.inf\r
+!endif\r
+\r
+[LibraryClasses.IA32.SMM_CORE]\r
+ ReportStatusCodeLib|MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf\r
+\r
+[LibraryClasses.IA32.DXE_RUNTIME_DRIVER]\r
+ ReportStatusCodeLib|MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf\r
+\r
+[LibraryClasses.IA32.UEFI_DRIVER,LibraryClasses.IA32.UEFI_APPLICATION]\r
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf\r
+\r
+################################################################################\r
+#\r
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform\r
+#\r
+################################################################################\r
+\r
+[PcdsFixedAtBuild]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialLineControl|0x03\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialFifoControl|0x07\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialDetectCable|FALSE\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|44236800\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0x14, 0x05, 0x84, 0x00, 0xFF}\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride|4\r
+\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBusNumber |0\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciDeviceNumber |31\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciFunctionNumber |0\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciEnableRegisterOffset|0x4b\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoBarEnableMask |0x80\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPciBarRegisterOffset |0x48\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiIoPortBaseAddress |0x1000\r
+ gPcAtChipsetPkgTokenSpaceGuid.PcdAcpiPm1TmrOffset |0x0008\r
+\r
+[PcdsFeatureFlag]\r
+\r
+################################################################################\r
+#\r
+# Pcd Dynamic Section - list of all EDK II PCD Entries defined by this Platform\r
+#\r
+################################################################################\r
+\r
+[PcdsDynamicDefault.common.DEFAULT]\r
+\r
+###################################################################################################\r
+#\r
+# Components Section - list of the modules and components that will be processed by compilation\r
+# tools and the EDK II tools to generate PE32/PE32+/Coff image files.\r
+#\r
+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed\r
+# into firmware volume images. This section is just a list of modules to compile from\r
+# source into UEFI-compliant binaries.\r
+# It is the FDF file that contains information on combining binary files into firmware\r
+# volume images, whose concept is beyond UEFI and is described in PI specification.\r
+# Binary modules do not need to be listed in this section, as they should be\r
+# specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),\r
+# Logo (Logo.bmp), and etc.\r
+# There may also be modules listed in this section that are not required in the FDF file,\r
+# When a module listed here is excluded from FDF file, then UEFI-compliant binary will be\r
+# generated for it, but the binary will not be put into any firmware volume.\r
+#\r
+###################################################################################################\r
+\r
+[Components]\r
+ QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf\r
+ QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmAccessPei/SmmAccessPei.inf\r
+ QuarkSocPkg/QuarkNorthCluster/Smm/Pei/SmmControlPei/SmmControlPei.inf\r
+ QuarkSocPkg/QuarkNorthCluster/QNCInit/Dxe/QNCInitDxe.inf\r
+ QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmAccessDxe/SmmAccess.inf\r
+ QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiRuntime.inf {\r
+ <LibraryClasses>\r
+ PciExpressLib|MdePkg/Library/DxeRuntimePciExpressLib/DxeRuntimePciExpressLib.inf\r
+ }\r
+ QuarkSocPkg/QuarkNorthCluster/Spi/PchSpiSmm.inf\r
+ QuarkSocPkg/QuarkNorthCluster/S3Support/Dxe/QncS3Support.inf {\r
+ <LibraryClasses>\r
+ DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf\r
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf\r
+ }\r
+ QuarkSocPkg/QuarkNorthCluster/Smm/Dxe/SmmControlDxe/SmmControlDxe.inf\r
+ QuarkSocPkg/QuarkNorthCluster/Smm/DxeSmm/QncSmmDispatcher/QNCSmmDispatcher.inf\r
+\r
+ QuarkSocPkg/QuarkSouthCluster/Usb/Common/Pei/UsbPei.inf\r
+ QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhciPei.inf\r
+ QuarkSocPkg/QuarkSouthCluster/IohInit/Dxe/IohInitDxe.inf\r
+ QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Dxe/OhciDxe.inf\r
+ QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDControllerDxe.inf\r
+ QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDMediaDeviceDxe/SDMediaDeviceDxe.inf\r
--- /dev/null
+/** @file\r
+\r
+Header file for chipset CE-AT spec.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _CE_ATA_H\r
+#define _CE_ATA_H\r
+\r
+#pragma pack(1)\r
+\r
+\r
+#define DATA_UNIT_SIZE 512\r
+\r
+\r
+#define CMD60 60\r
+#define CMD61 61\r
+\r
+\r
+#define RW_MULTIPLE_REGISTER CMD60\r
+#define RW_MULTIPLE_BLOCK CMD61\r
+\r
+\r
+#define CE_ATA_SIG_CE 0xCE\r
+#define CE_ATA_SIG_AA 0xAA\r
+\r
+\r
+#define Reg_Features_Exp 01\r
+#define Reg_SectorCount_Exp 02\r
+#define Reg_LBALow_Exp 03\r
+#define Reg_LBAMid_Exp 04\r
+#define Reg_LBAHigh_Exp 05\r
+#define Reg_Control 06\r
+#define Reg_Features_Error 09\r
+#define Reg_SectorCount 10\r
+#define Reg_LBALow 11\r
+#define Reg_LBAMid 12\r
+#define Reg_LBAHigh 13\r
+#define Reg_Device_Head 14\r
+#define Reg_Command_Status 15\r
+\r
+#define Reg_scrTempC 0x80\r
+#define Reg_scrTempMaxP 0x84\r
+#define Reg_scrTempMinP 0x88\r
+#define Reg_scrStatus 0x8C\r
+#define Reg_scrReallocsA 0x90\r
+#define Reg_scrERetractsA 0x94\r
+#define Reg_scrCapabilities 0x98\r
+#define Reg_scrControl 0xC0\r
+\r
+\r
+\r
+typedef struct {\r
+ UINT8 Reserved0;\r
+ UINT8 Features_Exp;\r
+ UINT8 SectorCount_Exp;\r
+ UINT8 LBALow_Exp;\r
+ UINT8 LBAMid_Exp;\r
+ UINT8 LBAHigh_Exp;\r
+ UINT8 Control;\r
+ UINT8 Reserved1[2];\r
+ UINT8 Features_Error;\r
+ UINT8 SectorCount;\r
+ UINT8 LBALow;\r
+ UINT8 LBAMid;\r
+ UINT8 LBAHigh;\r
+ UINT8 Device_Head;\r
+ UINT8 Command_Status;\r
+}TASK_FILE;\r
+\r
+\r
+//\r
+//Reduced ATA command set\r
+//\r
+#define IDENTIFY_DEVICE 0xEC\r
+#define READ_DMA_EXT 0x25\r
+#define WRITE_DMA_EXT 0x35\r
+#define STANDBY_IMMEDIATE 0xE0\r
+#define FLUSH_CACHE_EXT 0xEA\r
+\r
+\r
+\r
+typedef struct {\r
+ UINT16 Reserved0[10];\r
+ UINT16 SerialNumber[10];\r
+ UINT16 Reserved1[3];\r
+ UINT16 FirmwareRevision[4];\r
+ UINT16 ModelNumber[20];\r
+ UINT16 Reserved2[33];\r
+ UINT16 MajorVersion;\r
+ UINT16 Reserved3[19];\r
+ UINT16 MaximumLBA[4];\r
+ UINT16 Reserved4[2];\r
+ UINT16 Sectorsize;\r
+ UINT16 Reserved5;\r
+ UINT16 DeviceGUID[4];\r
+ UINT16 Reserved6[94];\r
+ UINT16 Features;\r
+ UINT16 MaxWritesPerAddress;\r
+ UINT16 Reserved7[47];\r
+ UINT16 IntegrityWord;\r
+}IDENTIFY_DEVICE_DATA;\r
+\r
+\r
+\r
+\r
+\r
+#pragma pack()\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Include file for I2C DXE Driver register definitions (PCIe config. space and memory space).\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _I2C_REGS_H_\r
+#define _I2C_REGS_H_\r
+\r
+\r
+//----------------------------------------------------------------------------\r
+/// I2C Device Address\r
+//----------------------------------------------------------------------------\r
+typedef struct {\r
+ ///\r
+ /// The I2C hardware address to which the I2C device is preassigned or allocated.\r
+ ///\r
+ UINTN I2CDeviceAddress : 10;\r
+} EFI_I2C_DEVICE_ADDRESS;\r
+\r
+//----------------------------------------------------------------------------\r
+/// I2C Addressing Mode (7-bit or 10 bit)\r
+//----------------------------------------------------------------------------\r
+typedef enum _EFI_I2C_ADDR_MODE {\r
+ EfiI2CSevenBitAddrMode,\r
+ EfiI2CTenBitAddrMode,\r
+} EFI_I2C_ADDR_MODE;\r
+\r
+\r
+//----------------------------------------------------------------------------\r
+// I2C Controller B:D:F\r
+//----------------------------------------------------------------------------\r
+#define I2C_Bus 0x00\r
+#define I2C_Device 0x15\r
+#define I2C_Func 0x02\r
+\r
+//----------------------------------------------------------------------------\r
+// Memory Mapped Registers\r
+//----------------------------------------------------------------------------\r
+#define I2C_REG_CON 0x00 // Control Register\r
+#define B_I2C_REG_CON_SPEED (BIT2+BIT1) // standard mode (01) or fast mode (10)\r
+#define B_I2C_REG_CON_10BITADD_MASTER (BIT4) // 7-bit addressing (0) or 10-bit addressing (1)\r
+#define I2C_REG_TAR 0x04 // Master Target Address Register\r
+#define B_I2C_REG_TAR (BIT9+BIT8+BIT7+BIT6+BIT5+BIT4+BIT3+BIT2+BIT1+BIT0) // Master Target Address bits\r
+#define I2C_REG_DATA_CMD 0x10 // Data Buffer and Command Register\r
+#define B_I2C_REG_DATA_CMD_RW (BIT8) // Data Buffer and Command Register Read/Write bit\r
+#define B_I2C_REG_DATA_CMD_STOP (BIT9) // Data Buffer and Command Register STOP bit\r
+#define B_I2C_REG_DATA_CMD_RESTART (BIT10) // Data Buffer and Command Register RESTART bit\r
+#define I2C_REG_SS_SCL_HCNT 0x14 // Standard Speed Clock SCL High Count Register\r
+#define I2C_REG_SS_SCL_LCNT 0x18 // Standard Speed Clock SCL Low Count Register\r
+#define I2C_REG_FS_SCL_HCNT 0x1C // Fast Speed Clock SCL High Count Register\r
+#define I2C_REG_FS_SCL_LCNT 0x20 // Fast Speed Clock SCL Low Count Register\r
+#define I2C_REG_INTR_STAT 0x2C // Interrupt Status Register\r
+#define B_I2C_REG_INTR_STAT_STOP_DET (BIT9) // Interrupt Status Register STOP_DET signal status\r
+#define I2C_REG_INTR_MASK 0x30 // Interrupt Status Mask Register\r
+#define I2C_REG_RAW_INTR_STAT 0x34 // Raw Interrupt Status Register\r
+#define I2C_REG_RAW_INTR_STAT_STOP_DET (BIT9) // Raw Interrupt Status Register STOP_DET signal status.\r
+#define I2C_REG_RAW_INTR_STAT_TX_ABRT (BIT6) // Raw Interrupt Status Register TX Abort status.\r
+#define I2C_REG_RAW_INTR_STAT_TX_OVER (BIT3) // Raw Interrupt Status Register TX Overflow signal status.\r
+#define I2C_REG_RAW_INTR_STAT_RX_OVER (BIT1) // Raw Interrupt Status Register RX Overflow signal status.\r
+#define I2C_REG_RAW_INTR_STAT_RX_UNDER (BIT0) // Raw Interrupt Status Register RX Underflow signal status.\r
+#define I2C_REG_RX_TL 0x38 // Receive FIFO Threshold Level Register\r
+#define I2C_REG_TX_TL 0x3C // Transmit FIFO Threshold Level Register\r
+#define I2C_REG_CLR_INT 0x40 // Clear Combined and Individual Interrupt Register\r
+#define I2C_REG_CLR_RX_UNDER 0x44 // Clear RX Under Interrupt Register\r
+#define I2C_REG_CLR_RX_OVER 0x48 // Clear RX Over Interrupt Register\r
+#define I2C_REG_CLR_TX_OVER 0x4C // Clear TX Over Interrupt Register\r
+#define I2C_REG_CLR_RD_REQ 0x50 // Clear RD REQ Interrupt Register\r
+#define I2C_REG_CLR_TX_ABRT 0x54 // Clear TX ABRT Interrupt Register\r
+#define I2C_REG_CLR_ACTIVITY 0x5C // Clear Activity Interrupt Register\r
+#define I2C_REG_CLR_STOP_DET 0x60 // Clear STOP DET Interrupt Register\r
+#define B_I2C_REG_CLR_STOP_DET (BIT0) // Clear STOP DET Interrupt Register\r
+#define I2C_REG_CLR_START_DET 0x64 // Clear START DET Interrupt Register\r
+#define B_I2C_REG_CLR_START_DET (BIT0) // Clear START DET Interrupt Register\r
+#define I2C_REG_ENABLE 0x6C // Enable Register\r
+#define B_I2C_REG_ENABLE (BIT0) // Enable (1) or disable (0) I2C Controller\r
+#define I2C_REG_STATUS 0x70 // Status Register\r
+#define I2C_REG_TXFLR 0x74 // Transmit FIFO Level Register\r
+#define B_I2C_REG_TXFLR (BIT3+BIT2+BIT1+BIT0) // Transmit FIFO Level Register bits\r
+#define I2C_REG_RXFLR 0x78 // Receive FIFO Level Register\r
+#define B_I2C_REG_RXFLR (BIT3+BIT2+BIT1+BIT0) // Receive FIFO Level Register bits\r
+#define I2C_REG_SDA_HOLD 0x7C // SDA HOLD Register\r
+#define I2C_REG_TX_ABRT_SOURCE 0x80 // Transmit Abort Source Register\r
+#define I2C_REG_ENABLE_STATUS 0x9C // Enable Status Register\r
+#define I2C_REG_FS_SPKLEN 0xA0 // SS and FS Spike Suppression Limit Register\r
+\r
+//\r
+// Features.\r
+//\r
+#define I2C_FIFO_SIZE 16\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Header file for QuarkSCSocId Ioh.\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+#ifndef _IOH_H_\r
+#define _IOH_H_\r
+\r
+#ifndef BIT0\r
+#define BIT0 0x01\r
+#define BIT1 0x02\r
+#define BIT2 0x04\r
+#define BIT3 0x08\r
+#define BIT4 0x10\r
+#define BIT5 0x20\r
+#define BIT6 0x40\r
+#define BIT7 0x80\r
+#define BIT8 0x100\r
+#define BIT9 0x200\r
+#define BIT00 0x00000001\r
+#define BIT01 0x00000002\r
+#define BIT02 0x00000004\r
+#define BIT03 0x00000008\r
+#define BIT04 0x00000010\r
+#define BIT05 0x00000020\r
+#define BIT06 0x00000040\r
+#define BIT07 0x00000080\r
+#define BIT08 0x00000100\r
+#define BIT09 0x00000200\r
+#define BIT10 0x00000400\r
+#define BIT11 0x00000800\r
+#define BIT12 0x00001000\r
+#define BIT13 0x00002000\r
+#define BIT14 0x00004000\r
+#define BIT15 0x00008000\r
+#define BIT16 0x00010000\r
+#define BIT17 0x00020000\r
+#define BIT18 0x00040000\r
+#define BIT19 0x00080000\r
+#define BIT20 0x00100000\r
+#define BIT21 0x00200000\r
+#define BIT22 0x00400000\r
+#define BIT23 0x00800000\r
+#define BIT24 0x01000000\r
+#define BIT25 0x02000000\r
+#define BIT26 0x04000000\r
+#define BIT27 0x08000000\r
+#define BIT28 0x10000000\r
+#define BIT29 0x20000000\r
+#define BIT30 0x40000000\r
+#define BIT31 0x80000000\r
+#endif\r
+\r
+#define IOH_PCI_CFG_ADDRESS(bus,dev,func,reg) \\r
+ ((UINT32) ( (((UINTN)bus) << 24) + (((UINTN)dev) << 16) + \\r
+ (((UINTN)func) << 8) + ((UINTN)reg) ))& 0x00000000ffffffff\r
+\r
+//----------------------------------------------------------------------------\r
+\r
+#define INTEL_VENDOR_ID 0x8086 // Intel Vendor ID\r
+\r
+//----------------------------------------------------------------------------\r
+// Pci Configuration Map Register Offsets\r
+//----------------------------------------------------------------------------\r
+#define PCI_REG_VID 0x00 // Vendor ID Register\r
+#define PCI_REG_DID 0x02 // Device ID Register\r
+#define PCI_REG_PCICMD 0x04 // PCI Command Register\r
+#define PCI_REG_PCISTS 0x06 // PCI Status Register\r
+#define PCI_REG_RID 0x08 // PCI Revision ID Register\r
+#define PCI_REG_PI 0x09 // Programming Interface\r
+#define PCI_REG_SCC 0x0a // Sub Class Code Register\r
+#define PCI_REG_BCC 0x0b // Base Class Code Register\r
+#define PCI_REG_PMLT 0x0d // Primary Master Latnecy Timer\r
+#define PCI_REG_HDR 0x0e // Header Type Register\r
+#define PCI_REG_PBUS 0x18 // Primary Bus Number Register\r
+#define PCI_REG_SBUS 0x19 // Secondary Bus Number Register\r
+#define PCI_REG_SUBUS 0x1a // Subordinate Bus Number Register\r
+#define PCI_REG_SMLT 0x1b // Secondary Master Latnecy Timer\r
+#define PCI_REG_IOBASE 0x1c // I/O base Register\r
+#define PCI_REG_IOLIMIT 0x1d // I/O Limit Register\r
+#define PCI_REG_SECSTATUS 0x1e // Secondary Status Register\r
+#define PCI_REG_MEMBASE 0x20 // Memory Base Register\r
+#define PCI_REG_MEMLIMIT 0x22 // Memory Limit Register\r
+#define PCI_REG_PRE_MEMBASE 0x24 // Prefretchable memory Base register\r
+#define PCI_REG_PRE_MEMLIMIT 0x26 // Prefretchable memory Limit register\r
+#define PCI_REG_SVID0 0x2c // Subsystem Vendor ID low byte\r
+#define PCI_REG_SVID1 0x2d // Subsystem Vendor ID high byte\r
+#define PCI_REG_SID0 0x2e // Subsystem ID low byte\r
+#define PCI_REG_SID1 0x2f // Subsystem ID high byte\r
+#define PCI_REG_IOBASE_U 0x30 // I/O base Upper Register\r
+#define PCI_REG_IOLIMIT_U 0x32 // I/O Limit Upper Register\r
+#define PCI_REG_INTLINE 0x3c // Interrupt Line Register\r
+#define PCI_REG_BRIDGE_CNTL 0x3e // Bridge Control Register\r
+\r
+//---------------------------------------------------------------------------\r
+// QuarkSCSocId Packet Hub definitions\r
+//---------------------------------------------------------------------------\r
+\r
+#define PCIE_BRIDGE_VID_DID 0x88008086\r
+\r
+//---------------------------------------------------------------------------\r
+// Quark South Cluster definitions.\r
+//---------------------------------------------------------------------------\r
+\r
+#define IOH_BUS 0\r
+#define IOH_PCI_IOSF2AHB_0_DEV_NUM 0x14\r
+#define IOH_PCI_IOSF2AHB_0_MAX_FUNCS 7\r
+#define IOH_PCI_IOSF2AHB_1_DEV_NUM 0x15\r
+#define IOH_PCI_IOSF2AHB_1_MAX_FUNCS 3\r
+\r
+//---------------------------------------------------------------------------\r
+// Quark South Cluster USB definitions.\r
+//---------------------------------------------------------------------------\r
+\r
+#define IOH_USB_BUS_NUMBER IOH_BUS\r
+#define IOH_USB_CONTROLLER_MMIO_RANGE 0x1000\r
+#define IOH_MAX_OHCI_USB_CONTROLLERS 1\r
+#define IOH_MAX_EHCI_USB_CONTROLLERS 1\r
+#define IOH_MAX_USBDEVICE_USB_CONTROLLERS 1\r
+\r
+#define R_IOH_USB_VENDOR_ID 0x00\r
+#define V_IOH_USB_VENDOR_ID INTEL_VENDOR_ID\r
+#define R_IOH_USB_DEVICE_ID 0x02\r
+#define R_IOH_USB_COMMAND 0x04\r
+#define B_IOH_USB_COMMAND_BME BIT2\r
+#define B_IOH_USB_COMMAND_MSE BIT1\r
+#define B_IOH_USB_COMMAND_ISE BIT0\r
+#define R_IOH_USB_MEMBAR 0x10\r
+#define B_IOH_USB_MEMBAR_ADDRESS_MASK 0xFFFFF000 // [31:12].\r
+#define R_IOH_USB_OHCI_HCCABAR 0x18\r
+\r
+//---------------------------------------------------------------------------\r
+// Quark South Cluster OHCI definitions\r
+//---------------------------------------------------------------------------\r
+#define IOH_USB_OHCI_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM\r
+#define IOH_OHCI_FUNCTION_NUMBER 0x04\r
+\r
+//---------------------------------------------------------------------------\r
+// Quark South Cluster EHCI definitions\r
+//---------------------------------------------------------------------------\r
+#define IOH_USB_EHCI_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM\r
+#define IOH_EHCI_FUNCTION_NUMBER 0x03\r
+\r
+//\r
+// EHCI memory mapped registers offset from memory BAR0.\r
+//\r
+#define R_IOH_EHCI_CAPLENGTH 0x00\r
+#define R_IOH_EHCI_INSNREG01 0x94\r
+#define B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_BP (16)\r
+#define B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_MASK (0xff << B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_BP)\r
+#define B_IOH_EHCI_INSNREG01_IN_THRESHOLD_BP (0)\r
+#define B_IOH_EHCI_INSNREG01_IN_THRESHOLD_MASK (0xff << B_IOH_EHCI_INSNREG01_IN_THRESHOLD_BP)\r
+\r
+//\r
+// EHCI memory mapped registers offset from memory BAR0 + Cap length value.\r
+//\r
+#define R_IOH_EHCI_CONFIGFLAGS 0x40\r
+\r
+//---------------------------------------------------------------------------\r
+// Quark South Cluster USB Device definitions\r
+//---------------------------------------------------------------------------\r
+#define IOH_USBDEVICE_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM\r
+#define IOH_USBDEVICE_FUNCTION_NUMBER 0x02\r
+\r
+//\r
+// USB Device memory mapped registers offset from memory BAR0.\r
+//\r
+#define R_IOH_USBDEVICE_D_INTR_UDC_REG 0x40c\r
+#define R_IOH_USBDEVICE_D_INTR_MSK_UDC_REG 0x410\r
+#define B_IOH_USBDEVICE_D_INTR_MSK_UDC_REG_MASK1_MASK 0xff\r
+#define R_IOH_USBDEVICE_EP_INTR_UDC_REG 0x414\r
+#define R_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG 0x418\r
+#define B_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG_OUT_EP_MASK 0x000f0000\r
+#define B_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG_IN_EP_MASK 0x0000000f\r
+\r
+//---------------------------------------------------------------------------\r
+// Quark South Cluster 10/100 Mbps Ethernet Device definitions.\r
+//---------------------------------------------------------------------------\r
+#define IOH_MAC0_BUS_NUMBER IOH_BUS\r
+#define IOH_MAC0_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM\r
+#define IOH_MAC0_FUNCTION_NUMBER 0x06\r
+#define IOH_MAC1_BUS_NUMBER IOH_BUS\r
+#define IOH_MAC1_DEVICE_NUMBER IOH_PCI_IOSF2AHB_0_DEV_NUM\r
+#define IOH_MAC1_FUNCTION_NUMBER 0x07\r
+\r
+//\r
+// MAC Device PCI config registers.\r
+//\r
+#define R_IOH_MAC_DEVICE_ID 0x02\r
+#define V_IOH_MAC_VENDOR_ID INTEL_VENDOR_ID\r
+#define R_IOH_MAC_DEVICE_ID 0x02\r
+#define V_IOH_MAC_DEVICE_ID 0x0937\r
+#define R_IOH_MAC_COMMAND 0x04\r
+#define B_IOH_MAC_COMMAND_BME BIT2\r
+#define B_IOH_MAC_COMMAND_MSE BIT1\r
+#define B_IOH_MAC_COMMAND_ISE BIT0\r
+#define R_IOH_MAC_MEMBAR 0x10\r
+#define B_IOH_MAC_MEMBAR_ADDRESS_MASK 0xFFFFF000\r
+\r
+//\r
+// LAN Device memory mapped registers offset from memory BAR0.\r
+//\r
+#define R_IOH_MAC_GMAC_REG_8 0x20\r
+#define B_IOH_MAC_USERVER_MASK 0x0000FF00\r
+#define B_IOH_MAC_SNPSVER_MASK 0x000000FF\r
+#define R_IOH_MAC_GMAC_REG_16 0x40\r
+#define B_IOH_MAC_ADDRHI_MASK 0x0000FFFF\r
+#define B_IOH_MAC_AE BIT31\r
+#define R_IOH_MAC_GMAC_REG_17 0x44\r
+#define B_IOH_MAC_ADDRLO_MASK 0xFFFFFFFF\r
+\r
+//---------------------------------------------------------------------------\r
+// Quark I2C / GPIO definitions\r
+//---------------------------------------------------------------------------\r
+\r
+#define V_IOH_I2C_GPIO_VENDOR_ID INTEL_VENDOR_ID\r
+#define V_IOH_I2C_GPIO_DEVICE_ID 0x0934\r
+\r
+#define R_IOH_I2C_MEMBAR 0x10\r
+#define B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK 0xFFFFF000 // [31:12].\r
+\r
+#define GPIO_SWPORTA_DR 0x00\r
+#define GPIO_SWPORTA_DDR 0x04\r
+#define GPIO_INTEN 0x30\r
+#define GPIO_INTMASK 0x34\r
+#define GPIO_INTTYPE_LEVEL 0x38\r
+#define GPIO_INT_POLARITY 0x3C\r
+#define GPIO_INTSTATUS 0x40\r
+#define GPIO_RAW_INTSTATUS 0x44\r
+#define GPIO_DEBOUNCE 0x48\r
+#define GPIO_PORTA_EOI 0x4C\r
+#define GPIO_EXT_PORTA 0x50\r
+#define GPIO_EXT_PORTB 0x54\r
+#define GPIO_LS_SYNC 0x60\r
+#define GPIO_CONFIG_REG2 0x70\r
+#define GPIO_CONFIG_REG1 0x74\r
+\r
+//---------------------------------------------------------------------------\r
+// Quark South Cluster UART definitions.\r
+//---------------------------------------------------------------------------\r
+\r
+#define R_IOH_UART_MEMBAR 0x10\r
+#define B_IOH_UART_MEMBAR_ADDRESS_MASK 0xFFFFF000 // [31:12].\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Macros to simplify and abstract the interface to PCI configuration.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+#ifndef _IOH_ACCESS_H_\r
+#define _IOH_ACCESS_H_\r
+\r
+#include "Ioh.h"\r
+#include "IohCommonDefinitions.h"\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+This header file provides common definitions just for MCH using to avoid including extra module's file.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _IOH_COMMON_DEFINITIONS_H_\r
+#define _IOH_COMMON_DEFINITIONS_H_\r
+\r
+//\r
+// PCI CONFIGURATION MAP REGISTER OFFSETS\r
+//\r
+#ifndef PCI_VID\r
+#define PCI_VID 0x0000 // Vendor ID Register\r
+#define PCI_DID 0x0002 // Device ID Register\r
+#define PCI_CMD 0x0004 // PCI Command Register\r
+#define PCI_STS 0x0006 // PCI Status Register\r
+#define PCI_RID 0x0008 // Revision ID Register\r
+#define PCI_IFT 0x0009 // Interface Type\r
+#define PCI_SCC 0x000A // Sub Class Code Register\r
+#define PCI_BCC 0x000B // Base Class Code Register\r
+#define PCI_CLS 0x000C // Cache Line Size\r
+#define PCI_PMLT 0x000D // Primary Master Latency Timer\r
+#define PCI_HDR 0x000E // Header Type Register\r
+#define PCI_BIST 0x000F // Built in Self Test Register\r
+#define PCI_BAR0 0x0010 // Base Address Register 0\r
+#define PCI_BAR1 0x0014 // Base Address Register 1\r
+#define PCI_BAR2 0x0018 // Base Address Register 2\r
+#define PCI_PBUS 0x0018 // Primary Bus Number Register\r
+#define PCI_SBUS 0x0019 // Secondary Bus Number Register\r
+#define PCI_SUBUS 0x001A // Subordinate Bus Number Register\r
+#define PCI_SMLT 0x001B // Secondary Master Latency Timer\r
+#define PCI_BAR3 0x001C // Base Address Register 3\r
+#define PCI_IOBASE 0x001C // I/O base Register\r
+#define PCI_IOLIMIT 0x001D // I/O Limit Register\r
+#define PCI_SECSTATUS 0x001E // Secondary Status Register\r
+#define PCI_BAR4 0x0020 // Base Address Register 4\r
+#define PCI_MEMBASE 0x0020 // Memory Base Register\r
+#define PCI_MEMLIMIT 0x0022 // Memory Limit Register\r
+#define PCI_BAR5 0x0024 // Base Address Register 5\r
+#define PCI_PRE_MEMBASE 0x0024 // Prefetchable memory Base register\r
+#define PCI_PRE_MEMLIMIT 0x0026 // Prefetchable memory Limit register\r
+#define PCI_PRE_MEMBASE_U 0x0028 // Prefetchable memory base upper 32 bits\r
+#define PCI_PRE_MEMLIMIT_U 0x002C // Prefetchable memory limit upper 32 bits\r
+#define PCI_SVID 0x002C // Subsystem Vendor ID\r
+#define PCI_SID 0x002E // Subsystem ID\r
+#define PCI_IOBASE_U 0x0030 // I/O base Upper Register\r
+#define PCI_IOLIMIT_U 0x0032 // I/O Limit Upper Register\r
+#define PCI_CAPP 0x0034 // Capabilities Pointer\r
+#define PCI_EROM 0x0038 // Expansion ROM Base Address\r
+#define PCI_INTLINE 0x003C // Interrupt Line Register\r
+#define PCI_INTPIN 0x003D // Interrupt Pin Register\r
+#define PCI_MAXGNT 0x003E // Max Grant Register\r
+#define PCI_BRIDGE_CNTL 0x003E // Bridge Control Register\r
+#define PCI_MAXLAT 0x003F // Max Latency Register\r
+#endif\r
+//\r
+// Bit Difinitions\r
+//\r
+#ifndef BIT0\r
+#define BIT0 0x0001\r
+#define BIT1 0x0002\r
+#define BIT2 0x0004\r
+#define BIT3 0x0008\r
+#define BIT4 0x0010\r
+#define BIT5 0x0020\r
+#define BIT6 0x0040\r
+#define BIT7 0x0080\r
+#define BIT8 0x0100\r
+#define BIT9 0x0200\r
+#define BIT10 0x0400\r
+#define BIT11 0x0800\r
+#define BIT12 0x1000\r
+#define BIT13 0x2000\r
+#define BIT14 0x4000\r
+#define BIT15 0x8000\r
+#define BIT16 0x00010000\r
+#define BIT17 0x00020000\r
+#define BIT18 0x00040000\r
+#define BIT19 0x00080000\r
+#define BIT20 0x00100000\r
+#define BIT21 0x00200000\r
+#define BIT22 0x00400000\r
+#define BIT23 0x00800000\r
+#define BIT24 0x01000000\r
+#define BIT25 0x02000000\r
+#define BIT26 0x04000000\r
+#define BIT27 0x08000000\r
+#define BIT28 0x10000000\r
+#define BIT29 0x20000000\r
+#define BIT30 0x40000000\r
+#define BIT31 0x80000000\r
+#endif\r
+\r
+\r
+//\r
+// Common Memory mapped Io access macros ------------------------------------------\r
+//\r
+#define IohMmioAddress( BaseAddr, Register ) \\r
+ ( (UINTN)BaseAddr + \\r
+ (UINTN)(Register) \\r
+ )\r
+\r
+//\r
+// UINT64\r
+//\r
+#define IohMmio64Ptr( BaseAddr, Register ) \\r
+ ( (volatile UINT64 *)IohMmioAddress( BaseAddr, Register ) )\r
+\r
+#define IohMmio64( BaseAddr, Register ) \\r
+ *IohMmio64Ptr( BaseAddr, Register )\r
+\r
+#define IohMmio64Or( BaseAddr, Register, OrData ) \\r
+ IohMmio64( BaseAddr, Register ) = \\r
+ (UINT64) ( \\r
+ IohMmio64( BaseAddr, Register ) | \\r
+ (UINT64)(OrData) \\r
+ )\r
+\r
+#define IohMmio64And( BaseAddr, Register, AndData ) \\r
+ IohMmio64( BaseAddr, Register ) = \\r
+ (UINT64) ( \\r
+ IohMmio64( BaseAddr, Register ) & \\r
+ (UINT64)(AndData) \\r
+ )\r
+\r
+#define IohMmio64AndThenOr( BaseAddr, Register, AndData, OrData ) \\r
+ IohMmio64( BaseAddr, Register ) = \\r
+ (UINT64) ( \\r
+ ( IohMmio64( BaseAddr, Register ) & \\r
+ (UINT64)(AndData) \\r
+ ) | \\r
+ (UINT64)(OrData) \\r
+ )\r
+\r
+//\r
+// UINT32\r
+//\r
+#define IohMmio32Ptr( BaseAddr, Register ) \\r
+ ( (volatile UINT32 *)IohMmioAddress( BaseAddr, Register ) )\r
+\r
+#define IohMmio32( BaseAddr, Register ) \\r
+ *IohMmio32Ptr( BaseAddr, Register )\r
+\r
+#define IohMmio32Or( BaseAddr, Register, OrData ) \\r
+ IohMmio32( BaseAddr, Register ) = \\r
+ (UINT32) ( \\r
+ IohMmio32( BaseAddr, Register ) | \\r
+ (UINT32)(OrData) \\r
+ )\r
+\r
+#define IohMmio32And( BaseAddr, Register, AndData ) \\r
+ IohMmio32( BaseAddr, Register ) = \\r
+ (UINT32) ( \\r
+ IohMmio32( BaseAddr, Register ) & \\r
+ (UINT32)(AndData) \\r
+ )\r
+\r
+#define IohMmio32AndThenOr( BaseAddr, Register, AndData, OrData ) \\r
+ IohMmio32( BaseAddr, Register ) = \\r
+ (UINT32) ( \\r
+ ( IohMmio32( BaseAddr, Register ) & \\r
+ (UINT32)(AndData) \\r
+ ) | \\r
+ (UINT32)(OrData) \\r
+ )\r
+//\r
+// UINT16\r
+//\r
+\r
+#define IohMmio16Ptr( BaseAddr, Register ) \\r
+ ( (volatile UINT16 *)IohMmioAddress( BaseAddr, Register ) )\r
+\r
+#define IohMmio16( BaseAddr, Register ) \\r
+ *IohMmio16Ptr( BaseAddr, Register )\r
+\r
+#define IohMmio16Or( BaseAddr, Register, OrData ) \\r
+ IohMmio16( BaseAddr, Register ) = \\r
+ (UINT16) ( \\r
+ IohMmio16( BaseAddr, Register ) | \\r
+ (UINT16)(OrData) \\r
+ )\r
+\r
+#define IohMmio16And( BaseAddr, Register, AndData ) \\r
+ IohMmio16( BaseAddr, Register ) = \\r
+ (UINT16) ( \\r
+ IohMmio16( BaseAddr, Register ) & \\r
+ (UINT16)(AndData) \\r
+ )\r
+\r
+#define IohMmio16AndThenOr( BaseAddr, Register, AndData, OrData ) \\r
+ IohMmio16( BaseAddr, Register ) = \\r
+ (UINT16) ( \\r
+ ( IohMmio16( BaseAddr, Register ) & \\r
+ (UINT16)(AndData) \\r
+ ) | \\r
+ (UINT16)(OrData) \\r
+ )\r
+//\r
+// UINT8\r
+//\r
+#define IohMmio8Ptr( BaseAddr, Register ) \\r
+ ( (volatile UINT8 *)IohMmioAddress( BaseAddr, Register ) )\r
+\r
+#define IohMmio8( BaseAddr, Register ) \\r
+ *IohMmio8Ptr( BaseAddr, Register )\r
+\r
+#define IohMmio8Or( BaseAddr, Register, OrData ) \\r
+ IohMmio8( BaseAddr, Register ) = \\r
+ (UINT8) ( \\r
+ IohMmio8( BaseAddr, Register ) | \\r
+ (UINT8)(OrData) \\r
+ )\r
+\r
+#define IohMmio8And( BaseAddr, Register, AndData ) \\r
+ IohMmio8( BaseAddr, Register ) = \\r
+ (UINT8) ( \\r
+ IohMmio8( BaseAddr, Register ) & \\r
+ (UINT8)(AndData) \\r
+ )\r
+\r
+#define IohMmio8AndThenOr( BaseAddr, Register, AndData, OrData ) \\r
+ IohMmio8( BaseAddr, Register ) = \\r
+ (UINT8) ( \\r
+ ( IohMmio8( BaseAddr, Register ) & \\r
+ (UINT8)(AndData) \\r
+ ) | \\r
+ (UINT8)(OrData) \\r
+ )\r
+\r
+//\r
+// Common Memory mapped Pci access macros ------------------------------------------\r
+//\r
+#define Ioh_PCI_EXPRESS_BASE_ADDRESS 0xE0000000\r
+\r
+\r
+#define IohMmPciAddress( Segment, Bus, Device, Function, Register ) \\r
+ ( (UINTN)Ioh_PCI_EXPRESS_BASE_ADDRESS + \\r
+ (UINTN)(Bus << 20) + \\r
+ (UINTN)(Device << 15) + \\r
+ (UINTN)(Function << 12) + \\r
+ (UINTN)(Register) \\r
+ )\r
+\r
+//\r
+// UINT32\r
+//\r
+#define IohMmPci32Ptr( Segment, Bus, Device, Function, Register ) \\r
+ ( (volatile UINT32 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )\r
+\r
+#define IohMmPci32( Segment, Bus, Device, Function, Register ) \\r
+ *IohMmPci32Ptr( Segment, Bus, Device, Function, Register )\r
+\r
+#define IohMmPci32Or( Segment, Bus, Device, Function, Register, OrData ) \\r
+ IohMmPci32( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT32) ( \\r
+ IohMmPci32( Segment, Bus, Device, Function, Register ) | \\r
+ (UINT32)(OrData) \\r
+ )\r
+\r
+#define IohMmPci32And( Segment, Bus, Device, Function, Register, AndData ) \\r
+ IohMmPci32( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT32) ( \\r
+ IohMmPci32( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT32)(AndData) \\r
+ )\r
+\r
+#define IohMmPci32AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \\r
+ IohMmPci32( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT32) ( \\r
+ ( IohMmPci32( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT32)(AndData) \\r
+ ) | \\r
+ (UINT32)(OrData) \\r
+ )\r
+//\r
+// UINT16\r
+//\r
+#define IohMmPci16Ptr( Segment, Bus, Device, Function, Register ) \\r
+ ( (volatile UINT16 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )\r
+\r
+#define IohMmPci16( Segment, Bus, Device, Function, Register ) \\r
+ *IohMmPci16Ptr( Segment, Bus, Device, Function, Register )\r
+\r
+#define IohMmPci16Or( Segment, Bus, Device, Function, Register, OrData ) \\r
+ IohMmPci16( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT16) ( \\r
+ IohMmPci16( Segment, Bus, Device, Function, Register ) | \\r
+ (UINT16)(OrData) \\r
+ )\r
+\r
+#define IohMmPci16And( Segment, Bus, Device, Function, Register, AndData ) \\r
+ IohMmPci16( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT16) ( \\r
+ IohMmPci16( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT16)(AndData) \\r
+ )\r
+\r
+#define IohMmPci16AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \\r
+ IohMmPci16( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT16) ( \\r
+ ( IohMmPci16( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT16)(AndData) \\r
+ ) | \\r
+ (UINT16)(OrData) \\r
+ )\r
+//\r
+// UINT8\r
+//\r
+#define IohMmPci8Ptr( Segment, Bus, Device, Function, Register ) \\r
+ ( (volatile UINT8 *)IohMmPciAddress( Segment, Bus, Device, Function, Register ) )\r
+\r
+#define IohMmPci8( Segment, Bus, Device, Function, Register ) \\r
+ *IohMmPci8Ptr( Segment, Bus, Device, Function, Register )\r
+\r
+#define IohMmPci8Or( Segment, Bus, Device, Function, Register, OrData ) \\r
+ IohMmPci8( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT8) ( \\r
+ IohMmPci8( Segment, Bus, Device, Function, Register ) | \\r
+ (UINT8)(OrData) \\r
+ )\r
+\r
+#define IohMmPci8And( Segment, Bus, Device, Function, Register, AndData ) \\r
+ IohMmPci8( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT8) ( \\r
+ IohMmPci8( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT8)(AndData) \\r
+ )\r
+\r
+#define IohMmPci8AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \\r
+ IohMmPci8( Segment, Bus, Device, Function, Register ) = \\r
+ (UINT8) ( \\r
+ ( IohMmPci8( Segment, Bus, Device, Function, Register ) & \\r
+ (UINT8)(AndData) \\r
+ ) | \\r
+ (UINT8)(OrData) \\r
+ )\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+Intel I2C library implementation built upon I/O library\r
+\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _I2C_LIB_H_\r
+#define _I2C_LIB_H_\r
+\r
+#include "I2cRegs.h"\r
+\r
+/**\r
+\r
+ The I2cWriteByte() function is a wrapper function for the WriteByte() function.\r
+ Provides a standard way to execute a standard single byte write to an IC2 device\r
+ (without accessing sub-addresses), as defined in the I2C Specification.\r
+\r
+ @param SlaveAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
+\r
+ @param Buffer Contains the value of byte data to execute to the\r
+ I2C slave device.\r
+\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+I2cWriteByte (\r
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
+ IN EFI_I2C_ADDR_MODE AddrMode,\r
+ IN OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+\r
+ The I2cReadByte() function is a wrapper function for the ReadByte() function.\r
+ Provides a standard way to execute a standard single byte read to an I2C device\r
+ (without accessing sub-addresses), as defined in the I2C Specification.\r
+\r
+ @param SlaveAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
+\r
+ @param Buffer Contains the value of byte data read from the\r
+ I2C slave device.\r
+\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+I2cReadByte (\r
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
+ IN EFI_I2C_ADDR_MODE AddrMode,\r
+ IN OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+\r
+ The I2cWriteMultipleByte() function is a wrapper function for the WriteMultipleByte()\r
+ function. Provides a standard way to execute multiple byte writes to an I2C device (e.g. when\r
+ accessing sub-addresses or writing block of data), as defined in the I2C Specification.\r
+\r
+ @param SlaveAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
+\r
+ @param Length No. of bytes to be written.\r
+\r
+ @param Buffer Contains the value of byte to be written to the\r
+ I2C slave device.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_INVALID_PARAMETER This, Length or Buffer pointers are invalid.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+I2cWriteMultipleByte (\r
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
+ IN EFI_I2C_ADDR_MODE AddrMode,\r
+ IN UINTN *Length,\r
+ IN OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+\r
+ The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte\r
+ function. Provides a standard way to execute multiple byte writes to an IC2 device\r
+ (e.g. when accessing sub-addresses or when reading block of data), as defined\r
+ in the I2C Specification (I2C combined write/read protocol).\r
+\r
+ @param SlaveAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
+\r
+ @param WriteLength No. of bytes to be written. In this case data\r
+ written typically contains sub-address or sub-addresses\r
+ in Hi-Lo format, that need to be read (I2C combined\r
+ write/read protocol).\r
+\r
+ @param ReadLength No. of bytes to be read from I2C slave device.\r
+ need to be read.\r
+\r
+ @param Buffer Contains the value of byte data read from the\r
+ I2C slave device.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_INVALID_PARAMETER This, WriteLength, ReadLength or Buffer\r
+ pointers are invalid.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+I2cReadMultipleByte (\r
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
+ IN EFI_I2C_ADDR_MODE AddrMode,\r
+ IN UINTN *WriteLength,\r
+ IN UINTN *ReadLength,\r
+ IN OUT VOID *Buffer\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Library that provides Soc specific library services for SouthCluster devices.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __IOH_LIB_H__\r
+#define __IOH_LIB_H__\r
+\r
+#include "Ioh.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeIohSsvidSsid (\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Func\r
+ );\r
+\r
+VOID\r
+EFIAPI\r
+EnableUsbMemIoBusMaster (\r
+ IN UINT8 UsbBusNumber\r
+ );\r
+\r
+UINT32\r
+EFIAPI\r
+ReadIohGpioValues (\r
+ VOID\r
+ );\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+\r
+Header file for Industry MMC 4.2 spec.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _MMC_H\r
+#define _MMC_H\r
+\r
+#pragma pack(1)\r
+//\r
+//Command definition\r
+//\r
+\r
+#define CMD0 0\r
+#define CMD1 1\r
+#define CMD2 2\r
+#define CMD3 3\r
+#define CMD4 4\r
+#define CMD6 6\r
+#define CMD7 7\r
+#define CMD8 8\r
+#define CMD9 9\r
+#define CMD10 10\r
+#define CMD11 11\r
+#define CMD12 12\r
+#define CMD13 13\r
+#define CMD14 14\r
+#define CMD15 15\r
+#define CMD16 16\r
+#define CMD17 17\r
+#define CMD18 18\r
+#define CMD19 19\r
+#define CMD20 20\r
+#define CMD23 23\r
+#define CMD24 24\r
+#define CMD25 25\r
+#define CMD26 26\r
+#define CMD27 27\r
+#define CMD28 28\r
+#define CMD29 29\r
+#define CMD30 30\r
+#define CMD35 35\r
+#define CMD36 36\r
+#define CMD38 38\r
+#define CMD39 39\r
+#define CMD40 40\r
+#define CMD42 42\r
+#define CMD55 55\r
+#define CMD56 56\r
+\r
+\r
+\r
+#define GO_IDLE_STATE CMD0\r
+#define SEND_OP_COND CMD1\r
+#define ALL_SEND_CID CMD2\r
+#define SET_RELATIVE_ADDR CMD3\r
+#define SET_DSR CMD4\r
+#define SWITCH CMD6\r
+#define SELECT_DESELECT_CARD CMD7\r
+#define SEND_EXT_CSD CMD8\r
+#define SEND_CSD CMD9\r
+#define SEND_CID CMD10\r
+#define READ_DAT_UNTIL_STOP CMD11\r
+#define STOP_TRANSMISSION CMD12\r
+#define SEND_STATUS CMD13\r
+#define BUSTEST_R CMD14\r
+#define GO_INACTIVE_STATE CMD15\r
+#define SET_BLOCKLEN CMD16\r
+#define READ_SINGLE_BLOCK CMD17\r
+#define READ_MULTIPLE_BLOCK CMD18\r
+#define BUSTEST_W CMD19\r
+#define WRITE_DAT_UNTIL_STOP CMD20\r
+#define SET_BLOCK_COUNT CMD23\r
+#define WRITE_BLOCK CMD24\r
+#define WRITE_MULTIPLE_BLOCK CMD25\r
+#define PROGRAM_CID CMD26\r
+#define PROGRAM_CSD CMD27\r
+#define SET_WRITE_PROT CMD28\r
+#define CLR_WRITE_PROT CMD29\r
+#define SEND_WRITE_PROT CMD30\r
+#define ERASE_GROUP_START CMD35\r
+#define ERASE_GROUP_END CMD36\r
+#define ERASE CMD38\r
+#define FAST_IO CMD39\r
+#define GO_IRQ_STATE CMD40\r
+#define LOCK_UNLOCK CMD42\r
+#define APP_CMD CMD55\r
+#define GEN_CMD CMD56\r
+\r
+\r
+#define CMD_INDEX_MASK 0x3F\r
+#define AUTO_CMD12_ENABLE BIT6\r
+#define AUTO_CMD23_ENABLE BIT7\r
+\r
+#define FREQUENCY_OD (400 * 1000)\r
+#define FREQUENCY_MMC_PP (26 * 1000 * 1000)\r
+#define FREQUENCY_MMC_PP_HIGH (52 * 1000 * 1000)\r
+\r
+#define DEFAULT_DSR_VALUE 0x404\r
+\r
+//\r
+//Registers definition\r
+//\r
+\r
+typedef struct {\r
+ UINT32 Reserved0: 7; // 0\r
+ UINT32 V170_V195: 1; // 1.70V - 1.95V\r
+ UINT32 V200_V260: 7; // 2.00V - 2.60V\r
+ UINT32 V270_V360: 9; // 2.70V - 3.60V\r
+ UINT32 Reserved1: 5; // 0\r
+ UINT32 AccessMode: 2; // 00b (byte mode), 10b (sector mode)\r
+ UINT32 Busy: 1; // This bit is set to LOW if the card has not finished the power up routine\r
+}OCR;\r
+\r
+\r
+typedef struct {\r
+ UINT8 NotUsed: 1; // 1\r
+ UINT8 CRC: 7; // CRC7 checksum\r
+ UINT8 MDT; // Manufacturing date\r
+ UINT32 PSN; // Product serial number\r
+ UINT8 PRV; // Product revision\r
+ UINT8 PNM[6]; // Product name\r
+ UINT16 OID; // OEM/Application ID\r
+ UINT8 MID; // Manufacturer ID\r
+}CID;\r
+\r
+\r
+typedef struct {\r
+ UINT8 NotUsed: 1; // 1 [0:0]\r
+ UINT8 CRC: 7; // CRC [7:1]\r
+ UINT8 ECC: 2; // ECC code [9:8]\r
+ UINT8 FILE_FORMAT: 2; // File format [11:10]\r
+ UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12]\r
+ UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13]\r
+ UINT8 COPY: 1; // Copy flag (OTP) [14:14]\r
+ UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15]\r
+ UINT16 CONTENT_PROT_APP: 1; // Content protection application [16:16]\r
+ UINT16 Reserved0: 4; // 0 [20:17]\r
+ UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21]\r
+ UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22]\r
+ UINT16 R2W_FACTOR: 3; // Write speed factor [28:26]\r
+ UINT16 DEFAULT_ECC: 2; // Manufacturer default ECC [30:29]\r
+ UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31]\r
+ UINT32 WP_GRP_SIZE: 5; // Write protect group size [36:32]\r
+ UINT32 ERASE_GRP_MULT: 5; // Erase group size multiplier [41:37]\r
+ UINT32 ERASE_GRP_SIZE: 5; // Erase group size [46:42]\r
+ UINT32 C_SIZE_MULT: 3; // Device size multiplier [49:47]\r
+ UINT32 VDD_W_CURR_MAX: 3; // Max. write current @ VDD max [52:50]\r
+ UINT32 VDD_W_CURR_MIN: 3; // Max. write current @ VDD min [55:53]\r
+ UINT32 VDD_R_CURR_MAX: 3; // Max. read current @ VDD max [58:56]\r
+ UINT32 VDD_R_CURR_MIN: 3; // Max. read current @ VDD min [61:59]\r
+ UINT32 C_SIZELow2: 2;// Device size [73:62]\r
+ UINT32 C_SIZEHigh10: 10;// Device size [73:62]\r
+ UINT32 Reserved1: 2; // 0 [75:74]\r
+ UINT32 DSR_IMP: 1; // DSR implemented [76:76]\r
+ UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77]\r
+ UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78]\r
+ UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79]\r
+ UINT32 READ_BL_LEN: 4; // Max. read data block length [83:80]\r
+ UINT32 CCC: 12;// Card command classes [95:84]\r
+ UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96]\r
+ UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]\r
+ UINT8 TAAC ; // Data read access-time 1 [119:112]\r
+ UINT8 Reserved2: 2; // 0 [121:120]\r
+ UINT8 SPEC_VERS: 4; // System specification version [125:122]\r
+ UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126]\r
+}CSD;\r
+\r
+typedef struct {\r
+ UINT8 Reserved0[181]; // 0 [0:180]\r
+ UINT8 ERASED_MEM_CONT; // Erased Memory Content [181]\r
+ UINT8 Reserved2; // Erased Memory Content [182]\r
+ UINT8 BUS_WIDTH; // Bus Width Mode [183]\r
+ UINT8 Reserved3; // 0 [184]\r
+ UINT8 HS_TIMING; // High Speed Interface Timing [185]\r
+ UINT8 Reserved4; // 0 [186]\r
+ UINT8 POWER_CLASS; // Power Class [187]\r
+ UINT8 Reserved5; // 0 [188]\r
+ UINT8 CMD_SET_REV; // Command Set Revision [189]\r
+ UINT8 Reserved6; // 0 [190]\r
+ UINT8 CMD_SET; // Command Set [191]\r
+ UINT8 EXT_CSD_REV; // Extended CSD Revision [192]\r
+ UINT8 Reserved7; // 0 [193]\r
+ UINT8 CSD_STRUCTURE; // CSD Structure Version [194]\r
+ UINT8 Reserved8; // 0 [195]\r
+ UINT8 CARD_TYPE; // Card Type [196]\r
+ UINT8 Reserved9[3]; // 0 [199:197]\r
+ UINT8 PWR_CL_52_195; // Power Class for 52MHz @ 1.95V [200]\r
+ UINT8 PWR_CL_26_195; // Power Class for 26MHz @ 1.95V [201]\r
+ UINT8 PWR_CL_52_360; // Power Class for 52MHz @ 3.6V [202]\r
+ UINT8 PWR_CL_26_360; // Power Class for 26MHz @ 3.6V [203]\r
+ UINT8 Reserved10; // 0 [204]\r
+ UINT8 MIN_PERF_R_4_26; // Minimum Read Performance for 4bit @26MHz [205]\r
+ UINT8 MIN_PERF_W_4_26; // Minimum Write Performance for 4bit @26MHz [206]\r
+ UINT8 MIN_PERF_R_8_26_4_52; // Minimum Read Performance for 8bit @26MHz/4bit @52MHz [207]\r
+ UINT8 MIN_PERF_W_8_26_4_52; // Minimum Write Performance for 8bit @26MHz/4bit @52MHz [208]\r
+ UINT8 MIN_PERF_R_8_52; // Minimum Read Performance for 8bit @52MHz [209]\r
+ UINT8 MIN_PERF_W_8_52; // Minimum Write Performance for 8bit @52MHz [210]\r
+ UINT8 Reserved11; // 0 [211]\r
+ UINT8 SEC_COUNT[4]; // Sector Count [215:212]\r
+ UINT8 Reserved12[288]; // 0 [503:216]\r
+ UINT8 S_CMD_SET; // Sector Count [504]\r
+ UINT8 Reserved13[7]; // Sector Count [511:505]\r
+}EXT_CSD;\r
+\r
+\r
+//\r
+//Card Status definition\r
+//\r
+typedef struct {\r
+ UINT32 Reserved0: 2; //Reserved for Manufacturer Test Mode\r
+ UINT32 Reserved1: 2; //Reserved for Application Specific commands\r
+ UINT32 Reserved2: 1; //\r
+ UINT32 SAPP_CMD: 1; //\r
+ UINT32 Reserved3: 1; //Reserved\r
+ UINT32 SWITCH_ERROR: 1; //\r
+ UINT32 READY_FOR_DATA: 1; //\r
+ UINT32 CURRENT_STATE: 4; //\r
+ UINT32 ERASE_RESET: 1; //\r
+ UINT32 Reserved4: 1; //Reserved\r
+ UINT32 WP_ERASE_SKIP: 1; //\r
+ UINT32 CID_CSD_OVERWRITE: 1; //\r
+ UINT32 OVERRUN: 1; //\r
+ UINT32 UNDERRUN: 1; //\r
+ UINT32 ERROR: 1; //\r
+ UINT32 CC_ERROR: 1; //\r
+ UINT32 CARD_ECC_FAILED: 1; //\r
+ UINT32 ILLEGAL_COMMAND: 1; //\r
+ UINT32 COM_CRC_ERROR: 1; //\r
+ UINT32 LOCK_UNLOCK_FAILED: 1; //\r
+ UINT32 CARD_IS_LOCKED: 1; //\r
+ UINT32 WP_VIOLATION: 1; //\r
+ UINT32 ERASE_PARAM: 1; //\r
+ UINT32 ERASE_SEQ_ERROR: 1; //\r
+ UINT32 BLOCK_LEN_ERROR: 1; //\r
+ UINT32 ADDRESS_MISALIGN: 1; //\r
+ UINT32 ADDRESS_OUT_OF_RANGE:1; //\r
+}CARD_STATUS;\r
+\r
+typedef struct {\r
+ UINT32 CmdSet: 3;\r
+ UINT32 Reserved0: 5;\r
+ UINT32 Value: 8;\r
+ UINT32 Index: 8;\r
+ UINT32 Access: 2;\r
+ UINT32 Reserved1: 6;\r
+}SWITCH_ARGUMENT;\r
+\r
+#define CommandSet_Mode 0\r
+#define SetBits_Mode 1\r
+#define ClearBits_Mode 2\r
+#define WriteByte_Mode 3\r
+\r
+\r
+#define Idle_STATE 0\r
+#define Ready_STATE 1\r
+#define Ident_STATE 2\r
+#define Stby_STATE 3\r
+#define Tran_STATE 4\r
+#define Data_STATE 5\r
+#define Rcv_STATE 6\r
+#define Prg_STATE 7\r
+#define Dis_STATE 8\r
+#define Btst_STATE 9\r
+\r
+\r
+\r
+#pragma pack()\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+Header file for Industry SD Card 2.0 spec.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_CARD_H\r
+#define _SD_CARD_H\r
+\r
+#include "MMC.h"\r
+\r
+#pragma pack(1)\r
+\r
+#define CHECK_PATTERN 0xAA ///< Physical Layer Simplified Specification Version 3.01 recommended 0xAA\r
+\r
+#define ACMD6 6\r
+#define ACMD13 13\r
+#define ACMD23 23\r
+#define ACMD41 41\r
+#define ACMD42 42\r
+#define ACMD51 51\r
+\r
+\r
+#define SWITCH_FUNC CMD6\r
+#define SEND_IF_COND CMD8\r
+\r
+\r
+#define SET_BUS_WIDTH ACMD6\r
+#define SD_STATUS ACMD13\r
+#define SET_WR_BLK_ERASE_COUNT ACMD23\r
+#define SD_SEND_OP_COND ACMD41\r
+#define SET_CLR_CARD_DETECT ACMD42\r
+#define SEND_SCR ACMD51\r
+\r
+\r
+\r
+#define SD_BUS_WIDTH_1 0\r
+#define SD_BUS_WIDTH_4 2\r
+\r
+\r
+\r
+#define FREQUENCY_SD_PP (25 * 1000 * 1000)\r
+#define FREQUENCY_SD_PP_HIGH (50 * 1000 * 1000)\r
+\r
+\r
+#define SD_SPEC_10 0\r
+#define SD_SPEC_11 1\r
+#define SD_SPEC_20 2\r
+\r
+\r
+#define VOLTAGE_27_36 0x1\r
+\r
+typedef struct {\r
+ UINT8 NotUsed: 1; // 1 [0:0]\r
+ UINT8 CRC: 7; // CRC [7:1]\r
+ UINT8 ECC: 2; // ECC code [9:8]\r
+ UINT8 FILE_FORMAT: 2; // File format [11:10]\r
+ UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12]\r
+ UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13]\r
+ UINT8 COPY: 1; // Copy flag (OTP) [14:14]\r
+ UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15]\r
+ UINT16 Reserved0: 5; // 0 [20:16]\r
+ UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21]\r
+ UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22]\r
+ UINT16 R2W_FACTOR: 3; // Write speed factor [28:26]\r
+ UINT16 DEFAULT_ECC: 2; // Manufacturer default ECC [30:29]\r
+ UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31]\r
+ UINT16 WP_GRP_SIZE: 7; // Write protect group size [38:32]\r
+ UINT16 SECTOR_SIZE: 7; // Erase sector size [45:39]\r
+ UINT16 ERASE_BLK_EN: 1; // Erase single block enable [46:46]\r
+ UINT16 Reserved1: 1; // 0 [47:47]\r
+\r
+ UINT32 C_SIZE: 22; // Device size [69:48]\r
+ UINT32 Reserved2: 6; // 0 [75:70]\r
+ UINT32 DSR_IMP: 1; // DSR implemented [76:76]\r
+ UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77]\r
+ UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78]\r
+ UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79]\r
+\r
+ UINT16 READ_BL_LEN: 4; // Max. read data block length [83:80]\r
+ UINT16 CCC: 12; // Card command classes [95:84]\r
+ UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96]\r
+ UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104]\r
+ UINT8 TAAC ; // Data read access-time 1 [119:112]\r
+ UINT8 Reserved3: 6; // 0 [125:120]\r
+ UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126]\r
+}CSD_SDV2;\r
+\r
+typedef struct {\r
+ UINT32 Reserved0;\r
+ UINT32 Reserved1: 16;\r
+ UINT32 SD_BUS_WIDTH: 4;\r
+ UINT32 SD_SECURITY: 3;\r
+ UINT32 DATA_STAT_AFTER_ERASE: 1;\r
+ UINT32 SD_SPEC: 4;\r
+ UINT32 SCR_STRUCT: 4;\r
+}SCR;\r
+\r
+\r
+typedef struct {\r
+ UINT8 Reserved0[50];\r
+ UINT8 ERASE_OFFSET: 2;\r
+ UINT8 ERASE_TIMEOUT: 6;\r
+ UINT16 ERASE_SIZE;\r
+ UINT8 Reserved1: 4;\r
+ UINT8 AU_SIZE: 4;\r
+ UINT8 PERFORMANCE_MOVE;\r
+ UINT8 SPEED_CLASS;\r
+ UINT32 SIZE_OF_PROTECTED_AREA;\r
+ UINT32 SD_CARD_TYPE: 16;\r
+ UINT32 Reserved2: 13;\r
+ UINT32 SECURED_MODE: 1;\r
+ UINT32 DAT_BUS_WIDTH: 2;\r
+}SD_STATUS_REG;\r
+\r
+\r
+\r
+typedef struct {\r
+ UINT8 Reserved0[34];\r
+ UINT16 Group1BusyStatus;\r
+ UINT16 Group2BusyStatus;\r
+ UINT16 Group3BusyStatus;\r
+ UINT16 Group4BusyStatus;\r
+ UINT16 Group5BusyStatus;\r
+ UINT16 Group6BusyStatus;\r
+ UINT8 DataStructureVersion;\r
+ UINT8 Group21Status;\r
+ UINT8 Group43Status;\r
+ UINT8 Group65Status;\r
+ UINT16 Group1Function;\r
+ UINT16 Group2Function;\r
+ UINT16 Group3Function;\r
+ UINT16 Group4Function;\r
+ UINT16 Group5Function;\r
+ UINT16 Group6Function;\r
+ UINT16 MaxCurrent;\r
+}SWITCH_STATUS;\r
+\r
+\r
+#pragma pack()\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+\r
+Interface definition for EFI_SD_HOST_IO_PROTOCOL.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_HOST_IO_H\r
+#define _SD_HOST_IO_H\r
+\r
+#include "SDCard.h"\r
+#include "CEATA.h"\r
+\r
+\r
+#define EFI_SD_HOST_IO_PROTOCOL_GUID \\r
+ { \\r
+ 0xb63f8ec7, 0xa9c9, 0x4472, {0xa4, 0xc0, 0x4d, 0x8b, 0xf3, 0x65, 0xcc, 0x51} \\r
+ }\r
+\r
+///\r
+/// Forward reference for pure ANSI compatability\r
+///\r
+typedef struct _EFI_SD_HOST_IO_PROTOCOL EFI_SD_HOST_IO_PROTOCOL;\r
+\r
+\r
+\r
+typedef enum {\r
+ ResponseNo = 0,\r
+ ResponseR1,\r
+ ResponseR1b,\r
+ ResponseR2,\r
+ ResponseR3,\r
+ ResponseR4,\r
+ ResponseR5,\r
+ ResponseR5b,\r
+ ResponseR6,\r
+ ResponseR7\r
+}RESPONSE_TYPE;\r
+\r
+typedef enum {\r
+ NoData = 0,\r
+ InData,\r
+ OutData\r
+}TRANSFER_TYPE;\r
+\r
+typedef enum {\r
+ Reset_Auto = 0,\r
+ Reset_DAT,\r
+ Reset_CMD,\r
+ Reset_DAT_CMD,\r
+ Reset_All\r
+}RESET_TYPE;\r
+\r
+#define PCI_SUBCLASS_SD_HOST_CONTROLLER 0x05\r
+#define PCI_IF_STANDARD_HOST_NO_DMA 0x00\r
+#define PCI_IF_STANDARD_HOST_SUPPORT_DMA 0x01\r
+\r
+#define SDHCI_SPEC_100 0\r
+#define SDHCI_SPEC_200 1\r
+#define SDHCI_SPEC_300 2\r
+\r
+//\r
+//MMIO Registers definition for MMC/SDIO controller\r
+//\r
+#define MMIO_DMAADR 0x00\r
+#define MMIO_BLKSZ 0x04\r
+#define MMIO_BLKCNT 0x06\r
+#define MMIO_CMDARG 0x08\r
+#define MMIO_XFRMODE 0x0C\r
+#define MMIO_SDCMD 0x0E\r
+#define MMIO_RESP 0x10\r
+#define MMIO_BUFDATA 0x20\r
+#define MMIO_PSTATE 0x24\r
+#define MMIO_HOSTCTL 0x28\r
+#define MMIO_PWRCTL 0x29\r
+#define MMIO_BLKGAPCTL 0x2A\r
+#define MMIO_WAKECTL 0x2B\r
+#define MMIO_CLKCTL 0x2C\r
+#define V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL 0x80\r
+#define V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL 0x3FF\r
+#define B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK 0xC0\r
+\r
+#define MMIO_TOCTL 0x2E\r
+#define MMIO_SWRST 0x2F\r
+#define MMIO_NINTSTS 0x30\r
+#define MMIO_ERINTSTS 0x32\r
+#define MMIO_NINTEN 0x34\r
+#define MMIO_ERINTEN 0x36\r
+#define MMIO_NINTSIGEN 0x38\r
+#define MMIO_ERINTSIGEN 0x3A\r
+#define MMIO_AC12ERRSTS 0x3C\r
+#define MMIO_HOSTCTL2 0x3E\r
+#define MMIO_CAP 0x40\r
+#define MMIO_MCCAP 0x48\r
+#define MMIO_SLTINTSTS 0xFC\r
+#define MMIO_CTRLRVER 0xFE\r
+#define MMIO_SRST 0x1FC\r
+\r
+//\r
+// Protocol definitions\r
+//\r
+\r
+/**\r
+ The main function used to send the command to the card inserted into the SD host slot.\r
+ It will assemble the arguments to set the command register and wait for the command\r
+ and transfer completed until timeout. Then it will read the response register to fill\r
+ the ResponseData.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param CommandIndex The command index to set the command index field of command register.\r
+ @param Argument Command argument to set the argument field of command register.\r
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.\r
+ @param Buffer Contains the data read from / write to the device.\r
+ @param BufferSize The size of the buffer.\r
+ @param ResponseType RESPONSE_TYPE.\r
+ @param TimeOut Time out value in 1 ms unit.\r
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_OUT_OF_RESOURCES\r
+ @retval EFI_TIMEOUT\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SEND_COMMAND) (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT16 CommandIndex,\r
+ IN UINT32 Argument,\r
+ IN TRANSFER_TYPE DataType,\r
+ IN UINT8 *Buffer, OPTIONAL\r
+ IN UINT32 BufferSize,\r
+ IN RESPONSE_TYPE ResponseType,\r
+ IN UINT32 TimeOut,\r
+ OUT UINT32 *ResponseData OPTIONAL\r
+ );\r
+\r
+/**\r
+ Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.\r
+ It depends on the max frequency the host can support, divider, and host speed mode.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param MaxFrequency Max frequency in HZ.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_CLOCK_FREQUENCY) (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 MaxFrequency\r
+ );\r
+\r
+\r
+/**\r
+ Set bus width of the host controller\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param BusWidth Bus width in 1, 4, 8 bits.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_BUS_WIDTH) (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 BusWidth\r
+ );\r
+\r
+/**\r
+ Set voltage which could supported by the host controller.\r
+ Support 0(Power off the host), 1.8V, 3.0V, 3.3V\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Voltage Units in 0.1 V.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_HOST_VOLTAGE) (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 Voltage\r
+ );\r
+\r
+/**\r
+ Reset the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param ResetAll TRUE to reset all.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_RESET_SD_HOST) (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN RESET_TYPE ResetType\r
+ );\r
+\r
+/**\r
+ Enable auto stop on the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Enable TRUE to enable, FALSE to disable.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_ENABLE_AUTO_STOP_CMD) (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ );\r
+\r
+/**\r
+ Find whether these is a card inserted into the slot. If so init the host.\r
+ If not, return EFI_NOT_FOUND.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_NOT_FOUND\r
+\r
+**/\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_DETECT_CARD_AND_INIT_HOST) (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This\r
+ );\r
+\r
+/**\r
+ Set the Block length on the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param BlockLength card supportes block length.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_SET_BLOCK_LENGTH) (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 BlockLength\r
+ );\r
+\r
+/**\r
+ Enable/Disable High Speed transfer mode\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Enable TRUE to Enable, FALSE to Disable\r
+\r
+ @return EFI_SUCCESS\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_HIGH_SPEED_MODE) (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ );\r
+\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EFI_SD_HOST_IO_PROTOCOL_DUAL_DATARATE_MODE) (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ );\r
+\r
+\r
+\r
+#define EFI_SD_HOST_IO_PROTOCOL_REVISION_01 0x02\r
+\r
+\r
+typedef struct {\r
+ UINT32 HighSpeedSupport: 1; //High speed supported\r
+ UINT32 V18Support: 1; //1.8V supported\r
+ UINT32 V30Support: 1; //3.0V supported\r
+ UINT32 V33Support: 1; //3.3V supported\r
+ UINT32 Reserved0: 4;\r
+ UINT32 HostVersion: 8;\r
+ UINT32 BusWidth4: 1; // 4 bit width\r
+ UINT32 BusWidth8: 1; // 8 bit width\r
+ UINT32 Reserved1: 14;\r
+ UINT32 BoundarySize;\r
+}HOST_CAPABILITY;\r
+\r
+\r
+//\r
+// Interface structure for the SD HOST I/O Protocol\r
+//\r
+struct _EFI_SD_HOST_IO_PROTOCOL {\r
+ UINT32 Revision;\r
+ HOST_CAPABILITY HostCapability;\r
+ EFI_SD_HOST_IO_PROTOCOL_SEND_COMMAND SendCommand;\r
+ EFI_SD_HOST_IO_PROTOCOL_SET_CLOCK_FREQUENCY SetClockFrequency;\r
+ EFI_SD_HOST_IO_PROTOCOL_SET_BUS_WIDTH SetBusWidth;\r
+ EFI_SD_HOST_IO_PROTOCOL_SET_HOST_VOLTAGE SetHostVoltage;\r
+ EFI_SD_HOST_IO_PROTOCOL_RESET_SD_HOST ResetSDHost;\r
+ EFI_SD_HOST_IO_PROTOCOL_ENABLE_AUTO_STOP_CMD EnableAutoStopCmd;\r
+ EFI_SD_HOST_IO_PROTOCOL_DETECT_CARD_AND_INIT_HOST DetectCardAndInitHost;\r
+ EFI_SD_HOST_IO_PROTOCOL_SET_BLOCK_LENGTH SetBlockLength;\r
+ EFI_SD_HOST_IO_PROTOCOL_HIGH_SPEED_MODE SetHighSpeedMode;\r
+ EFI_SD_HOST_IO_PROTOCOL_DUAL_DATARATE_MODE SetDDRMode;\r
+};\r
+\r
+extern EFI_GUID gEfiSDHostIoProtocolGuid;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Common header file shared by all source files.\r
+\r
+This file includes package header files, library classes and protocol, PPI & GUID definitions.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef __COMMON_HEADER_H_\r
+#define __COMMON_HEADER_H_\r
+\r
+//\r
+// The package level header files this module uses\r
+//\r
+#include <PiDxe.h>\r
+#include <Ioh.h>\r
+#include <IohCommonDefinitions.h>\r
+\r
+//\r
+// The protocols, PPI and GUID defintions for this module\r
+//\r
+#include <Protocol/PciRootBridgeIo.h>\r
+\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/DevicePath.h>\r
+\r
+//\r
+// The Library classes this module consumes\r
+//\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/S3PciLib.h>\r
+#include <Library/S3IoLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/S3BootScriptLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/IohLib.h>\r
+\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Head file for BDS Platform specific code\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _IOH_BDS_H\r
+#define _IOH_BDS_H\r
+\r
+#include <Ioh.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Library/DevicePathLib.h>\r
+\r
+extern EFI_DEVICE_PATH_PROTOCOL *gDeviceConnectOption [];\r
+\r
+#define PCI_DEVICE_PATH_NODE(Func, Dev) \\r
+ { \\r
+ { \\r
+ HARDWARE_DEVICE_PATH, \\r
+ HW_PCI_DP, \\r
+ { \\r
+ (UINT8) (sizeof (PCI_DEVICE_PATH)), \\r
+ (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) \\r
+ } \\r
+ }, \\r
+ (Func), \\r
+ (Dev) \\r
+ }\r
+\r
+#define PNPID_DEVICE_PATH_NODE(PnpId) \\r
+ { \\r
+ { \\r
+ ACPI_DEVICE_PATH, \\r
+ ACPI_DP, \\r
+ { \\r
+ (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), \\r
+ (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) \\r
+ } \\r
+ }, \\r
+ EISA_PNP_ID((PnpId)), \\r
+ 0 \\r
+ }\r
+\r
+\r
+\r
+#define gEndEntire \\r
+ { \\r
+ END_DEVICE_PATH_TYPE, \\r
+ END_ENTIRE_DEVICE_PATH_SUBTYPE, \\r
+ { \\r
+ END_DEVICE_PATH_LENGTH, \\r
+ 0 \\r
+ } \\r
+ }\r
+\r
+#define gPciRootBridge \\r
+ PNPID_DEVICE_PATH_NODE(0x0A03)\r
+\r
+\r
+//\r
+// Platform Root Bridge\r
+//\r
+typedef struct {\r
+ ACPI_HID_DEVICE_PATH PciRootBridge;\r
+ EFI_DEVICE_PATH_PROTOCOL End;\r
+} PLATFORM_ROOT_BRIDGE_DEVICE_PATH;\r
+\r
+\r
+typedef struct {\r
+ ACPI_HID_DEVICE_PATH PciRootBridge;\r
+ PCI_DEVICE_PATH IohDevice;\r
+ EFI_DEVICE_PATH_PROTOCOL End;\r
+} IOH_PCI_USB_DEVICE_PATH;\r
+\r
+//\r
+// Ioh BDS Functions\r
+//\r
+\r
+\r
+#endif // _IOH_BDS_H\r
--- /dev/null
+/** @file\r
+Defined the Ioh device path which will be used by\r
+platform Bbd to perform the platform policy connect.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "IohBds.h"\r
+\r
+//\r
+// Predefined platform root bridge\r
+//\r
+PLATFORM_ROOT_BRIDGE_DEVICE_PATH gPlatformRootBridge0 = {\r
+ gPciRootBridge,\r
+ gEndEntire\r
+};\r
+\r
+EFI_DEVICE_PATH_PROTOCOL* gPlatformRootBridges [] = {\r
+ (EFI_DEVICE_PATH_PROTOCOL*)&gPlatformRootBridge0,\r
+ NULL\r
+};\r
+\r
+//\r
+// Ioh USB EHCI controller device path\r
+//\r
+IOH_PCI_USB_DEVICE_PATH gIohUsbDevicePath0 = {\r
+ gPciRootBridge,\r
+ PCI_DEVICE_PATH_NODE(IOH_EHCI_FUNCTION_NUMBER, IOH_USB_EHCI_DEVICE_NUMBER),\r
+ gEndEntire\r
+};\r
+\r
+//\r
+// Ioh predefined device connecting option\r
+//\r
+EFI_DEVICE_PATH_PROTOCOL* gDeviceConnectOption [] = {\r
+ // (EFI_DEVICE_PATH_PROTOCOL*)&gIohUsbDevicePath0,\r
+ NULL\r
+};\r
+\r
--- /dev/null
+/** @file\r
+QuarkSCSocId module initialization module\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "CommonHeader.h"\r
+#include "IohBds.h"\r
+\r
+/**\r
+ The entry function for IohInit driver.\r
+\r
+ This function just call initialization function.\r
+\r
+ @param ImageHandle The driver image handle for GmchInit driver\r
+ @param SystemTable The pointer to System Table\r
+\r
+ @retval EFI_SUCCESS Success to initialize every module.\r
+ @return EFI_STATUS The status of initialization work.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IohInit (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+\r
+ InitializeIohSsvidSsid(IOH_BUS, IOH_PCI_IOSF2AHB_0_DEV_NUM, 0);\r
+\r
+ InitializeIohSsvidSsid(IOH_BUS, IOH_PCI_IOSF2AHB_1_DEV_NUM, 0);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+## @file\r
+# Component description file for Quark South Cluster Init driver.\r
+#\r
+# IohInit driver implement QuarkSCSocId related drivers, includes:\r
+# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver.\r
+#\r
+# This driver mainly do full initialization for the Soc chipet includes:\r
+# 1. Initialize the PCI Express device.\r
+# 2. Initialize the PciHostBridge, and allocate the I/O and memory space from GCD service.\r
+# 3. Initialize the SmmAccess module and install EFI_SMM_ACCESS_PROTOCOL\r
+# 4. Initialize the LegacyRegion module, install EFI_LEGACY_REGION_PROTOCOL and set below 1M\r
+# memory attribute from MTRR.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = IohInitDxe\r
+ FILE_GUID = 3FE2A8A3-C400-48F8-832F-7881A394C250\r
+ MODULE_TYPE = DXE_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = IohInit\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ IohInit.c\r
+ IohBds.h\r
+ IohData.c\r
+ CommonHeader.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ S3BootScriptLib\r
+ PcdLib\r
+ HobLib\r
+ PciLib\r
+ BaseMemoryLib\r
+ MemoryAllocationLib\r
+ S3PciLib\r
+ UefiLib\r
+ DebugLib\r
+ UefiRuntimeServicesTableLib\r
+ UefiBootServicesTableLib\r
+ DxeServicesTableLib\r
+ UefiDriverEntryPoint\r
+ BaseLib\r
+ S3IoLib\r
+ IoLib\r
+ DevicePathLib\r
+ IohLib\r
+\r
+[Protocols]\r
+ gEfiPciRootBridgeIoProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiPciIoProtocolGuid\r
+\r
+[Pcd]\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartBusNumber\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartDevNumber\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohUartFunctionNumber\r
+\r
+[Depex]\r
+ TRUE\r
--- /dev/null
+/** @file\r
+Provides definition of entry point to the common I2C module that produces\r
+common I2C Controller functions used by I2C library services.\r
+\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef _I2CCOMMON_H_\r
+#define _I2CCOMMON_H_\r
+\r
+#include <Uefi.h>\r
+#include <Base.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/I2cLib.h>\r
+#include <IohAccess.h>\r
+#include <IohCommonDefinitions.h>\r
+#include "I2cRegs.h"\r
+\r
+//\r
+// Constants that define I2C Controller timeout and max. polling time.\r
+//\r
+#define MAX_T_POLL_COUNT 100\r
+#define TI2C_POLL 25 // microseconds\r
+#define MAX_STOP_DET_POLL_COUNT ((1000 * 1000) / TI2C_POLL) // Extreme for expected Stop detect.\r
+\r
+/**\r
+ The GetI2CIoPortBaseAddress() function gets IO port base address of I2C Controller.\r
+\r
+ Always reads PCI configuration space to get MMIO base address of I2C Controller.\r
+\r
+ @return The IO port base address of I2C controller.\r
+\r
+**/\r
+UINTN\r
+GetI2CIoPortBaseAddress (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ The EnableI2CMmioSpace() function enables access to I2C MMIO space.\r
+\r
+**/\r
+VOID\r
+EnableI2CMmioSpace (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ The DisableI2CController() functions disables I2C Controller.\r
+\r
+**/\r
+VOID\r
+DisableI2CController (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ The EnableI2CController() function enables the I2C Controller.\r
+\r
+**/\r
+VOID\r
+EnableI2CController (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ The WaitForStopDet() function waits until I2C STOP Condition occurs,\r
+ indicating transfer completion.\r
+\r
+ @retval EFI_SUCCESS Stop detected.\r
+ @retval EFI_TIMEOUT Timeout while waiting for stop condition.\r
+ @retval EFI_ABORTED Tx abort signaled in HW status register.\r
+ @retval EFI_DEVICE_ERROR Tx or Rx overflow detected.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForStopDet (\r
+ VOID\r
+ );\r
+\r
+/**\r
+\r
+ The InitializeInternal() function initialises internal I2C Controller\r
+ register values that are commonly required for I2C Write and Read transfers.\r
+\r
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
+\r
+ @retval EFI_SUCCESS I2C Operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeInternal (\r
+ IN EFI_I2C_ADDR_MODE AddrMode\r
+ );\r
+\r
+/**\r
+\r
+ The WriteByte() function provides a standard way to execute a\r
+ standard single byte write to an IC2 device (without accessing\r
+ sub-addresses), as defined in the I2C Specification.\r
+\r
+ @param I2CAddress I2C Slave device address\r
+ @param Value The 8-bit value to write.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WriteByte (\r
+ IN UINTN I2CAddress,\r
+ IN UINT8 Value\r
+ );\r
+\r
+/**\r
+\r
+ The ReadByte() function provides a standard way to execute a\r
+ standard single byte read to an IC2 device (without accessing\r
+ sub-addresses), as defined in the I2C Specification.\r
+\r
+ @param I2CAddress I2C Slave device address\r
+ @param ReturnDataPtr Pointer to location to receive read byte.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ReadByte (\r
+ IN UINTN I2CAddress,\r
+ OUT UINT8 *ReturnDataPtr\r
+ );\r
+\r
+/**\r
+\r
+ The WriteMultipleByte() function provides a standard way to execute\r
+ multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or\r
+ when writing block of data), as defined in the I2C Specification.\r
+\r
+ @param I2CAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param WriteBuffer Contains the value of byte to be written to the\r
+ I2C slave device.\r
+\r
+ @param Length No. of bytes to be written.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Tx abort signaled in HW status register.\r
+ @retval EFI_DEVICE_ERROR Tx overflow detected.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WriteMultipleByte (\r
+ IN UINTN I2CAddress,\r
+ IN UINT8 *WriteBuffer,\r
+ IN UINTN Length\r
+ );\r
+\r
+/**\r
+\r
+ The ReadMultipleByte() function provides a standard way to execute\r
+ multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or\r
+ when reading block of data), as defined in the I2C Specification (I2C combined\r
+ write/read protocol).\r
+\r
+ @param I2CAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param Buffer Contains the value of byte data written or read from the\r
+ I2C slave device.\r
+\r
+ @param WriteLength No. of bytes to be written. In this case data\r
+ written typically contains sub-address or sub-addresses\r
+ in Hi-Lo format, that need to be read (I2C combined\r
+ write/read protocol).\r
+\r
+ @param ReadLength No. of bytes to be read from I2C slave device.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Tx abort signaled in HW status register.\r
+ @retval EFI_DEVICE_ERROR Rx underflow or Rx/Tx overflow detected.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ReadMultipleByte (\r
+ IN UINTN I2CAddress,\r
+ IN OUT UINT8 *Buffer,\r
+ IN UINTN WriteLength,\r
+ IN UINTN ReadLength\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+I2C Library for Quark I2C Controller.\r
+Follows I2C Controller setup instructions as detailed in\r
+Quark DataSheet (doc id: 329676) Section 19.1/19.1.3.\r
+\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "CommonHeader.h"\r
+\r
+/**\r
+ The Called to Common Service Entry.\r
+\r
+ @return None.\r
+\r
+**/\r
+\r
+VOID\r
+I2cCommonServiceEntry (\r
+ OUT UINT16 *SaveCmdPtr,\r
+ OUT UINT32 *SaveBar0Ptr\r
+ )\r
+{\r
+ *SaveBar0Ptr = IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);\r
+ if (((*SaveBar0Ptr) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {\r
+\r
+ IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) =\r
+ FixedPcdGet32 (PcdIohI2cMmioBase) & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK;\r
+\r
+ //\r
+ // also Save Cmd Register, Setup by InitializeInternal later during xfers.\r
+ //\r
+ *SaveCmdPtr = IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD);\r
+ }\r
+}\r
+\r
+/**\r
+ The Called on Common Service Exit.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+I2cCommonServiceExit (\r
+ IN CONST UINT16 SaveCmd,\r
+ IN CONST UINT32 SaveBar0\r
+\r
+ )\r
+{\r
+ if ((SaveBar0 & B_IOH_I2C_GPIO_MEMBAR_ADDR_MASK) == 0) {\r
+ IohMmPci16 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_CMD) = SaveCmd;\r
+ IohMmPci32 (0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0) = SaveBar0;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ The GetI2CIoPortBaseAddress() function gets IO port base address of I2C Controller.\r
+\r
+ Always reads PCI configuration space to get MMIO base address of I2C Controller.\r
+\r
+ @return The IO port base address of I2C controller.\r
+\r
+**/\r
+UINTN\r
+GetI2CIoPortBaseAddress (\r
+ VOID\r
+ )\r
+{\r
+ UINTN I2CIoPortBaseAddress;\r
+\r
+ //\r
+ // Get I2C Memory Mapped registers base address.\r
+ //\r
+ I2CIoPortBaseAddress = IohMmPci32(0, I2C_Bus, I2C_Device, I2C_Func, PCI_BAR0);\r
+\r
+ //\r
+ // Make sure that the IO port base address has been properly set.\r
+ //\r
+ ASSERT (I2CIoPortBaseAddress != 0);\r
+ ASSERT (I2CIoPortBaseAddress != 0xFF);\r
+\r
+ return I2CIoPortBaseAddress;\r
+}\r
+\r
+\r
+/**\r
+ The EnableI2CMmioSpace() function enables access to I2C MMIO space.\r
+\r
+**/\r
+VOID\r
+EnableI2CMmioSpace (\r
+ VOID\r
+ )\r
+{\r
+ UINT8 PciCmd;\r
+\r
+ //\r
+ // Read PCICMD. Bus=0, Dev=0, Func=0, Reg=0x4\r
+ //\r
+ PciCmd = IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD);\r
+\r
+ //\r
+ // Enable Bus Master(Bit2), MMIO Space(Bit1) & I/O Space(Bit0)\r
+ //\r
+ PciCmd |= 0x7;\r
+ IohMmPci8(0, I2C_Bus, I2C_Device, I2C_Func, PCI_REG_PCICMD) = PciCmd;\r
+\r
+}\r
+\r
+/**\r
+ The DisableI2CController() functions disables I2C Controller.\r
+\r
+**/\r
+VOID\r
+DisableI2CController (\r
+ VOID\r
+ )\r
+{\r
+ UINTN I2CIoPortBaseAddress;\r
+ UINT32 Addr;\r
+ UINT32 Data;\r
+ UINT8 PollCount;\r
+\r
+ PollCount = 0;\r
+\r
+ //\r
+ // Get I2C Memory Mapped registers base address.\r
+ //\r
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
+\r
+ //\r
+ // Disable the I2C Controller by setting IC_ENABLE.ENABLE to zero\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= ~B_I2C_REG_ENABLE;\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+\r
+ //\r
+ // Read the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled\r
+ //\r
+ Data = 0xFF;\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE_STATUS;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr)) & I2C_REG_ENABLE_STATUS;\r
+ while (Data != 0) {\r
+ //\r
+ // Poll the IC_ENABLE_STATUS.IC_EN Bit to check if Controller is disabled, until timeout (TI2C_POLL*MAX_T_POLL_COUNT).\r
+ //\r
+ PollCount++;\r
+ if (PollCount >= MAX_T_POLL_COUNT) {\r
+ break;\r
+ }\r
+ MicroSecondDelay(TI2C_POLL);\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= I2C_REG_ENABLE_STATUS;\r
+ }\r
+\r
+ //\r
+ // Asset if controller does not enter Disabled state.\r
+ //\r
+ ASSERT (PollCount < MAX_T_POLL_COUNT);\r
+\r
+ //\r
+ // Read IC_CLR_INTR register to automatically clear the combined interrupt,\r
+ // all individual interrupts and the IC_TX_ABRT_SOURCE register.\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_INT;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+\r
+}\r
+\r
+/**\r
+ The EnableI2CController() function enables the I2C Controller.\r
+\r
+**/\r
+VOID\r
+EnableI2CController (\r
+ VOID\r
+ )\r
+{\r
+ UINTN I2CIoPortBaseAddress;\r
+ UINT32 Addr;\r
+ UINT32 Data;\r
+\r
+ //\r
+ // Get I2C Memory Mapped registers base address.\r
+ //\r
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
+\r
+ //\r
+ // Enable the I2C Controller by setting IC_ENABLE.ENABLE to 1\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_ENABLE;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data |= B_I2C_REG_ENABLE;\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+\r
+ //\r
+ // Clear overflow and abort error status bits before transactions.\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_OVER;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_OVER;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_TX_ABRT;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+\r
+}\r
+\r
+/**\r
+ The WaitForStopDet() function waits until I2C STOP Condition occurs,\r
+ indicating transfer completion.\r
+\r
+ @retval EFI_SUCCESS Stop detected.\r
+ @retval EFI_TIMEOUT Timeout while waiting for stop condition.\r
+ @retval EFI_ABORTED Tx abort signaled in HW status register.\r
+ @retval EFI_DEVICE_ERROR Tx or Rx overflow detected.\r
+\r
+**/\r
+EFI_STATUS\r
+WaitForStopDet (\r
+ VOID\r
+ )\r
+{\r
+ UINTN I2CIoPortBaseAddress;\r
+ UINT32 Addr;\r
+ UINT32 Data;\r
+ UINT32 PollCount;\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ PollCount = 0;\r
+\r
+ //\r
+ // Get I2C Memory Mapped registers base address.\r
+ //\r
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
+\r
+ //\r
+ // Wait for STOP Detect.\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;\r
+\r
+ do {\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ if ((Data & I2C_REG_RAW_INTR_STAT_TX_ABRT) != 0) {\r
+ Status = EFI_ABORTED;\r
+ break;\r
+ }\r
+ if ((Data & I2C_REG_RAW_INTR_STAT_TX_OVER) != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+ if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+ }\r
+ if ((Data & I2C_REG_RAW_INTR_STAT_STOP_DET) != 0) {\r
+ Status = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ MicroSecondDelay(TI2C_POLL);\r
+ PollCount++;\r
+ if (PollCount >= MAX_STOP_DET_POLL_COUNT) {\r
+ Status = EFI_TIMEOUT;\r
+ break;\r
+ }\r
+\r
+ } while (TRUE);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ The InitializeInternal() function initialises internal I2C Controller\r
+ register values that are commonly required for I2C Write and Read transfers.\r
+\r
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
+\r
+ @retval EFI_SUCCESS I2C Operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeInternal (\r
+ IN EFI_I2C_ADDR_MODE AddrMode\r
+ )\r
+{\r
+ UINTN I2CIoPortBaseAddress;\r
+ UINTN Addr;\r
+ UINT32 Data;\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Enable access to I2C Controller MMIO space.\r
+ //\r
+ EnableI2CMmioSpace ();\r
+\r
+ //\r
+ // Disable I2C Controller initially\r
+ //\r
+ DisableI2CController ();\r
+\r
+ //\r
+ // Get I2C Memory Mapped registers base address.\r
+ //\r
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
+\r
+ //\r
+ // Clear START_DET\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_START_DET;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= ~B_I2C_REG_CLR_START_DET;\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+\r
+ //\r
+ // Clear STOP_DET\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_STOP_DET;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= ~B_I2C_REG_CLR_STOP_DET;\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+\r
+ //\r
+ // Set addressing mode to user defined (7 or 10 bit) and\r
+ // speed mode to that defined by PCD (standard mode default).\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_CON;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ // Set Addressing Mode\r
+ if (AddrMode == EfiI2CSevenBitAddrMode) {\r
+ Data &= ~B_I2C_REG_CON_10BITADD_MASTER;\r
+ } else {\r
+ Data |= B_I2C_REG_CON_10BITADD_MASTER;\r
+ }\r
+ // Set Speed Mode\r
+ Data &= ~B_I2C_REG_CON_SPEED;\r
+ if (FeaturePcdGet (PcdI2CFastModeEnabled)) {\r
+ Data |= BIT2;\r
+ } else {\r
+ Data |= BIT1;\r
+ }\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+\r
+ The WriteByte() function provides a standard way to execute a\r
+ standard single byte write to an IC2 device (without accessing\r
+ sub-addresses), as defined in the I2C Specification.\r
+\r
+ @param I2CAddress I2C Slave device address\r
+ @param Value The 8-bit value to write.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WriteByte (\r
+ IN UINTN I2CAddress,\r
+ IN UINT8 Value\r
+ )\r
+{\r
+ UINTN I2CIoPortBaseAddress;\r
+ UINTN Addr;\r
+ UINT32 Data;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Get I2C Memory Mapped registers base address\r
+ //\r
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
+\r
+ //\r
+ // Write to the IC_TAR register the address of the slave device to be addressed\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= ~B_I2C_REG_TAR;\r
+ Data |= I2CAddress;\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+\r
+ //\r
+ // Enable the I2C Controller\r
+ //\r
+ EnableI2CController ();\r
+\r
+ //\r
+ // Write the data and transfer direction to the IC_DATA_CMD register.\r
+ // Also specify that transfer should be terminated by STOP condition.\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= 0xFFFFFF00;\r
+ Data |= (UINT8)Value;\r
+ Data &= ~B_I2C_REG_DATA_CMD_RW;\r
+ Data |= B_I2C_REG_DATA_CMD_STOP;\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+\r
+ //\r
+ // Wait for transfer completion.\r
+ //\r
+ Status = WaitForStopDet ();\r
+\r
+ //\r
+ // Ensure I2C Controller disabled.\r
+ //\r
+ DisableI2CController();\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ The ReadByte() function provides a standard way to execute a\r
+ standard single byte read to an IC2 device (without accessing\r
+ sub-addresses), as defined in the I2C Specification.\r
+\r
+ @param I2CAddress I2C Slave device address\r
+ @param ReturnDataPtr Pointer to location to receive read byte.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ReadByte (\r
+ IN UINTN I2CAddress,\r
+ OUT UINT8 *ReturnDataPtr\r
+ )\r
+{\r
+ UINTN I2CIoPortBaseAddress;\r
+ UINTN Addr;\r
+ UINT32 Data;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Get I2C Memory Mapped registers base address.\r
+ //\r
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
+\r
+ //\r
+ // Write to the IC_TAR register the address of the slave device to be addressed\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= ~B_I2C_REG_TAR;\r
+ Data |= I2CAddress;\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+\r
+ //\r
+ // Enable the I2C Controller\r
+ //\r
+ EnableI2CController ();\r
+\r
+ //\r
+ // Write transfer direction to the IC_DATA_CMD register and\r
+ // specify that transfer should be terminated by STOP condition.\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= 0xFFFFFF00;\r
+ Data |= B_I2C_REG_DATA_CMD_RW;\r
+ Data |= B_I2C_REG_DATA_CMD_STOP;\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+\r
+ //\r
+ // Wait for transfer completion\r
+ //\r
+ Status = WaitForStopDet ();\r
+ if (!EFI_ERROR(Status)) {\r
+\r
+ //\r
+ // Clear RX underflow before reading IC_DATA_CMD.\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+\r
+ //\r
+ // Obtain and return read data byte from RX buffer (IC_DATA_CMD[7:0]).\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= 0x000000FF;\r
+ *ReturnDataPtr = (UINT8) Data;\r
+\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;\r
+ if (Data != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Ensure I2C Controller disabled.\r
+ //\r
+ DisableI2CController ();\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ The WriteMultipleByte() function provides a standard way to execute\r
+ multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or\r
+ when writing block of data), as defined in the I2C Specification.\r
+\r
+ @param I2CAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param WriteBuffer Contains the value of byte to be written to the\r
+ I2C slave device.\r
+\r
+ @param Length No. of bytes to be written.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Tx abort signaled in HW status register.\r
+ @retval EFI_DEVICE_ERROR Tx overflow detected.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WriteMultipleByte (\r
+ IN UINTN I2CAddress,\r
+ IN UINT8 *WriteBuffer,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ UINTN I2CIoPortBaseAddress;\r
+ UINTN Index;\r
+ UINTN Addr;\r
+ UINT32 Data;\r
+ EFI_STATUS Status;\r
+\r
+ if (Length > I2C_FIFO_SIZE) {\r
+ return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size.\r
+ }\r
+\r
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
+\r
+ //\r
+ // Write to the IC_TAR register the address of the slave device to be addressed\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= ~B_I2C_REG_TAR;\r
+ Data |= I2CAddress;\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+\r
+ //\r
+ // Enable the I2C Controller\r
+ //\r
+ EnableI2CController ();\r
+\r
+ //\r
+ // Write the data and transfer direction to the IC_DATA_CMD register.\r
+ // Also specify that transfer should be terminated by STOP condition.\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
+ for (Index = 0; Index < Length; Index++) {\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= 0xFFFFFF00;\r
+ Data |= (UINT8)WriteBuffer[Index];\r
+ Data &= ~B_I2C_REG_DATA_CMD_RW;\r
+ if (Index == (Length-1)) {\r
+ Data |= B_I2C_REG_DATA_CMD_STOP;\r
+ }\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+ }\r
+\r
+ //\r
+ // Wait for transfer completion\r
+ //\r
+ Status = WaitForStopDet ();\r
+\r
+ //\r
+ // Ensure I2C Controller disabled.\r
+ //\r
+ DisableI2CController ();\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ The ReadMultipleByte() function provides a standard way to execute\r
+ multiple byte writes to an IC2 device (e.g. when accessing sub-addresses or\r
+ when reading block of data), as defined in the I2C Specification (I2C combined\r
+ write/read protocol).\r
+\r
+ @param I2CAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param Buffer Contains the value of byte data written or read from the\r
+ I2C slave device.\r
+\r
+ @param WriteLength No. of bytes to be written. In this case data\r
+ written typically contains sub-address or sub-addresses\r
+ in Hi-Lo format, that need to be read (I2C combined\r
+ write/read protocol).\r
+\r
+ @param ReadLength No. of bytes to be read from I2C slave device.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Tx abort signaled in HW status register.\r
+ @retval EFI_DEVICE_ERROR Rx underflow or Rx/Tx overflow detected.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ReadMultipleByte (\r
+ IN UINTN I2CAddress,\r
+ IN OUT UINT8 *Buffer,\r
+ IN UINTN WriteLength,\r
+ IN UINTN ReadLength\r
+ )\r
+{\r
+ UINTN I2CIoPortBaseAddress;\r
+ UINTN Index;\r
+ UINTN Addr;\r
+ UINT32 Data;\r
+ UINT8 PollCount;\r
+ EFI_STATUS Status;\r
+\r
+ if (WriteLength > I2C_FIFO_SIZE || ReadLength > I2C_FIFO_SIZE) {\r
+ return EFI_UNSUPPORTED; // Routine does not handle xfers > fifo size.\r
+ }\r
+\r
+ I2CIoPortBaseAddress = GetI2CIoPortBaseAddress ();\r
+\r
+ //\r
+ // Write to the IC_TAR register the address of the slave device to be addressed\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_TAR;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= ~B_I2C_REG_TAR;\r
+ Data |= I2CAddress;\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+\r
+ //\r
+ // Enable the I2C Controller\r
+ //\r
+ EnableI2CController ();\r
+\r
+ //\r
+ // Write the data (sub-addresses) to the IC_DATA_CMD register.\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
+ for (Index = 0; Index < WriteLength; Index++) {\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= 0xFFFFFF00;\r
+ Data |= (UINT8)Buffer[Index];\r
+ Data &= ~B_I2C_REG_DATA_CMD_RW;\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+ }\r
+\r
+ //\r
+ // Issue Read Transfers for each byte (Restart issued when write/read bit changed).\r
+ //\r
+ for (Index = 0; Index < ReadLength; Index++) {\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data |= B_I2C_REG_DATA_CMD_RW;\r
+ // Issue a STOP for last read transfer.\r
+ if (Index == (ReadLength-1)) {\r
+ Data |= B_I2C_REG_DATA_CMD_STOP;\r
+ }\r
+ *((volatile UINT32 *) (UINTN)(Addr)) = Data;\r
+ }\r
+\r
+ //\r
+ // Wait for STOP condition.\r
+ //\r
+ Status = WaitForStopDet ();\r
+ if (!EFI_ERROR(Status)) {\r
+\r
+ //\r
+ // Poll Receive FIFO Buffer Level register until valid (upto MAX_T_POLL_COUNT times).\r
+ //\r
+ Data = 0;\r
+ PollCount = 0;\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_RXFLR;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ while ((Data != ReadLength) && (PollCount < MAX_T_POLL_COUNT)) {\r
+ MicroSecondDelay(TI2C_POLL);\r
+ PollCount++;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ }\r
+\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+\r
+ //\r
+ // If no timeout or device error then read rx data.\r
+ //\r
+ if (PollCount == MAX_T_POLL_COUNT) {\r
+ Status = EFI_TIMEOUT;\r
+ } else if ((Data & I2C_REG_RAW_INTR_STAT_RX_OVER) != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ } else {\r
+\r
+ //\r
+ // Clear RX underflow before reading IC_DATA_CMD.\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_CLR_RX_UNDER;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+\r
+ //\r
+ // Read data.\r
+ //\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_DATA_CMD;\r
+ for (Index = 0; Index < ReadLength; Index++) {\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= 0x000000FF;\r
+ *(Buffer+Index) = (UINT8)Data;\r
+ }\r
+ Addr = I2CIoPortBaseAddress + I2C_REG_RAW_INTR_STAT;\r
+ Data = *((volatile UINT32 *) (UINTN)(Addr));\r
+ Data &= I2C_REG_RAW_INTR_STAT_RX_UNDER;\r
+ if (Data != 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ } else {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Ensure I2C Controller disabled.\r
+ //\r
+ DisableI2CController ();\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ The I2cWriteByte() function is a wrapper function for the WriteByte function.\r
+ Provides a standard way to execute a standard single byte write to an IC2 device\r
+ (without accessing sub-addresses), as defined in the I2C Specification.\r
+\r
+ @param SlaveAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
+\r
+ @param Buffer Contains the value of byte data to execute to the\r
+ I2C slave device.\r
+\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+I2cWriteByte (\r
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
+ IN EFI_I2C_ADDR_MODE AddrMode,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN I2CAddress;\r
+ UINT16 SaveCmd;\r
+ UINT32 SaveBar0;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ SaveCmd = 0;\r
+ SaveBar0 = 0;\r
+\r
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ I2CAddress = SlaveAddress.I2CDeviceAddress;\r
+ Status = InitializeInternal (AddrMode);\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = WriteByte (I2CAddress, *(UINT8 *) Buffer);\r
+ }\r
+\r
+ I2cCommonServiceExit (SaveCmd, SaveBar0);\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ The I2cReadByte() function is a wrapper function for the ReadByte function.\r
+ Provides a standard way to execute a standard single byte read to an I2C device\r
+ (without accessing sub-addresses), as defined in the I2C Specification.\r
+\r
+ @param SlaveAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
+\r
+ @param Buffer Contains the value of byte data read from the\r
+ I2C slave device.\r
+\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_INVALID_PARAMETER This or Buffer pointers are invalid.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+I2cReadByte (\r
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
+ IN EFI_I2C_ADDR_MODE AddrMode,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN I2CAddress;\r
+ UINT16 SaveCmd;\r
+ UINT32 SaveBar0;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ SaveCmd = 0;\r
+ SaveBar0 =0;\r
+\r
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ I2CAddress = SlaveAddress.I2CDeviceAddress;\r
+\r
+ Status = InitializeInternal (AddrMode);\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = ReadByte (I2CAddress, (UINT8 *) Buffer);\r
+ }\r
+ I2cCommonServiceExit (SaveCmd, SaveBar0);\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ The I2cWriteMultipleByte() function is a wrapper function for the\r
+ WriteMultipleByte() function. Provides a standard way to execute multiple\r
+ byte writes to an I2C device (e.g. when accessing sub-addresses or writing\r
+ block of data), as defined in the I2C Specification.\r
+\r
+ @param SlaveAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
+\r
+ @param Length No. of bytes to be written.\r
+\r
+ @param Buffer Contains the value of byte to be written to the\r
+ I2C slave device.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_INVALID_PARAMETER This, Length or Buffer pointers are invalid.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+I2cWriteMultipleByte (\r
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
+ IN EFI_I2C_ADDR_MODE AddrMode,\r
+ IN UINTN *Length,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN I2CAddress;\r
+ UINT16 SaveCmd;\r
+ UINT32 SaveBar0;\r
+\r
+ if (Buffer == NULL || Length == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ SaveCmd = 0;\r
+ SaveBar0 =0;\r
+\r
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);\r
+ Status = EFI_SUCCESS;\r
+\r
+ I2CAddress = SlaveAddress.I2CDeviceAddress;\r
+\r
+ Status = InitializeInternal (AddrMode);\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = WriteMultipleByte (I2CAddress, Buffer, (*Length));\r
+ }\r
+\r
+ I2cCommonServiceExit (SaveCmd, SaveBar0);\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ The I2cReadMultipleByte() function is a wrapper function for the ReadMultipleByte() function.\r
+ Provides a standard way to execute multiple byte writes to an I2C device\r
+ (e.g. when accessing sub-addresses or when reading block of data), as defined\r
+ in the I2C Specification (I2C combined write/read protocol).\r
+\r
+ @param SlaveAddress The I2C slave address of the device\r
+ with which to communicate.\r
+\r
+ @param AddrMode I2C Addressing Mode: 7-bit or 10-bit address.\r
+\r
+ @param WriteLength No. of bytes to be written. In this case data\r
+ written typically contains sub-address or sub-addresses\r
+ in Hi-Lo format, that need to be read (I2C combined\r
+ write/read protocol).\r
+\r
+ @param ReadLength No. of bytes to be read from I2C slave device.\r
+\r
+ @param Buffer Contains the value of byte data read from the\r
+ I2C slave device.\r
+\r
+ @retval EFI_SUCCESS Transfer success.\r
+ @retval EFI_INVALID_PARAMETER This, WriteLength, ReadLength or Buffer\r
+ pointers are invalid.\r
+ @retval EFI_UNSUPPORTED Unsupported input param.\r
+ @retval EFI_TIMEOUT Timeout while waiting xfer.\r
+ @retval EFI_ABORTED Controller aborted xfer.\r
+ @retval EFI_DEVICE_ERROR Device error detected by controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+I2cReadMultipleByte (\r
+ IN EFI_I2C_DEVICE_ADDRESS SlaveAddress,\r
+ IN EFI_I2C_ADDR_MODE AddrMode,\r
+ IN UINTN *WriteLength,\r
+ IN UINTN *ReadLength,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN I2CAddress;\r
+ UINT16 SaveCmd;\r
+ UINT32 SaveBar0;\r
+\r
+ if (Buffer == NULL || WriteLength == NULL || ReadLength == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ SaveCmd = 0;\r
+ SaveBar0 =0;\r
+\r
+ I2cCommonServiceEntry (&SaveCmd, &SaveBar0);\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ I2CAddress = SlaveAddress.I2CDeviceAddress;\r
+ Status = InitializeInternal (AddrMode);\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = ReadMultipleByte (I2CAddress, Buffer, (*WriteLength), (*ReadLength));\r
+ }\r
+ I2cCommonServiceExit (SaveCmd, SaveBar0);\r
+ return Status;\r
+}\r
+\r
+\r
--- /dev/null
+## @file\r
+# Component description file for Quark South Cluster I2C library.\r
+#\r
+# I2C library implement QuarkSCSocId related drivers, includes:\r
+# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver.\r
+#\r
+# This driver contains I2C bus access routines:\r
+# 1. I2C Read (byte, multi-byte)\r
+# 2. I2C Write (byte, multi-byte)\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = I2cLib\r
+ FILE_GUID = 462d127a-c143-469e-8449-b6e36beb04a8\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = I2cLib\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ CommonHeader.h\r
+ I2cLib.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ PcdLib\r
+ PciLib\r
+ BaseMemoryLib\r
+ MemoryAllocationLib\r
+ DebugLib\r
+ BaseLib\r
+ TimerLib\r
+ IoLib\r
+ IohLib\r
+\r
+[FeaturePcd]\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdI2CFastModeEnabled\r
+\r
+[FixedPcd]\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohI2cMmioBase\r
+\r
+[Pcd]\r
+\r
+[Depex]\r
+ TRUE\r
--- /dev/null
+/** @file\r
+Common header file shared by all source files.\r
+\r
+This file includes package header files, library classes and protocol, PPI & GUID definitions.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+**/\r
+\r
+#ifndef __COMMON_HEADER_H_\r
+#define __COMMON_HEADER_H_\r
+\r
+#include <PiPei.h>\r
+#include <Ioh.h>\r
+#include <IohCommonDefinitions.h>\r
+\r
+#include <Library/IohLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/CpuLib.h>\r
+#include <Library/PciCf8Lib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <IndustryStandard/Pci22.h>\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Lib function for Pei Quark South Cluster.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#include "CommonHeader.h"\r
+\r
+/**\r
+ Program SVID/SID the same as VID/DID*\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeIohSsvidSsid (\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Func\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index <= IOH_PCI_IOSF2AHB_0_MAX_FUNCS; Index++) {\r
+ if (((Device == IOH_PCI_IOSF2AHB_1_DEV_NUM) && (Index >= IOH_PCI_IOSF2AHB_1_MAX_FUNCS))) {\r
+ continue;\r
+ }\r
+\r
+ IohMmPci32(0, Bus, Device, Index, PCI_REG_SVID0) = IohMmPci32(0, Bus, Device, Index, PCI_REG_VID);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/* Enable memory, io, and bus master for USB controller */\r
+VOID\r
+EFIAPI\r
+EnableUsbMemIoBusMaster (\r
+ IN UINT8 UsbBusNumber\r
+ )\r
+{\r
+ UINT16 CmdReg;\r
+\r
+ CmdReg = PciRead16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, PCI_REG_PCICMD));\r
+ CmdReg = (UINT16) (CmdReg | EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_BUS_MASTER);\r
+ PciWrite16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, PCI_REG_PCICMD), CmdReg);\r
+\r
+ CmdReg = PciRead16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, PCI_REG_PCICMD));\r
+ CmdReg = (UINT16) (CmdReg | EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_BUS_MASTER);\r
+ PciWrite16 (PCI_LIB_ADDRESS (UsbBusNumber, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, PCI_REG_PCICMD), CmdReg);\r
+}\r
+\r
+/**\r
+ Read south cluster GPIO input from Port A.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+ReadIohGpioValues (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 GipData;\r
+ UINT32 GipAddr;\r
+ UINT32 TempBarAddr;\r
+ UINT16 SaveCmdReg;\r
+ UINT32 SaveBarReg;\r
+\r
+ TempBarAddr = (UINT32) PcdGet64(PcdIohGpioMmioBase);\r
+\r
+ GipAddr = PCI_LIB_ADDRESS(\r
+ PcdGet8 (PcdIohGpioBusNumber),\r
+ PcdGet8 (PcdIohGpioDevNumber),\r
+ PcdGet8 (PcdIohGpioFunctionNumber), 0);\r
+\r
+ //\r
+ // Save current settings for PCI CMD/BAR registers.\r
+ //\r
+ SaveCmdReg = PciRead16 (GipAddr + PCI_COMMAND_OFFSET);\r
+ SaveBarReg = PciRead32 (GipAddr + PcdGet8 (PcdIohGpioBarRegister));\r
+\r
+ DEBUG ((EFI_D_INFO, "SC GPIO temporary enable at %08X\n", TempBarAddr));\r
+\r
+ // Use predefined tempory memory resource.\r
+ PciWrite32 ( GipAddr + PcdGet8 (PcdIohGpioBarRegister), TempBarAddr);\r
+ PciWrite8 ( GipAddr + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);\r
+\r
+ // Read GPIO configuration\r
+ GipData = MmioRead32(TempBarAddr + GPIO_EXT_PORTA);\r
+\r
+ //\r
+ // Restore settings for PCI CMD/BAR registers.\r
+ //\r
+ PciWrite32 ((GipAddr + PcdGet8 (PcdIohGpioBarRegister)), SaveBarReg);\r
+ PciWrite16 (GipAddr + PCI_COMMAND_OFFSET, SaveCmdReg);\r
+\r
+ // Only 8 bits valid.\r
+ return GipData & 0x000000FF;\r
+}\r
--- /dev/null
+## @file\r
+# Intel Soc Library Instance\r
+#\r
+# Intel Soc Library Instance\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = IohLib\r
+ FILE_GUID = B4C12297-7B19-4523-B165-81374D96716B\r
+ MODULE_TYPE = BASE\r
+ VERSION_STRING = 1.0\r
+ LIBRARY_CLASS = IohLib\r
+\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ IohLib.c\r
+ CommonHeader.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ DebugLib\r
+ PciLib\r
+ IoLib\r
+ PciCf8Lib\r
+ BaseLib\r
+ CpuLib\r
+\r
+[Pcd]\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBusNumber\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioDevNumber\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioFunctionNumber\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioBarRegister\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdIohGpioMmioBase\r
--- /dev/null
+/** @file\r
+\r
+UEFI Component Name(2) protocol implementation for SD controller driver.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SDController.h"\r
+\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSDControllerName = {\r
+ SDControllerGetDriverName,\r
+ SDControllerGetControllerName,\r
+ "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSDControllerName2 = {\r
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SDControllerGetDriverName,\r
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SDControllerGetControllerName,\r
+ "en"\r
+};\r
+\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSDControllerDriverNameTable[] = {\r
+ { "eng;en", L"EFI SD Host Controller Driver" },\r
+ { NULL, NULL }\r
+};\r
+\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 3066 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mSDControllerDriverNameTable,\r
+ DriverName,\r
+ (BOOLEAN)(This == &gSDControllerName)\r
+ );\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 3066 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ SDHOST_DATA *SDHostData;\r
+\r
+ //\r
+ // This is a device driver, so ChildHandle must be NULL.\r
+ //\r
+ if (ChildHandle != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Make sure this driver is currently managing ControllerHandle\r
+ //\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gSDControllerDriverBinding.DriverBindingHandle,\r
+ &gEfiPciIoProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get the device context\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ (VOID **) &SDHostIo,\r
+ gSDControllerDriverBinding.DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS(SDHostIo);\r
+\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ SDHostData->ControllerNameTable,\r
+ ControllerName,\r
+ (BOOLEAN)(This == &gSDControllerName)\r
+ );\r
+\r
+}\r
--- /dev/null
+/** @file\r
+\r
+This file contains the delarations for componet name routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef _COMPONENT_NAME_H_\r
+#define _COMPONENT_NAME_H_\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 3066 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 3066 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+The SD host controller driver model and HC protocol routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#include "SDController.h"\r
+\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gSDControllerDriverBinding = {\r
+ SDControllerSupported,\r
+ SDControllerStart,\r
+ SDControllerStop,\r
+ 0x20,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+\r
+EFI_SD_HOST_IO_PROTOCOL mSDHostIo = {\r
+ EFI_SD_HOST_IO_PROTOCOL_REVISION_01,\r
+ {\r
+ 0, // HighSpeedSupport\r
+ 0, // V18Support\r
+ 0, // V30Support\r
+ 0, // V33Support\r
+ 0, // Reserved0\r
+ 0, // BusWidth4\r
+ 0, // BusWidth8\r
+ 0, // Reserved1\r
+ 0, // Reserved1\r
+ (512 * 1024) //BoundarySize\r
+ },\r
+ SendCommand,\r
+ SetClockFrequency,\r
+ SetBusWidth,\r
+ SetHostVoltage,\r
+ ResetSDHost,\r
+ EnableAutoStopCmd,\r
+ DetectCardAndInitHost,\r
+ SetBlockLength,\r
+ SetHighSpeedMode,\r
+ SetDDRMode\r
+};\r
+\r
+/**\r
+ Find sdclk_freq_sel and upr_sdclk_freq_sel bits\r
+ for Clock Control Register (CLK_CTL)Offset 2Ch when using 8bit or 10bit\r
+ divided clock mode.\r
+\r
+ @param BaseClockFreg Base Clock Frequency in Hz For SD Clock in the\r
+ Capabilities register.\r
+ @param TargetFreq Target Frequency in Hz to reach.\r
+ @param Is8BitMode True if 8-bit Divided Clock Mode else 10bit mode.\r
+ @param Bits sdclk_freq_sel and upr_sdclk_freq_sel bits for\r
+ TargetFreq.\r
+\r
+ @return EFI_SUCCESS // Bits setup.\r
+ @return EFI_UNSUPPORTED // Cannot divide base clock to reach target clock.\r
+**/\r
+EFI_STATUS\r
+DividedClockModeBits (\r
+ IN CONST UINTN BaseClockFreg,\r
+ IN CONST UINTN TargetFreq,\r
+ IN CONST BOOLEAN Is8BitMode,\r
+ OUT UINT16 *Bits\r
+ )\r
+{\r
+ UINTN N;\r
+ UINTN CurrFreq;\r
+\r
+ *Bits = 0;\r
+ CurrFreq = BaseClockFreg;\r
+ N = 0;\r
+ //\r
+ // N == 0 same for 8bit & 10bit mode i.e. BaseClockFreg of controller.\r
+ //\r
+ if (TargetFreq < CurrFreq) {\r
+ if (Is8BitMode) {\r
+ N = 1;\r
+ do {\r
+ //\r
+ // N values for 8bit mode when N > 0.\r
+ // Bit[15:8] SDCLK Frequency Select at offset 2Ch\r
+ // 80h - base clock divided by 256\r
+ // 40h - base clock divided by 128\r
+ // 20h - base clock divided by 64\r
+ // 10h - base clock divided by 32\r
+ // 08h - base clock divided by 16\r
+ // 04h - base clock divided by 8\r
+ // 02h - base clock divided by 4\r
+ // 01h - base clock divided by 2\r
+ //\r
+ CurrFreq = BaseClockFreg / (2 * N);\r
+ if (TargetFreq >= CurrFreq) {\r
+ break;\r
+ }\r
+ N *= 2;\r
+ if (N > V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ } while (TRUE);\r
+ } else {\r
+ N = 1;\r
+ CurrFreq = BaseClockFreg / (2 * N);\r
+ //\r
+ // (try N = 0 or 1 first since don't want divide by 0).\r
+ //\r
+ if (TargetFreq < CurrFreq) {\r
+ //\r
+ // If still no match then calculate it for 10bit.\r
+ // N values for 10bit mode.\r
+ // N 1/2N Divided Clock (Duty 50%).\r
+ // from Spec "The length of divider is extended to 10 bits and all\r
+ // divider values shall be supported.\r
+ //\r
+ N = (BaseClockFreg / TargetFreq) / 2;\r
+\r
+ //\r
+ // Can only be N or N+1;\r
+ //\r
+ CurrFreq = BaseClockFreg / (2 * N);\r
+ if (TargetFreq < CurrFreq) {\r
+ N++;\r
+ CurrFreq = BaseClockFreg / (2 * N);\r
+ }\r
+\r
+ if (N > V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Set upper bits of SDCLK Frequency Select (bits 7:6 of reg 0x2c).\r
+ //\r
+ *Bits |= ((UINT16) ((N >> 2) & B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK));\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Set lower bits of SDCLK Frequency Select (bits 15:8 of reg 0x2c).\r
+ //\r
+ *Bits |= ((UINT16) ((UINT8) N) << 8);\r
+ DEBUG (\r
+ (EFI_D_INFO,\r
+ "SDIO:DividedClockModeBits: %dbit mode Want %dHz Got %dHz bits = %04x\r\n",\r
+ (Is8BitMode) ? 8 : 10,\r
+ TargetFreq,\r
+ CurrFreq,\r
+ (UINTN) *Bits\r
+ ));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Print type of error and command index\r
+\r
+ @param CommandIndex Command index to set the command index field of command register.\r
+ @param ErrorCode Error interrupt status read from host controller\r
+\r
+ @return EFI_DEVICE_ERROR\r
+ @return EFI_TIMEOUT\r
+ @return EFI_CRC_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+GetErrorReason (\r
+ IN UINT16 CommandIndex,\r
+ IN UINT16 ErrorCode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_DEVICE_ERROR;\r
+\r
+ DEBUG((EFI_D_ERROR, "[%2d] -- ", CommandIndex));\r
+\r
+ if (ErrorCode & BIT0) {\r
+ Status = EFI_TIMEOUT;\r
+ DEBUG((EFI_D_ERROR, "Command Timeout Erro"));\r
+ }\r
+\r
+ if (ErrorCode & BIT1) {\r
+ Status = EFI_CRC_ERROR;\r
+ DEBUG((EFI_D_ERROR, "Command CRC Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT2) {\r
+ DEBUG((EFI_D_ERROR, "Command End Bit Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT3) {\r
+ DEBUG((EFI_D_ERROR, "Command Index Error"));\r
+ }\r
+ if (ErrorCode & BIT4) {\r
+ Status = EFI_TIMEOUT;\r
+ DEBUG((EFI_D_ERROR, "Data Timeout Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT5) {\r
+ Status = EFI_CRC_ERROR;\r
+ DEBUG((EFI_D_ERROR, "Data CRC Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT6) {\r
+ DEBUG((EFI_D_ERROR, "Data End Bit Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT7) {\r
+ DEBUG((EFI_D_ERROR, "Current Limit Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT8) {\r
+ DEBUG((EFI_D_ERROR, "Auto CMD12 Error"));\r
+ }\r
+\r
+ if (ErrorCode & BIT9) {\r
+ DEBUG((EFI_D_ERROR, "ADMA Error"));\r
+ }\r
+\r
+ DEBUG((EFI_D_ERROR, "\n"));\r
+\r
+ return Status;\r
+}\r
+/**\r
+ Enable/Disable High Speed transfer mode\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Enable TRUE to Enable, FALSE to Disable\r
+\r
+ @return EFI_SUCCESS\r
+**/\r
+EFI_STATUS\r
+SetHighSpeedMode (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ )\r
+{\r
+ UINT32 Data;\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if (Enable) {\r
+ if (PcdGetBool(PcdSdHciQuirkNoHiSpd)) {\r
+ DEBUG ((EFI_D_INFO, "SDIO: Quirk never set High Speed Enable bit\r\n"));\r
+ return EFI_SUCCESS;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "Enable High Speed transfer mode ... \r\n"));\r
+ Data |= BIT2;\r
+ } else {\r
+ Data &= ~BIT2;\r
+ }\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ return EFI_SUCCESS;\r
+}\r
+EFI_STATUS\r
+EFIAPI\r
+SetDDRMode (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ )\r
+{\r
+ UINT16 Data;\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL2,\r
+ 1,\r
+ &Data\r
+ );\r
+ Data &= 0xFFF0;\r
+ if (Enable) {\r
+ Data |= 0x0004; // Enable DDR50 by default, later should enable other mode like HS200/400\r
+ Data |= BIT3; // Enable 1.8V Signaling\r
+ }\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL2,\r
+ 1,\r
+ &Data\r
+ );\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Power on/off the LED associated with the slot\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Enable TRUE to set LED on, FALSE to set LED off\r
+\r
+ @return EFI_SUCCESS\r
+**/\r
+EFI_STATUS\r
+HostLEDEnable (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 Data;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if (Enable) {\r
+ //\r
+ //LED On\r
+ //\r
+ Data |= BIT0;\r
+ } else {\r
+ //\r
+ //LED Off\r
+ //\r
+ Data &= ~BIT0;\r
+ }\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ The main function used to send the command to the card inserted into the SD host slot.\r
+ It will assemble the arguments to set the command register and wait for the command\r
+ and transfer completed until timeout. Then it will read the response register to fill\r
+ the ResponseData.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param CommandIndex The command index to set the command index field of command register.\r
+ @param Argument Command argument to set the argument field of command register.\r
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.\r
+ @param Buffer Contains the data read from / write to the device.\r
+ @param BufferSize The size of the buffer.\r
+ @param ResponseType RESPONSE_TYPE.\r
+ @param TimeOut Time out value in 1 ms unit.\r
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_OUT_OF_RESOURCES\r
+ @retval EFI_TIMEOUT\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SendCommand (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT16 CommandIndex,\r
+ IN UINT32 Argument,\r
+ IN TRANSFER_TYPE DataType,\r
+ IN UINT8 *Buffer, OPTIONAL\r
+ IN UINT32 BufferSize,\r
+ IN RESPONSE_TYPE ResponseType,\r
+ IN UINT32 TimeOut,\r
+ OUT UINT32 *ResponseData OPTIONAL\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ The main function used to send the command to the card inserted into the SD host\r
+ slot.\r
+ It will assemble the arguments to set the command register and wait for the command\r
+ and transfer completed until timeout. Then it will read the response register to fill\r
+ the ResponseData\r
+\r
+ Arguments:\r
+ This - Pointer to EFI_SD_HOST_IO_PROTOCOL\r
+ CommandIndex - The command index to set the command index field of command register\r
+ Argument - Command argument to set the argument field of command register\r
+ DataType - TRANSFER_TYPE, indicates no data, data in or data out\r
+ Buffer - Contains the data read from / write to the device\r
+ BufferSize - The size of the buffer\r
+ ResponseType - RESPONSE_TYPE\r
+ TimeOut - Time out value in 1 ms unit\r
+ ResponseData - Depending on the ResponseType, such as CSD or card status\r
+\r
+ Returns:\r
+ EFI_SUCCESS\r
+ EFI_INVALID_PARAMETER\r
+ EFI_OUT_OF_RESOURCES\r
+ EFI_TIMEOUT\r
+ EFI_DEVICE_ERROR\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 ResponseDataCount;\r
+ UINT32 Data;\r
+ UINT64 Data64;\r
+ UINT8 Index;\r
+ INTN TimeOut2;\r
+ BOOLEAN AutoCMD12Enable = FALSE;\r
+\r
+\r
+ Status = EFI_SUCCESS;\r
+ ResponseDataCount = 1;\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ AutoCMD12Enable = (CommandIndex & AUTO_CMD12_ENABLE) ? TRUE : FALSE;\r
+ CommandIndex = CommandIndex & CMD_INDEX_MASK;\r
+\r
+ if (Buffer != NULL && DataType == NoData) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ if (((UINTN)Buffer & (This->HostCapability.BoundarySize - 1)) != (UINTN)NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "SendCommand: Command Index = %d \r\n", CommandIndex));\r
+ //\r
+ TimeOut2 = 1000; // 10 ms\r
+ do {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_PSTATE,\r
+ 1,\r
+ &Data\r
+ );\r
+ gBS->Stall (10);\r
+ }while ((TimeOut2-- > 0) && (Data & BIT0));\r
+ TimeOut2 = 1000; // 10 ms\r
+ do {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_PSTATE,\r
+ 1,\r
+ &Data\r
+ );\r
+ gBS->Stall (10);\r
+ }while ((TimeOut2-- > 0) && (Data & BIT1));\r
+ //Clear status bits\r
+ //\r
+ Data = 0xFFFF;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_NINTSTS,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ Data = 0xFFFF;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_ERINTSTS,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+\r
+ if (Buffer != NULL) {\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_DMAADR,\r
+ 1,\r
+ &Buffer\r
+ );\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_BLKSZ,\r
+ 1,\r
+ &Data\r
+ );\r
+ Data &= ~(0xFFF);\r
+ if (BufferSize <= SDHostData->BlockLength) {\r
+ Data |= (BufferSize | 0x7000);\r
+ } else {\r
+ Data |= (SDHostData->BlockLength | 0x7000);\r
+ }\r
+\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_BLKSZ,\r
+ 1,\r
+ &Data\r
+ );\r
+ if (BufferSize <= SDHostData->BlockLength) {\r
+ Data = 1;\r
+ } else {\r
+ Data = BufferSize / SDHostData->BlockLength;\r
+ }\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_BLKCNT,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ } else {\r
+ Data = 0;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_BLKSZ,\r
+ 1,\r
+ &Data\r
+ );\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_BLKCNT,\r
+ 1,\r
+ &Data\r
+ );\r
+ }\r
+\r
+ //\r
+ //Argument\r
+ //\r
+ Data = Argument;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_CMDARG,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_XFRMODE,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+\r
+ DEBUG ((EFI_D_INFO, "Transfer mode read = 0x%x \r\n", (Data & 0xFFFF)));\r
+ //\r
+ //BIT0 - DMA Enable\r
+ //BIT2 - Auto Cmd12\r
+ //\r
+ if (DataType == InData) {\r
+ Data |= BIT4 | BIT0;\r
+ } else if (DataType == OutData){\r
+ Data &= ~BIT4;\r
+ Data |= BIT0;\r
+ } else {\r
+ Data &= ~(BIT4 | BIT0);\r
+ }\r
+\r
+ if (BufferSize <= SDHostData->BlockLength) {\r
+ Data &= ~ (BIT5 | BIT1 | BIT2);\r
+ Data |= BIT1; // Enable block count always\r
+ } else {\r
+ if (SDHostData->IsAutoStopCmd && AutoCMD12Enable) {\r
+ Data |= (BIT5 | BIT1 | BIT2);\r
+ } else {\r
+ Data |= (BIT5 | BIT1);\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Transfer mode write = 0x%x \r\n", (Data & 0xffff)));\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_XFRMODE,\r
+ 1,\r
+ &Data\r
+ );\r
+ //\r
+ //Command\r
+ //\r
+ //ResponseTypeSelect IndexCheck CRCCheck ResponseType\r
+ // 00 0 0 NoResponse\r
+ // 01 0 1 R2\r
+ // 10 0 0 R3, R4\r
+ // 10 1 1 R1, R5, R6, R7\r
+ // 11 1 1 R1b, R5b\r
+ //\r
+ switch (ResponseType) {\r
+ case ResponseNo:\r
+ Data = (CommandIndex << 8);\r
+ ResponseDataCount = 0;\r
+ break;\r
+\r
+ case ResponseR1:\r
+ case ResponseR5:\r
+ case ResponseR6:\r
+ case ResponseR7:\r
+ Data = (CommandIndex << 8) | BIT1 | BIT4| BIT3;\r
+ ResponseDataCount = 1;\r
+ break;\r
+\r
+ case ResponseR1b:\r
+ case ResponseR5b:\r
+ Data = (CommandIndex << 8) | BIT0 | BIT1 | BIT4| BIT3;\r
+ ResponseDataCount = 1;\r
+ break;\r
+\r
+ case ResponseR2:\r
+ Data = (CommandIndex << 8) | BIT0 | BIT3;\r
+ ResponseDataCount = 4;\r
+ break;\r
+\r
+ case ResponseR3:\r
+ case ResponseR4:\r
+ Data = (CommandIndex << 8) | BIT1;\r
+ ResponseDataCount = 1;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (0);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ if (DataType != NoData) {\r
+ Data |= BIT5;\r
+ }\r
+\r
+ HostLEDEnable (This, TRUE);\r
+\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_SDCMD,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+\r
+ Data = 0;\r
+ do {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_ERINTSTS,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if ((Data & 0x07FF) != 0) {\r
+ Status = GetErrorReason (CommandIndex, (UINT16)Data);\r
+ DEBUG ((EFI_D_ERROR, "SendCommand: Error happens \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_NINTSTS,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if ((Data & BIT0) == BIT0) {\r
+ //\r
+ //Command completed, can read response\r
+ //\r
+ if (DataType == NoData) {\r
+ break;\r
+ } else {\r
+ //\r
+ //Transfer completed\r
+ //\r
+ if ((Data & BIT1) == BIT1) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ gBS->Stall (1 * 1000);\r
+\r
+ TimeOut --;\r
+\r
+ } while (TimeOut > 0);\r
+\r
+ if (TimeOut == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ DEBUG ((EFI_D_ERROR, "SendCommand: Time out \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ if (ResponseData != NULL) {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_RESP,\r
+ ResponseDataCount,\r
+ ResponseData\r
+ );\r
+ if (ResponseType == ResponseR2) {\r
+ //\r
+ // Adjustment for R2 response\r
+ //\r
+ Data = 1;\r
+ for (Index = 0; Index < ResponseDataCount; Index++) {\r
+ Data64 = LShiftU64(*ResponseData, 8);\r
+ *ResponseData = (UINT32)((Data64 & 0xFFFFFFFF) | Data);\r
+ Data = (UINT32)RShiftU64 (Data64, 32);\r
+ ResponseData++;\r
+ }\r
+ }\r
+ }\r
+\r
+Exit:\r
+ HostLEDEnable (This, FALSE);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.\r
+ It depends on the max frequency the host can support, divider, and host speed mode.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param MaxFrequency Max frequency in HZ.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetClockFrequency (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 MaxFrequency\r
+ )\r
+{\r
+ UINT32 Data;\r
+ UINT16 FreqSelBits;\r
+ EFI_STATUS Status;\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 TimeOutCount;\r
+ UINT32 Revision;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ Data = 0;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_CTRLRVER,\r
+ 1,\r
+ &Revision\r
+ );\r
+ Revision &= 0x000000FF;\r
+\r
+ Status = DividedClockModeBits (\r
+ SDHostData->BaseClockInMHz * 1000 * 1000,\r
+ MaxFrequency,\r
+ (Revision < SDHCI_SPEC_300),\r
+ &FreqSelBits\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Cannot reach MaxFrequency with SDHostData->BaseClockInMHz.\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+ }\r
+\r
+ Data = 0;\r
+\r
+ //\r
+ //Enable internal clock and Stop Clock Enable\r
+ //\r
+ Data = BIT0;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ TimeOutCount = TIME_OUT_1S;\r
+ do {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ gBS->Stall (1 * 1000);\r
+ TimeOutCount --;\r
+ if (TimeOutCount == 0) {\r
+ DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));\r
+ return EFI_TIMEOUT;\r
+ }\r
+ } while ((Data & BIT1) != BIT1);\r
+\r
+ DEBUG ((EFI_D_INFO, "Base Clock In MHz: %d\r\n", SDHostData->BaseClockInMHz));\r
+\r
+ Data = (BIT0 | ((UINT32) FreqSelBits));\r
+ DEBUG ((EFI_D_INFO, "Data write to MMIO_CLKCTL: 0x%04x \r\n", Data));\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ TimeOutCount = TIME_OUT_1S;\r
+ do {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ gBS->Stall (1 * 1000);\r
+ TimeOutCount --;\r
+ if (TimeOutCount == 0) {\r
+ DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));\r
+ return EFI_TIMEOUT;\r
+ }\r
+ } while ((Data & BIT1) != BIT1);\r
+ gBS->Stall (20 * 1000);\r
+ Data |= BIT2;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Set bus width of the host controller\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param BusWidth Bus width in 1, 4, 8 bits.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetBusWidth (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 BusWidth\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT8 Data;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+\r
+\r
+ if ((BusWidth != 1) && (BusWidth != 4) && (BusWidth != 8)) {\r
+ DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((SDHostData->SDHostIo.HostCapability.BusWidth8 == FALSE) && (BusWidth == 8)) {\r
+ DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ PciIo = SDHostData->PciIo;\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ //\r
+ // BIT5 8-bit MMC Support (MMC8):\r
+ // If set, IOH supports 8-bit MMC. When cleared, IOH does not support this feature\r
+ //\r
+ if (BusWidth == 8) {\r
+ DEBUG ((EFI_D_INFO, "Bus Width is 8-bit ... \r\n"));\r
+ Data |= BIT5;\r
+ } else if (BusWidth == 4) {\r
+ DEBUG ((EFI_D_INFO, "Bus Width is 4-bit ... \r\n"));\r
+ Data &= ~BIT5;\r
+ Data |= BIT1;\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Bus Width is 1-bit ... \r\n"));\r
+ Data &= ~BIT5;\r
+ Data &= ~BIT1;\r
+ }\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_HOSTCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Set voltage which could supported by the host controller.\r
+ Support 0(Power off the host), 1.8V, 3.0V, 3.3V\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Voltage Units in 0.1 V.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetHostVoltage (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 Voltage\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT8 Data;\r
+ EFI_STATUS Status;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ Status = EFI_SUCCESS;\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_PWRCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if (Voltage == 0) {\r
+ //\r
+ //Power Off the host\r
+ //\r
+ Data &= ~BIT0;\r
+ } else if (Voltage <= 18 && This->HostCapability.V18Support) {\r
+ //\r
+ //1.8V\r
+ //\r
+ Data |= (BIT1 | BIT3 | BIT0);\r
+ } else if (Voltage > 18 && Voltage <= 30 && This->HostCapability.V30Support) {\r
+ //\r
+ //3.0V\r
+ //\r
+ Data |= (BIT2 | BIT3 | BIT0);\r
+ } else if (Voltage > 30 && Voltage <= 33 && This->HostCapability.V33Support) {\r
+ //\r
+ //3.3V\r
+ //\r
+ Data |= (BIT1 | BIT2 | BIT3 | BIT0);\r
+ } else {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Exit;\r
+ }\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_PWRCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ gBS->Stall (10 * 1000);\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Reset the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param ResetAll TRUE to reset all.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ResetSDHost (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN RESET_TYPE ResetType\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 Data;\r
+ UINT16 ErrStatus;\r
+ UINT32 Mask;\r
+ UINT32 TimeOutCount;\r
+ UINT16 SaveClkCtl;\r
+ UINT16 ZeroClkCtl;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ Mask = 0;\r
+ ErrStatus = 0;\r
+\r
+ if (ResetType == Reset_Auto) {\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_ERINTSTS,\r
+ 1,\r
+ &ErrStatus\r
+ );\r
+ if ((ErrStatus & 0xF) != 0) {\r
+ //\r
+ //Command Line\r
+ //\r
+ Mask |= BIT1;\r
+ }\r
+ if ((ErrStatus & 0x70) != 0) {\r
+ //\r
+ //Data Line\r
+ //\r
+ Mask |= BIT2;\r
+ }\r
+ }\r
+\r
+\r
+ if (ResetType == Reset_DAT || ResetType == Reset_DAT_CMD) {\r
+ Mask |= BIT2;\r
+ }\r
+ if (ResetType == Reset_CMD || ResetType == Reset_DAT_CMD) {\r
+ Mask |= BIT1;\r
+ }\r
+ if (ResetType == Reset_All) {\r
+ Mask = BIT0;\r
+ }\r
+\r
+ if (Mask == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // To improve SD stability, we zero the MMIO_CLKCTL register and\r
+ // stall for 50 microseconds before reseting the controller. We\r
+ // restore the register setting following the reset operation.\r
+ //\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &SaveClkCtl\r
+ );\r
+\r
+ ZeroClkCtl = (UINT16) 0;\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &ZeroClkCtl\r
+ );\r
+\r
+ gBS->Stall (50);\r
+\r
+ //\r
+ // Reset the SD host controller\r
+ //\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_SWRST,\r
+ 1,\r
+ &Mask\r
+ );\r
+\r
+ Data = 0;\r
+ TimeOutCount = TIME_OUT_1S;\r
+ do {\r
+\r
+ gBS->Stall (1 * 1000);\r
+\r
+ TimeOutCount --;\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_SWRST,\r
+ 1,\r
+ &Data\r
+ );\r
+ if ((Data & Mask) == 0) {\r
+ break;\r
+ }\r
+ } while (TimeOutCount > 0);\r
+\r
+ //\r
+ // We now restore the MMIO_CLKCTL register which we set to 0 above.\r
+ //\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CLKCTL,\r
+ 1,\r
+ &SaveClkCtl\r
+ );\r
+\r
+ if (TimeOutCount == 0) {\r
+ DEBUG ((EFI_D_ERROR, "ResetSDHost: Time out \r\n"));\r
+ return EFI_TIMEOUT;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Enable auto stop on the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Enable TRUE to enable, FALSE to disable.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EnableAutoStopCmd (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+\r
+ SDHostData->IsAutoStopCmd = Enable;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Set the Block length on the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param BlockLength card supportes block length.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetBlockLength (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 BlockLength\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+\r
+ DEBUG ((EFI_D_INFO, "Block length on the host controller: %d \r\n", BlockLength));\r
+ SDHostData->BlockLength = BlockLength;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Find whether these is a card inserted into the slot. If so init the host.\r
+ If not, return EFI_NOT_FOUND.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_NOT_FOUND\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DetectCardAndInitHost (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This\r
+ )\r
+{\r
+ SDHOST_DATA *SDHostData;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 Data;\r
+ EFI_STATUS Status;\r
+ UINT8 Voltages[] = { 33, 30, 18 };\r
+ UINTN Loop;\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+ PciIo = SDHostData->PciIo;\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ Data = 0;\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_PSTATE,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if ((Data & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) {\r
+ //\r
+ // Has no card inserted\r
+ //\r
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: No Cards \r\n"));\r
+ Status = EFI_NOT_FOUND;\r
+ goto Exit;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: Find Cards \r\n"));\r
+\r
+ Status = EFI_NOT_FOUND;\r
+ for (Loop = 0; Loop < sizeof (Voltages); Loop++) {\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "DetectCardAndInitHost: SetHostVoltage %d.%dV \r\n",\r
+ Voltages[Loop] / 10,\r
+ Voltages[Loop] % 10\r
+ ));\r
+ Status = SetHostVoltage (This, Voltages[Loop]);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [failed]\n"));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [success]\n"));\r
+ break;\r
+ }\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set voltage \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ Status = SetClockFrequency (This, FREQUENCY_OD);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set frequency \r\n"));\r
+ goto Exit;\r
+ }\r
+ SetBusWidth (This, 1);\r
+\r
+ //\r
+ //Enable normal status change\r
+ //\r
+\r
+ Data = (BIT0 | BIT1);\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_NINTEN,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ //\r
+ //Enable error status change\r
+ //\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_ERINTEN,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ Data |= (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8);\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_ERINTEN,\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ //\r
+ //Data transfer Timeout control\r
+ //\r
+ Data = 0x0E;\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ 0,\r
+ (UINT64)MMIO_TOCTL,\r
+ 1,\r
+ &Data\r
+ );\r
+ //\r
+ //Set Default Bus width as 1 bit\r
+ //\r
+\r
+Exit:\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+ Entry point for EFI drivers.\r
+\r
+ @param ImageHandle EFI_HANDLE.\r
+ @param SystemTable EFI_SYSTEM_TABLE.\r
+\r
+ @retval EFI_SUCCESS Driver is successfully loaded.\r
+ @return Others Failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSDController (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ return EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gSDControllerDriverBinding,\r
+ ImageHandle,\r
+ &gSDControllerName,\r
+ &gSDControllerName2\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle. Any\r
+ ControllerHandle that has SDHostIoProtocol installed will be supported.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @return EFI_SUCCESS This driver supports this device.\r
+ @return EFI_UNSUPPORTED This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS OpenStatus;\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ PCI_CLASSC PciClass;\r
+ EFI_SD_HOST_IO_PROTOCOL *SdHostIo;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ (VOID **)&SdHostIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG (( DEBUG_INFO, "SdHost controller is already started\n"));\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ //\r
+ // Test whether there is PCI IO Protocol attached on the controller handle.\r
+ //\r
+ OpenStatus = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (OpenStatus)) {\r
+ return OpenStatus;\r
+ }\r
+\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ PCI_CLASSCODE_OFFSET,\r
+ sizeof (PCI_CLASSC) / sizeof (UINT8),\r
+ &PciClass\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Test whether the controller belongs to SD type\r
+ //\r
+ if ((PciClass.BaseCode != PCI_CLASS_SYSTEM_PERIPHERAL) ||\r
+ (PciClass.SubClassCode != PCI_SUBCLASS_SD_HOST_CONTROLLER) ||\r
+ ((PciClass.PI != PCI_IF_STANDARD_HOST_NO_DMA) && (PciClass.PI != PCI_IF_STANDARD_HOST_SUPPORT_DMA))\r
+ ) {\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+\r
+ON_EXIT:\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+}\r
+/**\r
+ Starting the SD Host Controller Driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_UNSUPPORTED This driver does not support this device.\r
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ SDHOST_DATA *SDHostData;\r
+ UINT32 Data;\r
+\r
+\r
+ SDHostData = NULL;\r
+ Data = 0;\r
+\r
+ //\r
+ // Open PCI I/O Protocol and save pointer to open protocol\r
+ // in private data area.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Enable the SD Host Controller MMIO space\r
+ //\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ EFI_PCI_DEVICE_ENABLE,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+\r
+ SDHostData = (SDHOST_DATA*)AllocateZeroPool(sizeof (SDHOST_DATA));\r
+ if (SDHostData == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ SDHostData->Signature = SDHOST_DATA_SIGNATURE;\r
+ SDHostData->PciIo = PciIo;\r
+\r
+ CopyMem (&SDHostData->SDHostIo, &mSDHostIo, sizeof (EFI_SD_HOST_IO_PROTOCOL));\r
+\r
+ ResetSDHost (&SDHostData->SDHostIo, Reset_All);\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ 0,\r
+ (UINT64)MMIO_CTRLRVER,\r
+ 1,\r
+ &Data\r
+ );\r
+ SDHostData->SDHostIo.HostCapability.HostVersion = Data & 0xFF;\r
+ DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: HostVersion 0x%x \r\n", SDHostData->SDHostIo.HostCapability.HostVersion));\r
+\r
+ PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ 0,\r
+ (UINT64)MMIO_CAP,\r
+ 1,\r
+ &Data\r
+ );\r
+ DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: MMIO_CAP 0x%x \r\n", Data));\r
+ if ((Data & BIT18) != 0) {\r
+ SDHostData->SDHostIo.HostCapability.BusWidth8 = TRUE;\r
+ }\r
+\r
+ if ((Data & BIT21) != 0) {\r
+ SDHostData->SDHostIo.HostCapability.HighSpeedSupport = TRUE;\r
+ }\r
+\r
+ if ((Data & BIT24) != 0) {\r
+ SDHostData->SDHostIo.HostCapability.V33Support = TRUE;\r
+ }\r
+\r
+ if ((Data & BIT25) != 0) {\r
+ SDHostData->SDHostIo.HostCapability.V30Support = TRUE;\r
+ }\r
+\r
+ if ((Data & BIT26) != 0) {\r
+ SDHostData->SDHostIo.HostCapability.V18Support = TRUE;\r
+ }\r
+\r
+ SDHostData->SDHostIo.HostCapability.BusWidth4 = TRUE;\r
+\r
+ if(SDHostData->SDHostIo.HostCapability.HostVersion < SDHCI_SPEC_300) {\r
+\r
+\r
+\r
+ SDHostData->BaseClockInMHz = (Data >> 8) & 0x3F;\r
+ }\r
+ else {\r
+ SDHostData->BaseClockInMHz = (Data >> 8) & 0xFF;\r
+\r
+ }\r
+\r
+ SDHostData->BlockLength = 512 << ((Data >> 16) & 0x03);\r
+ DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: BlockLength 0x%x \r\n", SDHostData->BlockLength));\r
+ SDHostData->IsAutoStopCmd = TRUE;\r
+\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &SDHostData->SDHostIo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Install the component name protocol\r
+ //\r
+ SDHostData->ControllerNameTable = NULL;\r
+\r
+ AddUnicodeString2 (\r
+ "eng",\r
+ gSDControllerName.SupportedLanguages,\r
+ &SDHostData->ControllerNameTable,\r
+ L"SD Host Controller",\r
+ TRUE\r
+ );\r
+ AddUnicodeString2 (\r
+ "en",\r
+ gSDControllerName2.SupportedLanguages,\r
+ &SDHostData->ControllerNameTable,\r
+ L"SD Host Controller",\r
+ FALSE\r
+ );\r
+\r
+Exit:\r
+ if (EFI_ERROR (Status)) {\r
+ if (SDHostData != NULL) {\r
+ FreePool (SDHostData);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop this driver on ControllerHandle. Support stoping any child handles\r
+ created by this driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to stop driver on.\r
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
+ @param ChildHandleBuffer List of handles for the children we need to stop.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ SDHOST_DATA *SDHostData;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ (VOID **) &SDHostIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ //\r
+ // Test whether the Controller handler passed in is a valid\r
+ // Usb controller handle that should be supported, if not,\r
+ // return the error status directly\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ SetHostVoltage (SDHostIo, 0);\r
+\r
+ SDHostData = SDHOST_DATA_FROM_THIS(SDHostIo);\r
+\r
+ //\r
+ // Uninstall Block I/O protocol from the device handle\r
+ //\r
+ Status = gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ SDHostIo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ FreeUnicodeStringTable (SDHostData->ControllerNameTable);\r
+\r
+ FreePool (SDHostData);\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
--- /dev/null
+/** @file\r
+\r
+The definition for SD host controller driver model and HC protocol routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_CONTROLLER_H_\r
+#define _SD_CONTROLLER_H_\r
+\r
+\r
+#include <Uefi.h>\r
+\r
+\r
+#include <Protocol/PciIo.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <IndustryStandard/Pci22.h>\r
+\r
+\r
+#include "ComponentName.h"\r
+#include "SDHostIo.h"\r
+\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL gSDControllerDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gSDControllerName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gSDControllerName2;\r
+\r
+\r
+#define SDHOST_DATA_SIGNATURE SIGNATURE_32 ('s', 'd', 'h', 's')\r
+\r
+#define BLOCK_SIZE 0x200\r
+#define TIME_OUT_1S 1000\r
+\r
+#pragma pack(1)\r
+//\r
+// PCI Class Code structure\r
+//\r
+typedef struct {\r
+ UINT8 PI;\r
+ UINT8 SubClassCode;\r
+ UINT8 BaseCode;\r
+} PCI_CLASSC;\r
+\r
+#pragma pack()\r
+\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EFI_SD_HOST_IO_PROTOCOL SDHostIo;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ BOOLEAN IsAutoStopCmd;\r
+ UINT32 BaseClockInMHz;\r
+ UINT32 CurrentClockInKHz;\r
+ UINT32 BlockLength;\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+}SDHOST_DATA;\r
+\r
+#define SDHOST_DATA_FROM_THIS(a) \\r
+ CR(a, SDHOST_DATA, SDHostIo, SDHOST_DATA_SIGNATURE)\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle. Any\r
+ ControllerHandle that has SDHostIoProtocol installed will be supported.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @return EFI_SUCCESS This driver supports this device.\r
+ @return EFI_UNSUPPORTED This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Starting the SD Host Controller Driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_UNSUPPORTED This driver does not support this device.\r
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Stop this driver on ControllerHandle. Support stoping any child handles\r
+ created by this driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to stop driver on.\r
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
+ @param ChildHandleBuffer List of handles for the children we need to stop.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+/**\r
+ The main function used to send the command to the card inserted into the SD host slot.\r
+ It will assemble the arguments to set the command register and wait for the command\r
+ and transfer completed until timeout. Then it will read the response register to fill\r
+ the ResponseData.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param CommandIndex The command index to set the command index field of command register.\r
+ @param Argument Command argument to set the argument field of command register.\r
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.\r
+ @param Buffer Contains the data read from / write to the device.\r
+ @param BufferSize The size of the buffer.\r
+ @param ResponseType RESPONSE_TYPE.\r
+ @param TimeOut Time out value in 1 ms unit.\r
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_OUT_OF_RESOURCES\r
+ @retval EFI_TIMEOUT\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SendCommand (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT16 CommandIndex,\r
+ IN UINT32 Argument,\r
+ IN TRANSFER_TYPE DataType,\r
+ IN UINT8 *Buffer, OPTIONAL\r
+ IN UINT32 BufferSize,\r
+ IN RESPONSE_TYPE ResponseType,\r
+ IN UINT32 TimeOut,\r
+ OUT UINT32 *ResponseData OPTIONAL\r
+ );\r
+\r
+/**\r
+ Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.\r
+ It depends on the max frequency the host can support, divider, and host speed mode.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param MaxFrequency Max frequency in HZ.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetClockFrequency (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 MaxFrequencyInKHz\r
+ );\r
+\r
+/**\r
+ Set bus width of the host controller\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param BusWidth Bus width in 1, 4, 8 bits.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetBusWidth (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 BusWidth\r
+ );\r
+\r
+\r
+/**\r
+ Set voltage which could supported by the host controller.\r
+ Support 0(Power off the host), 1.8V, 3.0V, 3.3V\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Voltage Units in 0.1 V.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetHostVoltage (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 Voltage\r
+ );\r
+\r
+\r
+/**\r
+ Reset the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param ResetAll TRUE to reset all.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ResetSDHost (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN RESET_TYPE ResetType\r
+ );\r
+\r
+\r
+/**\r
+ Enable auto stop on the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Enable TRUE to enable, FALSE to disable.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EnableAutoStopCmd (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ );\r
+\r
+/**\r
+ Find whether these is a card inserted into the slot. If so init the host.\r
+ If not, return EFI_NOT_FOUND.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_NOT_FOUND\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DetectCardAndInitHost (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This\r
+ );\r
+\r
+/**\r
+ Set the Block length on the host controller.\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param BlockLength card supportes block length.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetBlockLength (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN UINT32 BlockLength\r
+ );\r
+\r
+/**\r
+ Enable/Disable High Speed transfer mode\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param Enable TRUE to Enable, FALSE to Disable\r
+\r
+ @return EFI_SUCCESS\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetHighSpeedMode (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SetDDRMode (\r
+ IN EFI_SD_HOST_IO_PROTOCOL *This,\r
+ IN BOOLEAN Enable\r
+ );\r
+#endif\r
--- /dev/null
+## @file\r
+#\r
+# Component Description File For SDControllerDxe Module.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SDController\r
+ FILE_GUID = 90A330BD-6F89-4900-933A-C25EB4356348\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = InitializeSDController\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+# DRIVER_BINDING = gSDControllerDriverBinding\r
+# COMPONENT_NAME = gSDControllerName\r
+# COMPONENT_NAME2 = gSDControllerName2\r
+#\r
+\r
+[Sources]\r
+ SDController.c\r
+ SDController.h\r
+ ComponentName.c\r
+ ComponentName.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ MemoryAllocationLib\r
+ BaseLib\r
+ UefiLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ BaseMemoryLib\r
+ DebugLib\r
+ PcdLib\r
+\r
+[Protocols]\r
+ gEfiPciIoProtocolGuid ## TO_START\r
+ gEfiSDHostIoProtocolGuid ## BY_START\r
+\r
+[FeaturePcd]\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdSdHciQuirkNoHiSpd\r
+\r
--- /dev/null
+/** @file\r
+\r
+CEATA specific functions implementation\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SDMediaDevice.h"\r
+\r
+/**\r
+ Send RW_MULTIPLE_REGISTER command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param Address Register address.\r
+ @param ByteCount Buffer size.\r
+ @param Write TRUE means write, FALSE means read.\r
+ @param Buffer Buffer pointer.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+ReadWriteMultipleRegister (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT16 Address,\r
+ IN UINT8 ByteCount,\r
+ IN BOOLEAN Write,\r
+ IN UINT8 *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Argument;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if ((Address % 4 != 0) || (ByteCount % 4 != 0)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ Argument = (Address << 16) | ByteCount;\r
+ if (Write) {\r
+ Argument |= BIT31;\r
+ }\r
+\r
+\r
+ if (Write) {\r
+ CopyMem (CardData->AlignedBuffer, Buffer, ByteCount);\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ RW_MULTIPLE_REGISTER,\r
+ Argument,\r
+ OutData,\r
+ CardData->AlignedBuffer,\r
+ ByteCount,\r
+ ResponseR1b,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ } else {\r
+ Status = SendCommand (\r
+ CardData,\r
+ RW_MULTIPLE_REGISTER,\r
+ Argument,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ ByteCount,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem (Buffer, CardData->AlignedBuffer, ByteCount);\r
+ }\r
+\r
+ }\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send ReadWriteMultipleBlock command with RW_MULTIPLE_REGISTER command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param DataUnitCount Buffer size in 512 bytes unit.\r
+ @param Write TRUE means write, FALSE means read.\r
+ @param Buffer Buffer pointer.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+ReadWriteMultipleBlock (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT16 DataUnitCount,\r
+ IN BOOLEAN Write,\r
+ IN UINT8 *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT32 TransferLength;\r
+\r
+ Status = EFI_SUCCESS;\r
+ SDHostIo = CardData->SDHostIo;\r
+\r
+ TransferLength = DataUnitCount * DATA_UNIT_SIZE;\r
+ if (TransferLength > SDHostIo->HostCapability.BoundarySize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Write) {\r
+ CopyMem (CardData->AlignedBuffer, Buffer, TransferLength);\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ RW_MULTIPLE_BLOCK,\r
+ (DataUnitCount | BIT31),\r
+ OutData,\r
+ CardData->AlignedBuffer,\r
+ TransferLength,\r
+ ResponseR1b,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ } else {\r
+ Status = SendCommand (\r
+ CardData,\r
+ RW_MULTIPLE_BLOCK,\r
+ DataUnitCount,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ TransferLength,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ CopyMem (Buffer, CardData->AlignedBuffer, TransferLength);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send software reset\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+SoftwareReset (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Data;\r
+ UINT32 TimeOut;\r
+\r
+ Data = BIT2;\r
+\r
+ Status = FastIO (CardData, Reg_Control, &Data, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ TimeOut = 5 * 1000;\r
+\r
+ do {\r
+ gBS->Stall (1 * 1000);\r
+ Status = FastIO (CardData, Reg_Control, &Data, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ if ((Data & BIT2) == BIT2) {\r
+ break;\r
+ }\r
+\r
+ TimeOut--;\r
+ } while (TimeOut > 0);\r
+\r
+ if (TimeOut == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ goto Exit;\r
+ }\r
+\r
+ Data &= ~BIT2;\r
+ Status = FastIO (CardData, Reg_Control, &Data, TRUE);\r
+\r
+ TimeOut = 5 * 1000;\r
+\r
+ do {\r
+ gBS->Stall (1 * 1000);\r
+ Status = FastIO (CardData, Reg_Control, &Data, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ if ((Data & BIT2) != BIT2) {\r
+ break;\r
+ }\r
+\r
+ TimeOut--;\r
+ } while (TimeOut > 0);\r
+\r
+\r
+ if (TimeOut == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ goto Exit;\r
+ }\r
+\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ SendATACommand specificed in Taskfile\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param TaskFile Pointer to TASK_FILE.\r
+ @param Write TRUE means write, FALSE means read.\r
+ @param Buffer If NULL, means no data transfer, neither read nor write.\r
+ @param SectorCount Buffer size in 512 bytes unit.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+SendATACommand (\r
+ IN CARD_DATA *CardData,\r
+ IN TASK_FILE *TaskFile,\r
+ IN BOOLEAN Write,\r
+ IN UINT8 *Buffer,\r
+ IN UINT16 SectorCount\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT8 Data;\r
+ UINT32 TimeOut;\r
+\r
+ SDHostIo = CardData->SDHostIo;\r
+\r
+ //\r
+ //Write register\r
+ //\r
+ Status = ReadWriteMultipleRegister (\r
+ CardData,\r
+ 0,\r
+ sizeof (TASK_FILE),\r
+ TRUE,\r
+ (UINT8*)TaskFile\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ TimeOut = 5000;\r
+ do {\r
+ gBS->Stall (1 * 1000);\r
+ Data = 0;\r
+ Status = FastIO (\r
+ CardData,\r
+ Reg_Command_Status,\r
+ &Data,\r
+ FALSE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (((Data & BIT7) == 0) && ((Data & BIT6) == BIT6)) {\r
+ break;\r
+ }\r
+\r
+ TimeOut --;\r
+ } while (TimeOut > 0);\r
+\r
+ if (TimeOut == 0) {\r
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleRegister FastIO EFI_TIMEOUT 0x%x\n", Data));\r
+ Status = EFI_TIMEOUT;\r
+ goto Exit;\r
+ }\r
+\r
+\r
+ if (Buffer != NULL) {\r
+ Status = ReadWriteMultipleBlock (\r
+ CardData,\r
+ SectorCount,\r
+ Write,\r
+ (UINT8*)Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock EFI_TIMEOUT 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ TimeOut = 5 * 1000;\r
+ do {\r
+ gBS->Stall (1 * 1000);\r
+\r
+ Data = 0;\r
+ Status = FastIO (\r
+ CardData,\r
+ Reg_Command_Status,\r
+ &Data,\r
+ FALSE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (((Data & BIT7) == 0) && ((Data & BIT3) == 0)) {\r
+ break;\r
+ }\r
+\r
+ TimeOut --;\r
+ } while (TimeOut > 0);\r
+ if (TimeOut == 0) {\r
+ DEBUG((EFI_D_ERROR, "ReadWriteMultipleBlock FastIO EFI_TIMEOUT 0x%x\n", Data));\r
+ Status = EFI_TIMEOUT;\r
+ goto Exit;\r
+ }\r
+\r
+\r
+ if (((Data & BIT6) == BIT6) && (Data & BIT0) == 0) {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+Exit:\r
+ if (EFI_ERROR (Status)) {\r
+ SoftwareReset (CardData);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ IDENTIFY_DEVICE command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+IndentifyDevice (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));\r
+\r
+ //\r
+ //The host only supports nIEN = 0\r
+ //\r
+ CardData->TaskFile.Command_Status = IDENTIFY_DEVICE;\r
+\r
+\r
+ Status = SendATACommand (\r
+ CardData,\r
+ &CardData->TaskFile,\r
+ FALSE,\r
+ (UINT8*)&(CardData->IndentifyDeviceData),\r
+ 1\r
+ );\r
+\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ FLUSH_CACHE_EXT command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+FlushCache (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+\r
+ //\r
+ //Hitachi CE-ATA will always make the busy high after\r
+ //receving this command\r
+ //\r
+/*\r
+ EFI_STATUS Status;\r
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));\r
+ //\r
+ //The host only supports nIEN = 0\r
+ //\r
+ CardData->TaskFile.Command_Status = FLUSH_CACHE_EXT;\r
+\r
+ Status = SendATACommand (\r
+ CardData,\r
+ &CardData->TaskFile,\r
+ FALSE,\r
+ NULL,\r
+ 0\r
+ );\r
+*/\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ STANDBY_IMMEDIATE command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+StandByImmediate (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));\r
+ //\r
+ //The host only supports nIEN = 0\r
+ //\r
+ CardData->TaskFile.Command_Status = STANDBY_IMMEDIATE;\r
+\r
+\r
+ Status = SendATACommand (\r
+ CardData,\r
+ &CardData->TaskFile,\r
+ FALSE,\r
+ NULL,\r
+ 0\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ READ_DMA_EXT command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller\r
+ is responsible for either having implicit or explicit ownership\r
+ of the buffer.\r
+ @param SectorCount Size in 512 bytes unit.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+ReadDMAExt (\r
+ IN CARD_DATA *CardData,\r
+ IN EFI_LBA LBA,\r
+ IN UINT8 *Buffer,\r
+ IN UINT16 SectorCount\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));\r
+ //\r
+ //The host only supports nIEN = 0\r
+ //\r
+ CardData->TaskFile.Command_Status = READ_DMA_EXT;\r
+\r
+ CardData->TaskFile.SectorCount = (UINT8)SectorCount;\r
+ CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8);\r
+\r
+ CardData->TaskFile.LBALow = (UINT8)LBA;\r
+ CardData->TaskFile.LBAMid = (UINT8)RShiftU64(LBA, 8);\r
+ CardData->TaskFile.LBAHigh = (UINT8)RShiftU64(LBA, 16);\r
+\r
+ CardData->TaskFile.LBALow_Exp = (UINT8)RShiftU64(LBA, 24);\r
+ CardData->TaskFile.LBAMid_Exp = (UINT8)RShiftU64(LBA, 32);\r
+ CardData->TaskFile.LBAHigh_Exp = (UINT8)RShiftU64(LBA, 40);\r
+\r
+ Status = SendATACommand (\r
+ CardData,\r
+ &CardData->TaskFile,\r
+ FALSE,\r
+ Buffer,\r
+ SectorCount\r
+ );\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+ WRITE_DMA_EXT command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller\r
+ is responsible for either having implicit or explicit ownership\r
+ of the buffer.\r
+ @param SectorCount Size in 512 bytes unit.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+WriteDMAExt (\r
+ IN CARD_DATA *CardData,\r
+ IN EFI_LBA LBA,\r
+ IN UINT8 *Buffer,\r
+ IN UINT16 SectorCount\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));\r
+ //\r
+ //The host only supports nIEN = 0\r
+ //\r
+ CardData->TaskFile.Command_Status = WRITE_DMA_EXT;\r
+\r
+ CardData->TaskFile.SectorCount = (UINT8)SectorCount;\r
+ CardData->TaskFile.SectorCount_Exp = (UINT8)(SectorCount >> 8);\r
+\r
+ CardData->TaskFile.LBALow = (UINT8)LBA;\r
+ CardData->TaskFile.LBAMid = (UINT8)RShiftU64(LBA, 8);\r
+ CardData->TaskFile.LBAHigh = (UINT8)RShiftU64(LBA, 16);\r
+\r
+ CardData->TaskFile.LBALow_Exp = (UINT8)RShiftU64(LBA, 24);\r
+ CardData->TaskFile.LBAMid_Exp = (UINT8)RShiftU64(LBA, 32);\r
+ CardData->TaskFile.LBAHigh_Exp = (UINT8)RShiftU64(LBA, 40);\r
+\r
+ Status = SendATACommand (\r
+ CardData,\r
+ &CardData->TaskFile,\r
+ TRUE,\r
+ Buffer,\r
+ SectorCount\r
+ );\r
+ return Status;\r
+\r
+}\r
+\r
+\r
+/**\r
+ Judge whether it is CE-ATA device or not.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval TRUE\r
+ @retval FALSE\r
+\r
+**/\r
+BOOLEAN\r
+IsCEATADevice (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = ReadWriteMultipleRegister (\r
+ CardData,\r
+ 0,\r
+ sizeof (TASK_FILE),\r
+ FALSE,\r
+ (UINT8*)&CardData->TaskFile\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ //To bring back the normal MMC card to work\r
+ //\r
+ CardData->SDHostIo->ResetSDHost (CardData->SDHostIo, Reset_DAT_CMD);\r
+ return FALSE;\r
+ }\r
+\r
+ if (CardData->TaskFile.LBAMid == CE_ATA_SIG_CE &&\r
+ CardData->TaskFile.LBAHigh == CE_ATA_SIG_AA\r
+ ) {\r
+ //\r
+ //Disable Auto CMD for CE-ATA\r
+ //\r
+ CardData->SDHostIo->EnableAutoStopCmd (CardData->SDHostIo, FALSE);\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+\r
+\r
--- /dev/null
+/** @file\r
+\r
+Block I/O protocol for CE-ATA device\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SDMediaDevice.h"\r
+\r
+/**\r
+ Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive.\r
+ verification operation of the device during reset.\r
+ (This parameter is ingored in this driver.)\r
+\r
+ @retval EFI_SUCCESS Success\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CEATABlockReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CARD_DATA *CardData;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+\r
+ CardData = CARD_DATA_FROM_THIS(This);\r
+ SDHostIo = CardData->SDHostIo;\r
+\r
+ if (!ExtendedVerification) {\r
+ Status = SoftwareReset (CardData);\r
+ } else {\r
+ Status = SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "CEATABlockReset: Fail to ResetSDHost\n" ));\r
+ return Status;\r
+ }\r
+ Status = MMCSDCardInit (CardData);\r
+ }\r
+\r
+\r
+ return Status;\r
+\r
+ }\r
+\r
+/**\r
+ Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+ @param MediaId The media id that the write request is for.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ The caller is responsible for writing to only legitimate locations.\r
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple of the\r
+ intrinsic block size of the device.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller\r
+ is responsible for either having implicit or explicit ownership\r
+ of the buffer.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CEATABlockReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CARD_DATA *CardData;\r
+ UINT32 TransferSize;\r
+ UINT8 *pBuf;\r
+ UINT32 Index;\r
+ UINT64 Address;\r
+ UINT32 Remainder;\r
+ UINT64 CEATALBA;\r
+ UINT32 BoundarySize;\r
+\r
+ Status = EFI_SUCCESS;\r
+ CardData = CARD_DATA_FROM_THIS(This);\r
+ pBuf = Buffer;\r
+ Index = 0;\r
+ Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);\r
+ BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;\r
+\r
+ if (!Buffer) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));\r
+ goto Exit;\r
+ }\r
+\r
+ if (MediaId != CardData->BlockIoMedia.MediaId) {\r
+ Status = EFI_MEDIA_CHANGED;\r
+ DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Media changed\n" ));\r
+ goto Exit;\r
+ }\r
+\r
+ if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Bad buffer size\n" ));\r
+ goto Exit;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ Status = EFI_SUCCESS;\r
+ goto Exit;\r
+ }\r
+\r
+ if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));\r
+ goto Exit;\r
+ }\r
+\r
+\r
+ do {\r
+ if (BufferSize < BoundarySize) {\r
+ TransferSize = (UINT32)BufferSize;\r
+ } else {\r
+ TransferSize = BoundarySize;\r
+ }\r
+\r
+ Address += Index * TransferSize;\r
+ CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);\r
+ ASSERT(Remainder == 0);\r
+\r
+ Status = ReadDMAExt (\r
+ CardData,\r
+ CEATALBA,\r
+ pBuf,\r
+ (UINT16)(TransferSize / DATA_UNIT_SIZE)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "Read Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));\r
+ This->Reset (This, TRUE);\r
+ goto Exit;\r
+ }\r
+ BufferSize -= TransferSize;\r
+ pBuf += TransferSize;\r
+ Index ++;\r
+ } while (BufferSize != 0);\r
+\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+ @param MediaId The media id that the write request is for.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ The caller is responsible for writing to only legitimate locations.\r
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple of the\r
+ intrinsic block size of the device.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller\r
+ is responsible for either having implicit or explicit ownership\r
+ of the buffer.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CEATABlockWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CARD_DATA *CardData;\r
+ UINT32 TransferSize;\r
+ UINT8 *pBuf;\r
+ UINT32 Index;\r
+ UINT64 Address;\r
+ UINT32 Remainder;\r
+ UINT64 CEATALBA;\r
+ UINT32 BoundarySize;\r
+\r
+\r
+ Status = EFI_SUCCESS;\r
+ CardData = CARD_DATA_FROM_THIS(This);\r
+ pBuf = Buffer;\r
+ Index = 0;\r
+ Address = MultU64x32(LBA, CardData->BlockIoMedia.BlockSize);\r
+ BoundarySize = CardData->SDHostIo->HostCapability.BoundarySize;\r
+\r
+\r
+ if (!Buffer) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ if (MediaId != CardData->BlockIoMedia.MediaId) {\r
+ Status = EFI_MEDIA_CHANGED;\r
+ goto Exit;\r
+ }\r
+\r
+ if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto Exit;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ Status = EFI_SUCCESS;\r
+ goto Exit;\r
+ }\r
+\r
+ if (CardData->BlockIoMedia.ReadOnly) {\r
+ Status = EFI_WRITE_PROTECTED;\r
+ goto Exit;\r
+ }\r
+\r
+ if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ CardData->NeedFlush = TRUE;\r
+\r
+ do {\r
+ if (BufferSize < BoundarySize) {\r
+ TransferSize = (UINT32)BufferSize;\r
+ } else {\r
+ TransferSize = BoundarySize;\r
+ }\r
+\r
+ Address += Index * TransferSize;\r
+ CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);\r
+ ASSERT(Remainder == 0);\r
+\r
+ Status = WriteDMAExt (\r
+ CardData,\r
+ CEATALBA,\r
+ pBuf,\r
+ (UINT16)(TransferSize / DATA_UNIT_SIZE)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "Write Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));\r
+ This->Reset (This, TRUE);\r
+ goto Exit;\r
+ }\r
+ BufferSize -= TransferSize;\r
+ pBuf += TransferSize;\r
+ Index ++;\r
+ } while (BufferSize != 0);\r
+\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.\r
+ (In this driver, this function just returns EFI_SUCCESS.)\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval Others\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CEATABlockFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+ CARD_DATA *CardData;\r
+\r
+ CardData = CARD_DATA_FROM_THIS(This);\r
+\r
+ if (CardData->NeedFlush) {\r
+ CardData->NeedFlush = FALSE;\r
+ Status = FlushCache (CardData);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ CEATA card BlockIo init function.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval Others\r
+**/\r
+EFI_STATUS\r
+CEATABlockIoInit (\r
+ IN CARD_DATA *CardData\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ CEATA card BlockIo init function\r
+\r
+ Arguments:\r
+ CardData - Pointer to CARD_DATA\r
+\r
+ Returns:\r
+ EFI_SUCCESS - Success\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 MaxSize;\r
+ UINT32 Remainder;\r
+ //\r
+ //BlockIO protocol\r
+ //\r
+ CardData->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
+ CardData->BlockIo.Media = &(CardData->BlockIoMedia);\r
+ CardData->BlockIo.Reset = CEATABlockReset;\r
+ CardData->BlockIo.ReadBlocks = CEATABlockReadBlocks ;\r
+ CardData->BlockIo.WriteBlocks = CEATABlockWriteBlocks;\r
+ CardData->BlockIo.FlushBlocks = CEATABlockFlushBlocks;\r
+\r
+ CardData->BlockIoMedia.MediaId = 0;\r
+ CardData->BlockIoMedia.RemovableMedia = FALSE;\r
+ CardData->BlockIoMedia.MediaPresent = TRUE;\r
+ CardData->BlockIoMedia.LogicalPartition = FALSE;\r
+\r
+ if (CardData->CSDRegister.PERM_WRITE_PROTECT | CardData->CSDRegister.TMP_WRITE_PROTECT) {\r
+ CardData->BlockIoMedia.ReadOnly = TRUE;\r
+ } else {\r
+ CardData->BlockIoMedia.ReadOnly = FALSE;\r
+ }\r
+\r
+\r
+ CardData->BlockIoMedia.WriteCaching = FALSE;\r
+ CardData->BlockIoMedia.IoAlign = 1;\r
+\r
+ Status = IndentifyDevice (CardData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ //Some device does not support this feature\r
+ //\r
+\r
+ if (CardData->IndentifyDeviceData.MaxWritesPerAddress == 0) {\r
+ CardData->BlockIoMedia.ReadOnly = TRUE;\r
+ }\r
+\r
+ CardData->BlockIoMedia.BlockSize = (1 << CardData->IndentifyDeviceData.Sectorsize);\r
+ ASSERT(CardData->BlockIoMedia.BlockSize >= 12);\r
+\r
+\r
+ MaxSize = *(UINT64*)(CardData->IndentifyDeviceData.MaximumLBA);\r
+ MaxSize = MultU64x32 (MaxSize, 512);\r
+\r
+ Remainder = 0;\r
+ CardData->BlockNumber = DivU64x32Remainder (MaxSize, CardData->BlockIoMedia.BlockSize, &Remainder);\r
+ ASSERT(Remainder == 0);\r
+\r
+ CardData->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1);\r
+\r
+\r
+Exit:\r
+ return Status;\r
+\r
+}\r
+\r
+\r
+\r
--- /dev/null
+/** @file\r
+\r
+UEFI Component Name(2) protocol implementation for SD media device driver.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SDMediaDevice.h"\r
+\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSDMediaDeviceName = {\r
+ SDMediaDeviceGetDriverName,\r
+ SDMediaDeviceGetControllerName,\r
+ "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSDMediaDeviceName2 = {\r
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SDMediaDeviceGetDriverName,\r
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SDMediaDeviceGetControllerName,\r
+ "en"\r
+};\r
+\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSDMediaDeviceDriverNameTable[] = {\r
+ { "eng;en", L"UEFI MMC/SD Media Device Driver" },\r
+ { NULL, NULL }\r
+};\r
+\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 3066 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDMediaDeviceGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mSDMediaDeviceDriverNameTable,\r
+ DriverName,\r
+ (BOOLEAN)(This == &gSDMediaDeviceName)\r
+ );\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 3066 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDMediaDeviceGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ CARD_DATA *CardData;\r
+\r
+ //\r
+ // This is a device driver, so ChildHandle must be NULL.\r
+ //\r
+ if (ChildHandle != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Get the device context\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ gSDMediaDeviceDriverBinding.DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ CardData = CARD_DATA_FROM_THIS (BlockIo);\r
+\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ CardData->ControllerNameTable,\r
+ ControllerName,\r
+ (BOOLEAN)(This == &gSDMediaDeviceName)\r
+ );\r
+\r
+}\r
--- /dev/null
+/** @file\r
+\r
+This file contains the delarations for componet name routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _COMPONENT_NAME_H_\r
+#define _COMPONENT_NAME_H_\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 3066 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDMediaDeviceGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 3066 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDMediaDeviceGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+#endif\r
--- /dev/null
+/** @file\r
+\r
+Block I/O protocol for MMC/SD device\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SDMediaDevice.h"\r
+\r
+/**\r
+ Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive.\r
+ verification operation of the device during reset.\r
+ (This parameter is ingored in this driver.)\r
+\r
+ @retval EFI_SUCCESS Success\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MMCSDBlockReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ CARD_DATA *CardData;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+\r
+ CardData = CARD_DATA_FROM_THIS(This);\r
+ SDHostIo = CardData->SDHostIo;\r
+\r
+ return SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);\r
+ }\r
+\r
+/**\r
+ Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+ @param MediaId The media id that the write request is for.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ The caller is responsible for writing to only legitimate locations.\r
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple of the\r
+ intrinsic block size of the device.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller\r
+ is responsible for either having implicit or explicit ownership\r
+ of the buffer.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MMCSDBlockReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Address;\r
+ CARD_DATA *CardData;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT32 RemainingLength;\r
+ UINT32 TransferLength;\r
+ UINT8 *BufferPointer;\r
+ BOOLEAN SectorAddressing;\r
+ UINTN TotalBlock;\r
+\r
+ DEBUG((EFI_D_INFO, "Read(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));\r
+ Status = EFI_SUCCESS;\r
+ CardData = CARD_DATA_FROM_THIS(This);\r
+ SDHostIo = CardData->SDHostIo;\r
+ if (MediaId != CardData->BlockIoMedia.MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (ModU64x32 (BufferSize,CardData->BlockIoMedia.BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+ if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {\r
+ SectorAddressing = TRUE;\r
+ } else {\r
+ SectorAddressing = FALSE;\r
+ }\r
+ if (SectorAddressing) {\r
+ //\r
+ //Block Address\r
+ //\r
+ Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);\r
+ } else {\r
+ //\r
+ //Byte Address\r
+ //\r
+ Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);\r
+ }\r
+ TotalBlock = (UINTN) DivU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize);\r
+ if (LBA + TotalBlock > CardData->BlockIoMedia.LastBlock + 1) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+\r
+ if (!Buffer) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks:Invalid parameter \r\n"));\r
+ goto Done;\r
+ }\r
+\r
+ if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \r\n"));\r
+ goto Done;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+\r
+\r
+\r
+ BufferPointer = Buffer;\r
+ RemainingLength = (UINT32)BufferSize;\r
+\r
+ while (RemainingLength > 0) {\r
+ if ((BufferSize > CardData->BlockIoMedia.BlockSize)) {\r
+ if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {\r
+ TransferLength = SDHostIo->HostCapability.BoundarySize;\r
+ } else {\r
+ TransferLength = RemainingLength;\r
+ }\r
+\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+ if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_BLOCKLEN,\r
+ CardData->BlockIoMedia.BlockSize,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_BLOCK_COUNT,\r
+ TransferLength / CardData->BlockIoMedia.BlockSize,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ Status = SendCommand (\r
+ CardData,\r
+ READ_MULTIPLE_BLOCK,\r
+ Address,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ TransferLength,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));\r
+ break;\r
+ }\r
+ } else {\r
+ if (RemainingLength > CardData->BlockIoMedia.BlockSize) {\r
+ TransferLength = CardData->BlockIoMedia.BlockSize;\r
+ } else {\r
+ TransferLength = RemainingLength;\r
+ }\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ READ_SINGLE_BLOCK,\r
+ Address,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ (UINT32)TransferLength,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));\r
+ break;\r
+ }\r
+ }\r
+ CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);\r
+\r
+ if (SectorAddressing) {\r
+ //\r
+ //Block Address\r
+ //\r
+ Address += TransferLength / 512;\r
+ } else {\r
+ //\r
+ //Byte Address\r
+ //\r
+ Address += TransferLength;\r
+ }\r
+ BufferPointer += TransferLength;\r
+ RemainingLength -= TransferLength;\r
+ }\r
+\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if ((CardData->CardType == SDMemoryCard) ||\r
+ (CardData->CardType == SDMemoryCard2)||\r
+ (CardData->CardType == SDMemoryCard2High)) {\r
+ SendCommand (\r
+ CardData,\r
+ STOP_TRANSMISSION,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1b,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ } else {\r
+ SendCommand (\r
+ CardData,\r
+ STOP_TRANSMISSION,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ }\r
+\r
+ }\r
+\r
+\r
+Done:\r
+ DEBUG((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+ @param MediaId The media id that the write request is for.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ The caller is responsible for writing to only legitimate locations.\r
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple of the\r
+ intrinsic block size of the device.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller\r
+ is responsible for either having implicit or explicit ownership\r
+ of the buffer.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MMCSDBlockWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA LBA,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Address;\r
+ CARD_DATA *CardData;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT32 RemainingLength;\r
+ UINT32 TransferLength;\r
+ UINT8 *BufferPointer;\r
+ BOOLEAN SectorAddressing;\r
+\r
+ DEBUG((EFI_D_INFO, "Write(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));\r
+ Status = EFI_SUCCESS;\r
+ CardData = CARD_DATA_FROM_THIS(This);\r
+ SDHostIo = CardData->SDHostIo;\r
+ if ((CardData->CardType == SDMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {\r
+ SectorAddressing = TRUE;\r
+ } else {\r
+ SectorAddressing = FALSE;\r
+ }\r
+ if (SectorAddressing) {\r
+ //\r
+ //Block Address\r
+ //\r
+ Address = (UINT32)DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);\r
+ } else {\r
+ //\r
+ //Byte Address\r
+ //\r
+ Address = (UINT32)MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);\r
+ }\r
+\r
+ if (!Buffer) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \r\n"));\r
+ goto Done;\r
+ }\r
+\r
+ if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \r\n"));\r
+ goto Done;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ if (This->Media->ReadOnly == TRUE) {\r
+ Status = EFI_WRITE_PROTECTED;\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \r\n"));\r
+ goto Done;\r
+ }\r
+\r
+\r
+\r
+ BufferPointer = Buffer;\r
+ RemainingLength = (UINT32)BufferSize;\r
+\r
+ while (RemainingLength > 0) {\r
+ if ((BufferSize > CardData->BlockIoMedia.BlockSize) ) {\r
+ if (RemainingLength > SDHostIo->HostCapability.BoundarySize) {\r
+ TransferLength = SDHostIo->HostCapability.BoundarySize;\r
+ } else {\r
+ TransferLength = RemainingLength;\r
+ }\r
+\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+\r
+ if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_BLOCKLEN,\r
+ CardData->BlockIoMedia.BlockSize,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_BLOCK_COUNT,\r
+ TransferLength / CardData->BlockIoMedia.BlockSize,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ WRITE_MULTIPLE_BLOCK,\r
+ Address,\r
+ OutData,\r
+ CardData->AlignedBuffer,\r
+ (UINT32)TransferLength,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));\r
+ break;\r
+ }\r
+ } else {\r
+ if (RemainingLength > CardData->BlockIoMedia.BlockSize) {\r
+ TransferLength = CardData->BlockIoMedia.BlockSize;\r
+ } else {\r
+ TransferLength = RemainingLength;\r
+ }\r
+\r
+ CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ WRITE_BLOCK,\r
+ Address,\r
+ OutData,\r
+ CardData->AlignedBuffer,\r
+ (UINT32)TransferLength,\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ }\r
+ if (SectorAddressing) {\r
+ //\r
+ //Block Address\r
+ //\r
+ Address += TransferLength / 512;\r
+ } else {\r
+ //\r
+ //Byte Address\r
+ //\r
+ Address += TransferLength;\r
+ }\r
+ BufferPointer += TransferLength;\r
+ RemainingLength -= TransferLength;\r
+\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ SendCommand (\r
+ CardData,\r
+ STOP_TRANSMISSION,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1b,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+\r
+ }\r
+\r
+\r
+Done:\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.\r
+ (In this driver, this function just returns EFI_SUCCESS.)\r
+\r
+ @param This The EFI_BLOCK_IO_PROTOCOL instance.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval Others\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MMCSDBlockFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ )\r
+{\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ MMC/SD card BlockIo init function.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval Others\r
+**/\r
+EFI_STATUS\r
+MMCSDBlockIoInit (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ //\r
+ //BlockIO protocol\r
+ //\r
+ CardData->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
+ CardData->BlockIo.Media = &(CardData->BlockIoMedia);\r
+ CardData->BlockIo.Reset = MMCSDBlockReset;\r
+ CardData->BlockIo.ReadBlocks = MMCSDBlockReadBlocks ;\r
+ CardData->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;\r
+ CardData->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;\r
+\r
+ CardData->BlockIoMedia.MediaId = 0;\r
+ CardData->BlockIoMedia.RemovableMedia = FALSE;\r
+ CardData->BlockIoMedia.MediaPresent = TRUE;\r
+ CardData->BlockIoMedia.LogicalPartition = FALSE;\r
+\r
+ if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {\r
+ CardData->BlockIoMedia.ReadOnly = TRUE;\r
+ } else {\r
+ CardData->BlockIoMedia.ReadOnly = FALSE;\r
+ }\r
+\r
+\r
+ CardData->BlockIoMedia.WriteCaching = FALSE;\r
+ CardData->BlockIoMedia.BlockSize = CardData->BlockLen;\r
+ CardData->BlockIoMedia.IoAlign = 1;\r
+ CardData->BlockIoMedia.LastBlock = (EFI_LBA)(CardData->BlockNumber - 1);\r
+\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+\r
--- /dev/null
+/** @file\r
+\r
+MMC/SD transfer specific functions\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SDMediaDevice.h"\r
+\r
+/**\r
+ Check card status, print the debug info and check the error\r
+\r
+ @param Status Status got from card status register.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+CheckCardStatus (\r
+ IN UINT32 Status\r
+ )\r
+{\r
+ CARD_STATUS *CardStatus;\r
+ CardStatus = (CARD_STATUS*)(&Status);\r
+\r
+ if (CardStatus->ADDRESS_OUT_OF_RANGE) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_OUT_OF_RANGE\n"));\r
+ }\r
+\r
+ if (CardStatus->ADDRESS_MISALIGN) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_MISALIGN\n"));\r
+ }\r
+\r
+ if (CardStatus->BLOCK_LEN_ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: BLOCK_LEN_ERROR\n"));\r
+ }\r
+\r
+ if (CardStatus->ERASE_SEQ_ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_SEQ_ERROR\n"));\r
+ }\r
+\r
+ if (CardStatus->ERASE_PARAM) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_PARAM\n"));\r
+ }\r
+\r
+ if (CardStatus->WP_VIOLATION) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: WP_VIOLATION\n"));\r
+ }\r
+\r
+ if (CardStatus->CARD_IS_LOCKED) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: CARD_IS_LOCKED\n"));\r
+ }\r
+\r
+ if (CardStatus->LOCK_UNLOCK_FAILED) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: LOCK_UNLOCK_FAILED\n"));\r
+ }\r
+\r
+ if (CardStatus->COM_CRC_ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: COM_CRC_ERROR\n"));\r
+ }\r
+\r
+ if (CardStatus->ILLEGAL_COMMAND) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ILLEGAL_COMMAND\n"));\r
+ }\r
+\r
+ if (CardStatus->CARD_ECC_FAILED) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: CARD_ECC_FAILED\n"));\r
+ }\r
+\r
+ if (CardStatus->CC_ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: CC_ERROR\n"));\r
+ }\r
+\r
+ if (CardStatus->ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERROR\n"));\r
+ }\r
+\r
+ if (CardStatus->UNDERRUN) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: UNDERRUN\n"));\r
+ }\r
+\r
+ if (CardStatus->OVERRUN) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: OVERRUN\n"));\r
+ }\r
+\r
+ if (CardStatus->CID_CSD_OVERWRITE) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: CID_CSD_OVERWRITE\n"));\r
+ }\r
+\r
+ if (CardStatus->WP_ERASE_SKIP) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: WP_ERASE_SKIP\n"));\r
+ }\r
+\r
+ if (CardStatus->ERASE_RESET) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_RESET\n"));\r
+ }\r
+\r
+ if (CardStatus->SWITCH_ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: SWITCH_ERROR\n"));\r
+ }\r
+\r
+ if ((Status & 0xFCFFA080) != 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send command by using Host IO protocol\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param CommandIndex The command index to set the command index field of command register.\r
+ @param Argument Command argument to set the argument field of command register.\r
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.\r
+ @param Buffer Contains the data read from / write to the device.\r
+ @param BufferSize The size of the buffer.\r
+ @param ResponseType RESPONSE_TYPE.\r
+ @param TimeOut Time out value in 1 ms unit.\r
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+SendCommand (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT16 CommandIndex,\r
+ IN UINT32 Argument,\r
+ IN TRANSFER_TYPE DataType,\r
+ IN UINT8 *Buffer, OPTIONAL\r
+ IN UINT32 BufferSize,\r
+ IN RESPONSE_TYPE ResponseType,\r
+ IN UINT32 TimeOut,\r
+ OUT UINT32 *ResponseData\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ SDHostIo = CardData->SDHostIo;\r
+ if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {\r
+ CommandIndex |= AUTO_CMD12_ENABLE;\r
+ }\r
+\r
+ Status = SDHostIo->SendCommand (\r
+ SDHostIo,\r
+ CommandIndex,\r
+ Argument,\r
+ DataType,\r
+ Buffer,\r
+ BufferSize,\r
+ ResponseType,\r
+ TimeOut,\r
+ ResponseData\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {\r
+ ASSERT(ResponseData != NULL);\r
+ Status = CheckCardStatus (*ResponseData);\r
+ }\r
+ } else {\r
+ SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send the card APP_CMD command with the following command indicated by CommandIndex\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param CommandIndex The command index to set the command index field of command register.\r
+ @param Argument Command argument to set the argument field of command register.\r
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.\r
+ @param Buffer Contains the data read from / write to the device.\r
+ @param BufferSize The size of the buffer.\r
+ @param ResponseType RESPONSE_TYPE.\r
+ @param TimeOut Time out value in 1 ms unit.\r
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+SendAppCommand (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT16 CommandIndex,\r
+ IN UINT32 Argument,\r
+ IN TRANSFER_TYPE DataType,\r
+ IN UINT8 *Buffer, OPTIONAL\r
+ IN UINT32 BufferSize,\r
+ IN RESPONSE_TYPE ResponseType,\r
+ IN UINT32 TimeOut,\r
+ OUT UINT32 *ResponseData\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT8 Index;\r
+\r
+ SDHostIo = CardData->SDHostIo;\r
+ Status = EFI_SUCCESS;\r
+\r
+ for (Index = 0; Index < 2; Index++) {\r
+ Status = SDHostIo->SendCommand (\r
+ SDHostIo,\r
+ APP_CMD,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = CheckCardStatus (*(UINT32*)&(CardData->CardStatus));\r
+ if (CardData->CardStatus.SAPP_CMD != 1) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ } else {\r
+ SDHostIo->ResetSDHost (SDHostIo, Reset_Auto);\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {\r
+ CommandIndex |= AUTO_CMD12_ENABLE;\r
+ }\r
+\r
+ Status = SDHostIo->SendCommand (\r
+ SDHostIo,\r
+ CommandIndex,\r
+ Argument,\r
+ DataType,\r
+ Buffer,\r
+ BufferSize,\r
+ ResponseType,\r
+ TimeOut,\r
+ ResponseData\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {\r
+ ASSERT(ResponseData != NULL);\r
+ Status = CheckCardStatus (*ResponseData);\r
+ }\r
+ } else {\r
+ SDHostIo->ResetSDHost (SDHostIo, Reset_Auto);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Send the card FAST_IO command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param RegisterAddress Register Address.\r
+ @param RegisterData Pointer to register Data.\r
+ @param Write TRUE for write, FALSE for read.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+FastIO (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT8 RegisterAddress,\r
+ IN OUT UINT8 *RegisterData,\r
+ IN BOOLEAN Write\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Argument;\r
+ UINT32 Data;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (RegisterData == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ Argument = (CardData->Address << 16) | (RegisterAddress << 8);\r
+ if (Write) {\r
+ Argument |= BIT15 | (*RegisterData);\r
+ }\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ FAST_IO,\r
+ Argument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR4,\r
+ TIMEOUT_COMMAND,\r
+ &Data\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ if ((Data & BIT15) == 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+\r
+ if (!Write) {\r
+ *RegisterData = (UINT8)Data;\r
+ }\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send the card GO_INACTIVE_STATE command.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+PutCardInactive (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ GO_INACTIVE_STATE,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseNo,\r
+ TIMEOUT_COMMAND,\r
+ NULL\r
+ );\r
+\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+ Get card interested information for CSD rergister\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+CaculateCardParameter (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Frequency;\r
+ UINT32 Multiple;\r
+ UINT32 CSize;\r
+ CSD_SDV2 *CsdSDV2;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ switch (CardData->CSDRegister.TRAN_SPEED & 0x7) {\r
+ case 0:\r
+ Frequency = 100 * 1000;\r
+ break;\r
+\r
+ case 1:\r
+ Frequency = 1 * 1000 * 1000;\r
+ break;\r
+\r
+ case 2:\r
+ Frequency = 10 * 1000 * 1000;\r
+ break;\r
+\r
+ case 3:\r
+ Frequency = 100 * 1000 * 1000;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ switch ((CardData->CSDRegister.TRAN_SPEED >> 3) & 0xF) {\r
+ case 1:\r
+ Multiple = 10;\r
+ break;\r
+\r
+ case 2:\r
+ Multiple = 12;\r
+ break;\r
+\r
+ case 3:\r
+ Multiple = 13;\r
+ break;\r
+\r
+ case 4:\r
+ Multiple = 15;\r
+ break;\r
+\r
+ case 5:\r
+ Multiple = 20;\r
+ break;\r
+\r
+ case 6:\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+ Multiple = 26;\r
+ } else {\r
+ Multiple = 25;\r
+ }\r
+ break;\r
+\r
+ case 7:\r
+ Multiple = 30;\r
+ break;\r
+\r
+ case 8:\r
+ Multiple = 35;\r
+ break;\r
+\r
+ case 9:\r
+ Multiple = 40;\r
+ break;\r
+\r
+ case 10:\r
+ Multiple = 45;\r
+ break;\r
+\r
+ case 11:\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+ Multiple = 52;\r
+ } else {\r
+ Multiple = 50;\r
+ }\r
+ break;\r
+\r
+ case 12:\r
+ Multiple = 55;\r
+ break;\r
+\r
+ case 13:\r
+ Multiple = 60;\r
+ break;\r
+\r
+ case 14:\r
+ Multiple = 70;\r
+ break;\r
+\r
+ case 15:\r
+ Multiple = 80;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ Frequency = Frequency * Multiple / 10;\r
+ CardData->MaxFrequency = Frequency;\r
+\r
+ CardData->BlockLen = 1 << CardData->CSDRegister.READ_BL_LEN;\r
+\r
+ if (CardData->CardType == SDMemoryCard2High) {\r
+ ASSERT(CardData->CSDRegister.CSD_STRUCTURE == 1);\r
+ CsdSDV2 = (CSD_SDV2*)&CardData->CSDRegister;\r
+ //\r
+ // The SD Spec 2.0 says (CSize + 1) * 512K is the total size, so block numbber is (CSize + 1) * 1K\r
+ // the K here means 1024 not 1000\r
+ //\r
+ CardData->BlockNumber = DivU64x32 (MultU64x32 (CsdSDV2->C_SIZE + 1, 512 * 1024) , CardData->BlockLen);\r
+ } else {\r
+ //\r
+ // For MMC card > 2G, the block number will be recaculate later\r
+ //\r
+ CSize = CardData->CSDRegister.C_SIZELow2 | (CardData->CSDRegister.C_SIZEHigh10 << 2);\r
+ CardData->BlockNumber = MultU64x32 (LShiftU64 (1, CardData->CSDRegister.C_SIZE_MULT + 2), CSize + 1);\r
+ }\r
+\r
+ //\r
+ //For >= 2G card, BlockLen may be 1024, but the transfer size is still 512 bytes\r
+ //\r
+ if (CardData->BlockLen > 512) {\r
+ CardData->BlockNumber = DivU64x32 (MultU64x32 (CardData->BlockNumber, CardData->BlockLen), 512);\r
+ CardData->BlockLen = 512;\r
+ }\r
+\r
+ DEBUG((\r
+ EFI_D_INFO,\r
+ "CalculateCardParameter: Card Size: 0x%lx\n", MultU64x32 (CardData->BlockNumber, CardData->BlockLen)\r
+ ));\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Test the bus width setting for MMC card.It is used only for verification purpose.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param Width 1, 4, 8 bits.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+MMCCardBusWidthTest (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT32 Width\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Data;\r
+ UINT64 Value;\r
+\r
+ ASSERT(CardData != NULL);\r
+\r
+\r
+ Value = 0;\r
+\r
+ switch (Width) {\r
+ case 1:\r
+ Data = 0x80;\r
+ break;\r
+\r
+ case 4:\r
+ Data = 0x5A;\r
+ break;\r
+\r
+ case 8:\r
+ Data = 0xAA55;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ CopyMem (CardData->AlignedBuffer, &Data, Width);\r
+ Status = SendCommand (\r
+ CardData,\r
+ BUSTEST_W,\r
+ 0,\r
+ OutData,\r
+ CardData->AlignedBuffer,\r
+ Width,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_W 0x%x\n", *(UINT32*)&(CardData->CardStatus)));\r
+ goto Exit;\r
+ }\r
+\r
+ gBS->Stall (10 * 1000);\r
+\r
+ Data = 0;\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ BUSTEST_R,\r
+ 0,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ Width,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_R 0x%x\n", *(UINT32*)&(CardData->CardStatus)));\r
+ goto Exit;\r
+ }\r
+ CopyMem (&Data, CardData->AlignedBuffer, Width);\r
+\r
+ switch (Width) {\r
+ case 1:\r
+ Value = (~(Data ^ 0x80)) & 0xC0;\r
+ break;\r
+ case 4:\r
+ Value = (~(Data ^ 0x5A)) & 0xFF;\r
+ break;\r
+ case 8:\r
+ Value = (~(Data ^ 0xAA55)) & 0xFFFF;\r
+ break;\r
+ }\r
+\r
+ if (Value == 0) {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function can detect these card types:\r
+ 1. MMC card\r
+ 2. SD 1.1 card\r
+ 3. SD 2.0 standard card\r
+ 3. SD 2.0 high capacity card\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+GetCardType (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT32 Argument;\r
+ UINT32 ResponseData;\r
+ UINT32 Count;\r
+ BOOLEAN SDCommand8Support;\r
+\r
+\r
+ SDHostIo = CardData->SDHostIo;\r
+\r
+ //\r
+ // Reset the card\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ GO_IDLE_STATE,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseNo,\r
+ TIMEOUT_COMMAND,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ //No spec requirment, can be adjusted\r
+ //\r
+ gBS->Stall (10 * 1000);\r
+\r
+\r
+ //\r
+ // Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass\r
+ // MMC and SD1.1 card will fail this command\r
+ //\r
+ Argument = (VOLTAGE_27_36 << 8) | CHECK_PATTERN;\r
+ ResponseData = 0;\r
+ SDCommand8Support = FALSE;\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_IF_COND,\r
+ Argument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR7,\r
+ TIMEOUT_COMMAND,\r
+ &ResponseData\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if (Status != EFI_TIMEOUT) {\r
+ DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, none time out error\n"));\r
+ goto Exit;\r
+ }\r
+ } else {\r
+ if (ResponseData != Argument) {\r
+ DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, respond data does not match send data\n"));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+ SDCommand8Support = TRUE;\r
+ }\r
+\r
+\r
+ Argument = 0;\r
+ if (SDHostIo->HostCapability.V30Support == TRUE) {\r
+ Argument |= BIT17 | BIT18;\r
+ } else if (SDHostIo->HostCapability.V33Support == TRUE) {\r
+ Argument |= BIT20 | BIT21;\r
+ }\r
+\r
+ if (SDCommand8Support) {\r
+ //\r
+ //If command SD_SEND_OP_COND sucessed, it should be set.\r
+ // SD 1.1 card will ignore it\r
+ // SD 2.0 standard card will repsond with CCS 0, SD high capacity card will respond with CCS 1\r
+ // CCS is BIT30 of OCR\r
+ Argument |= BIT30;\r
+ }\r
+\r
+\r
+ Count = 20;\r
+ //\r
+ //Only SD card will respond to this command, and spec says the card only checks condition at first ACMD41 command\r
+ //\r
+ do {\r
+ Status = SendAppCommand (\r
+ CardData,\r
+ SD_SEND_OP_COND,\r
+ Argument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR3,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->OCRRegister)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ if ((Status == EFI_TIMEOUT) && (!SDCommand8Support)) {\r
+ CardData->CardType = MMCCard;\r
+ Status = EFI_SUCCESS;\r
+ DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, MMC card was identified\n"));\r
+ } else {\r
+ //\r
+ // Not as expected, MMC card should has no response, which means timeout.\r
+ // SD card should pass this command\r
+ //\r
+ DEBUG((EFI_D_ERROR, "SD_SEND_OP_COND Fail, check whether it is neither a MMC card nor a SD card\n"));\r
+ }\r
+ goto Exit;\r
+ }\r
+ //\r
+ //Avoid waiting if sucess. Busy bit 0 means not ready\r
+ //\r
+ if (CardData->OCRRegister.Busy == 1) {\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (50 * 1000);\r
+ Count--;\r
+ if (Count == 0) {\r
+ DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));\r
+ Status = EFI_TIMEOUT;\r
+ goto Exit;\r
+ }\r
+ } while (1);\r
+\r
+ //\r
+ //Check supported voltage\r
+ //\r
+ Argument = 0;\r
+ if (SDHostIo->HostCapability.V30Support == TRUE) {\r
+ if ((CardData->OCRRegister.V270_V360 & BIT2) == BIT2) {\r
+ Argument |= BIT17;\r
+ } else if ((CardData->OCRRegister.V270_V360 & BIT3) == BIT3) {\r
+ Argument |= BIT18;\r
+ }\r
+ } else if (SDHostIo->HostCapability.V33Support == TRUE) {\r
+ if ((CardData->OCRRegister.V270_V360 & BIT5) == BIT5) {\r
+ Argument |= BIT20;\r
+ } else if ((CardData->OCRRegister.V270_V360 & BIT6) == BIT6) {\r
+ Argument |= BIT21;\r
+ }\r
+ }\r
+\r
+ if (Argument == 0) {\r
+ //\r
+ //No matched support voltage\r
+ //\r
+ PutCardInactive (CardData);\r
+ DEBUG((EFI_D_ERROR, "No matched voltage for this card\n"));\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Exit;\r
+ }\r
+\r
+ CardData->CardType = SDMemoryCard;\r
+ if (SDCommand8Support == TRUE) {\r
+ CardData->CardType = SDMemoryCard2;\r
+ DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above standard card was identified\n"));\r
+ }\r
+\r
+ if ((CardData->OCRRegister.AccessMode & BIT1) == BIT1) {\r
+ CardData->CardType = SDMemoryCard2High;\r
+ DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above high capacity card was identified\n"));\r
+ }\r
+\r
+\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ MMC card high/low voltage selection function\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_BAD_BUFFER_SIZE\r
+\r
+**/\r
+EFI_STATUS\r
+MMCCardVoltageSelection (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT8 Retry;\r
+ UINT32 TimeOut;\r
+\r
+ Status = EFI_SUCCESS;\r
+ SDHostIo = CardData->SDHostIo;\r
+ //\r
+ //First try the high voltage, then if supported choose the low voltage\r
+ //\r
+\r
+ for (Retry = 0; Retry < 3; Retry++) {\r
+ //\r
+ // To bring back the normal MMC card to work\r
+ // after sending the SD command. Otherwise some\r
+ // card could not work\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ GO_IDLE_STATE,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseNo,\r
+ TIMEOUT_COMMAND,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));\r
+ continue;\r
+ }\r
+ //\r
+ //CE-ATA device needs long delay\r
+ //\r
+ gBS->Stall ((Retry + 1) * 50 * 1000);\r
+\r
+ //\r
+ //Get OCR register to check voltage support, first time the OCR is 0\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_OP_COND,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR3,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->OCRRegister)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Retry == 3) {\r
+ DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ //TimeOut Value, 5000 * 100 * 1000 = 5 s\r
+ //\r
+ TimeOut = 5000;\r
+\r
+ do {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_OP_COND,\r
+ 0x40300000,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR3,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->OCRRegister)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ gBS->Stall (1 * 1000);\r
+ TimeOut--;\r
+ if (TimeOut == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));\r
+ goto Exit;\r
+ }\r
+ } while (CardData->OCRRegister.Busy != 1);\r
+\r
+ if (CardData->OCRRegister.AccessMode == 2) // eMMC Card uses Sector Addressing - High Capacity\r
+ {\r
+ DEBUG((EFI_D_INFO, "eMMC Card is High Capacity\n"));\r
+ CardData->CardType = MMCCardHighCap;\r
+ }\r
+\r
+Exit:\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+ This function set the bus and device width for MMC card\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param Width 1, 4, 8 bits.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+MMCCardSetBusWidth (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT8 BusWidth,\r
+ IN BOOLEAN EnableDDRMode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ SWITCH_ARGUMENT SwitchArgument;\r
+ UINT8 Value;\r
+\r
+ SDHostIo = CardData->SDHostIo;\r
+ Value = 0;\r
+ switch (BusWidth) {\r
+ case 8:\r
+ if (EnableDDRMode)\r
+ Value = 6;\r
+ else\r
+ Value = 2;\r
+ break;\r
+\r
+ case 4:\r
+ if (EnableDDRMode)\r
+ Value = 5;\r
+ else\r
+ Value = 1;\r
+ break;\r
+\r
+ case 1:\r
+ if (EnableDDRMode) // Bus width 1 is not supported in ddr mode\r
+ return EFI_UNSUPPORTED;\r
+ Value = 0;\r
+ break;\r
+\r
+ default:\r
+ ASSERT(0);\r
+ }\r
+\r
+\r
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));\r
+ SwitchArgument.CmdSet = 0;\r
+ SwitchArgument.Value = Value;\r
+ SwitchArgument.Index = (UINT32)((UINTN)\r
+ (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN)(&(CardData->ExtCSDRegister)));\r
+ SwitchArgument.Access = WriteByte_Mode;\r
+ Status = SendCommand (\r
+ CardData,\r
+ SWITCH,\r
+ *(UINT32*)&SwitchArgument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1b,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_STATUS,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth));\r
+ goto Exit;\r
+ } else {\r
+ DEBUG((EFI_D_ERROR, "MMCCardSetBusWidth:SWITCH Card Status:0x%x\n", *(UINT32*)&(CardData->CardStatus)));\r
+ Status = SDHostIo->SetBusWidth (SDHostIo, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SWITCH set %d bits Fail\n", BusWidth));\r
+ goto Exit;\r
+ }\r
+ gBS->Stall (5 * 1000);\r
+ }\r
+ }\r
+\r
+ if (!EnableDDRMode) { // CMD19 and CMD14 are illegal commands in ddr mode\r
+ //if (EFI_ERROR (Status)) {\r
+ // DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest: Fail to enable high speed mode\n"));\r
+ // goto Exit;\r
+ //}\r
+\r
+ Status = MMCCardBusWidthTest (CardData, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth));\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ CardData->CurrentBusWidth = BusWidth;\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ MMC/SD card init function\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+MMCSDCardInit (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ SWITCH_ARGUMENT SwitchArgument;\r
+ UINT32 Data;\r
+ UINT32 Argument;\r
+ UINT32 nIndex;\r
+ UINT8 PowerValue;\r
+ BOOLEAN EnableDDRMode;\r
+\r
+ ASSERT(CardData != NULL);\r
+ SDHostIo = CardData->SDHostIo;\r
+ EnableDDRMode = FALSE;\r
+\r
+ CardData->CardType = UnknownCard;\r
+ Status = GetCardType (CardData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ DEBUG((DEBUG_INFO, "CardData->CardType 0x%x\n", CardData->CardType));\r
+\r
+ ASSERT (CardData->CardType != UnknownCard);\r
+ //\r
+ //MMC, SD card need host auto stop command support\r
+ //\r
+ SDHostIo->EnableAutoStopCmd (SDHostIo, TRUE);\r
+\r
+ if (CardData->CardType == MMCCard) {\r
+ Status = MMCCardVoltageSelection (CardData);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Get CID Register\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ ALL_SEND_CID,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR2,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CIDRegister)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "ALL_SEND_CID Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ } else {\r
+ // Dump out the Card ID data\r
+ DEBUG((EFI_D_INFO, "Product Name: "));\r
+ for ( nIndex=0; nIndex<6; nIndex++ ) {\r
+ DEBUG((EFI_D_INFO, "%c", CardData->CIDRegister.PNM[nIndex]));\r
+ }\r
+ DEBUG((EFI_D_INFO, "\nApplication ID : %d\n", CardData->CIDRegister.OID));\r
+ DEBUG((EFI_D_INFO, "Manufacturer ID: %d\n", CardData->CIDRegister.MID));\r
+ DEBUG((EFI_D_INFO, "Revision ID : %d\n", CardData->CIDRegister.PRV));\r
+ DEBUG((EFI_D_INFO, "Serial Number : %d\n", CardData->CIDRegister.PSN));\r
+ }\r
+\r
+ //\r
+ //SET_RELATIVE_ADDR\r
+ //\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+ //\r
+ //Hard code the RCA address\r
+ //\r
+ CardData->Address = 1;\r
+\r
+ //\r
+ // Set RCA Register\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_RELATIVE_ADDR,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+ } else {\r
+ Data = 0;\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_RELATIVE_ADDR,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR6,\r
+ TIMEOUT_COMMAND,\r
+ &Data\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ CardData->Address = (UINT16)(Data >> 16);\r
+ *(UINT32*)&CardData->CardStatus = Data & 0x1FFF;\r
+ CardData->CardStatus.ERROR = (Data >> 13) & 0x1;\r
+ CardData->CardStatus.ILLEGAL_COMMAND = (Data >> 14) & 0x1;\r
+ CardData->CardStatus.COM_CRC_ERROR = (Data >> 15) & 0x1;\r
+ Status = CheckCardStatus (*(UINT32*)&CardData->CardStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Get CSD Register\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_CSD,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR2,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CSDRegister)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SEND_CSD Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ DEBUG((EFI_D_INFO, "CardData->CSDRegister.SPEC_VERS = 0x%x\n", CardData->CSDRegister.SPEC_VERS));\r
+ DEBUG((EFI_D_INFO, "CardData->CSDRegister.CSD_STRUCTURE = 0x%x\n", CardData->CSDRegister.CSD_STRUCTURE));\r
+\r
+ Status = CaculateCardParameter (CardData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+\r
+ //\r
+ // It is platform and hardware specific, need hadrware engineer input\r
+ //\r
+ if (CardData->CSDRegister.DSR_IMP == 1) {\r
+ //\r
+ // Default is 0x404\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_DSR,\r
+ (DEFAULT_DSR_VALUE << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseNo,\r
+ TIMEOUT_COMMAND,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_DSR Fail Status = 0x%x\n", Status));\r
+ //\r
+ // Assume can operate even fail\r
+ //\r
+ }\r
+ }\r
+ //\r
+ //Change clock frequency from 400KHz to max supported when not in high speed mode\r
+ //\r
+ Status = SDHostIo->SetClockFrequency (SDHostIo, CardData->MaxFrequency);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ //Put the card into tran state\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SELECT_DESELECT_CARD,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // No spec requirment, can be adjusted\r
+ //\r
+ gBS->Stall (5 * 1000);\r
+ //\r
+ // No need to do so\r
+ //\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_STATUS,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+ //\r
+ //if the SPEC_VERS indicates a version 4.0 or higher\r
+ //The card is a high speed card and support Switch\r
+ //and Send_ext_csd command\r
+ //otherwise it is an old card\r
+ //\r
+\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+ //\r
+ //Only V4.0 and above supports more than 1 bits and high speed\r
+ //\r
+ if (CardData->CSDRegister.SPEC_VERS >= 4) {\r
+ //\r
+ //Get ExtCSDRegister\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_EXT_CSD,\r
+ 0x0,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ sizeof (EXT_CSD),\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SEND_EXT_CSD Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD));\r
+\r
+ //\r
+ // Recaculate the block number for >2G MMC card\r
+ //\r
+ Data = (CardData->ExtCSDRegister.SEC_COUNT[0]) |\r
+ (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) |\r
+ (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) |\r
+ (CardData->ExtCSDRegister.SEC_COUNT[3] << 24);\r
+\r
+ if (Data != 0) {\r
+ CardData->BlockNumber = Data;\r
+ }\r
+ DEBUG((DEBUG_INFO, "CardData->BlockNumber %d\n", Data));\r
+ DEBUG((EFI_D_ERROR, "CardData->ExtCSDRegister.CARD_TYPE -> %d\n", (UINTN)CardData->ExtCSDRegister.CARD_TYPE));\r
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2)||\r
+ (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {\r
+ //DEBUG((DEBUG_INFO, "To enable DDR mode\n"));\r
+ //EnableDDRMode = TRUE;\r
+ }\r
+ //\r
+ // Check current chipset capability and the plugged-in card\r
+ // whether supports HighSpeed\r
+ //\r
+ if (SDHostIo->HostCapability.HighSpeedSupport) {\r
+\r
+ //\r
+ //Change card timing to high speed interface timing\r
+ //\r
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));\r
+ SwitchArgument.CmdSet = 0;\r
+ SwitchArgument.Value = 1;\r
+ SwitchArgument.Index = (UINT32)((UINTN)\r
+ (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN)(&(CardData->ExtCSDRegister)));\r
+ SwitchArgument.Access = WriteByte_Mode;\r
+ Status = SendCommand (\r
+ CardData,\r
+ SWITCH,\r
+ *(UINT32*)&SwitchArgument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1b,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCSDCardInit:SWITCH frequency Fail Status = 0x%x\n", Status));\r
+ }\r
+\r
+ gBS->Stall (5 * 1000);\r
+\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_STATUS,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (EnableDDRMode) {\r
+ DEBUG((EFI_D_ERROR, "Enable ddr mode on host controller\n"));\r
+ SDHostIo->SetDDRMode (SDHostIo, TRUE);\r
+ } else {\r
+ DEBUG((EFI_D_ERROR, "Enable high speed mode on host controller\n"));\r
+ SDHostIo->SetHighSpeedMode (SDHostIo, TRUE);\r
+ }\r
+ //\r
+ // Change host clock to support high speed and enable chispet to\r
+ // support speed\r
+ //\r
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {\r
+ Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP_HIGH);\r
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {\r
+ Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP);\r
+ } else {\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));\r
+ goto Exit;\r
+ }\r
+ //\r
+ // It seems no need to stall after changing bus freqeuncy.\r
+ // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command.\r
+ // But SetClock alreay has delay.\r
+ //\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+\r
+\r
+ //\r
+ // Prefer wide bus width for performance\r
+ //\r
+ //\r
+ // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits\r
+ //\r
+ if (SDHostIo->HostCapability.BusWidth8 == TRUE) {\r
+ Status = MMCCardSetBusWidth (CardData, 8, EnableDDRMode);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // CE-ATA may support 8 bits and 4 bits, but has no software method for detection\r
+ //\r
+ Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ }\r
+ } else if (SDHostIo->HostCapability.BusWidth4 == TRUE) {\r
+ Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ PowerValue = 0;\r
+\r
+ if (CardData->CurrentBusWidth == 8) {\r
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {\r
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;\r
+ PowerValue = PowerValue >> 4;\r
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {\r
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;\r
+ PowerValue = PowerValue >> 4;\r
+ }\r
+ } else if (CardData->CurrentBusWidth == 4) {\r
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {\r
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;\r
+ PowerValue = PowerValue & 0xF;\r
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {\r
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;\r
+ PowerValue = PowerValue & 0xF;\r
+ }\r
+ }\r
+\r
+ if (PowerValue != 0) {\r
+ //\r
+ //Update Power Class\r
+ //\r
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));\r
+ SwitchArgument.CmdSet = 0;\r
+ SwitchArgument.Value = PowerValue;\r
+ SwitchArgument.Index = (UINT32)((UINTN)\r
+ (&(CardData->ExtCSDRegister.POWER_CLASS)) - (UINTN)(&(CardData->ExtCSDRegister)));\r
+ SwitchArgument.Access = WriteByte_Mode;\r
+ Status = SendCommand (\r
+ CardData,\r
+ SWITCH,\r
+ *(UINT32*)&SwitchArgument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1b,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_STATUS,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SWITCH Power Class Fail Status = 0x%x\n", Status));\r
+ }\r
+ //gBS->Stall (10 * 1000);\r
+ }\r
+ }\r
+\r
+\r
+\r
+ } else {\r
+\r
+\r
+ DEBUG((EFI_D_ERROR, "MMC Card version %d only supportes 1 bits at lower transfer speed\n",CardData->CSDRegister.SPEC_VERS));\r
+ }\r
+ } else {\r
+ //\r
+ // Pin 1, at power up this line has a 50KOhm pull up enabled in the card.\r
+ // This pull-up should be disconnected by the user, during regular data transfer,\r
+ // with SET_CLR_CARD_DETECT (ACMD42) command\r
+ //\r
+ Status = SendAppCommand (\r
+ CardData,\r
+ SET_CLR_CARD_DETECT,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_CLR_CARD_DETECT Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ /*\r
+ //\r
+ // Don't rely on SCR and SD status, some cards have unexpected SCR.\r
+ // It only sets private section, the other bits are 0\r
+ // such as Sandisk Ultra II 4.0G, KinSton mini SD 128M, Toshiba 2.0GB\r
+ // Some card even fail this command, KinSton SD 4GB\r
+ //\r
+ Status = SendAppCommand (\r
+ CardData,\r
+ SEND_SCR,\r
+ 0,\r
+ InData,\r
+ (UINT8*)&(CardData->SCRRegister),\r
+ sizeof(SCR),\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // SD memory card at least supports 1 and 4 bits.\r
+ //\r
+ // ASSERT ((CardData->SCRRegister.SD_BUS_WIDTH & (BIT0 | BIT2)) == (BIT0 | BIT2));\r
+ */\r
+\r
+ //\r
+ // Set Bus Width to 4\r
+ //\r
+ Status = SendAppCommand (\r
+ CardData,\r
+ SET_BUS_WIDTH,\r
+ SD_BUS_WIDTH_4,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_BUS_WIDTH 4 bits Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ Status = SDHostIo->SetBusWidth (SDHostIo, 4);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ CardData->CurrentBusWidth = 4;\r
+\r
+\r
+ if ((SDHostIo->HostCapability.HighSpeedSupport == FALSE) ||\r
+ ((CardData->CSDRegister.CCC & BIT10) != BIT10)) {\r
+ //\r
+ // Host must support high speed\r
+ // Card must support Switch function\r
+ //\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ //Mode = 0, group 1, function 1, check operation\r
+ //\r
+ Argument = 0xFFFF01;\r
+ ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ SWITCH_FUNC,\r
+ Argument,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ sizeof (SWITCH_STATUS),\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));\r
+\r
+ if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||\r
+ ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {\r
+ //\r
+ // 1. SD 1.1 card does not suppport busy bit\r
+ // 2. Ready state\r
+ //\r
+ //\r
+\r
+ //\r
+ //Mode = 1, group 1, function 1, BIT31 set means set mode\r
+ //\r
+ Argument = 0xFFFF01 | BIT31;\r
+ ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ SWITCH_FUNC,\r
+ Argument,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ sizeof (SWITCH_STATUS),\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));\r
+\r
+ if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||\r
+ ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {\r
+ //\r
+ // 1. SD 1.1 card does not suppport busy bit\r
+ // 2. Ready state\r
+ //\r
+\r
+ //\r
+ // 8 clocks, (1/ 25M) * 8 ==> 320 us, so 1ms > 0.32 ms\r
+ //\r
+ gBS->Stall (1000);\r
+\r
+ //\r
+ //Change host clock\r
+ //\r
+ Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_SD_PP_HIGH);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ }\r
+ }\r
+ }\r
+ if (!((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||\r
+ (CardData->ExtCSDRegister.CARD_TYPE & BIT3))) {\r
+\r
+ //\r
+ // Set Block Length, to improve compatibility in case of some cards\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_BLOCKLEN,\r
+ 512,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_BLOCKLEN Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+ }\r
+ SDHostIo->SetBlockLength (SDHostIo, 512);\r
+\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+\r
+The definition for SD media device driver model and blkio protocol routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "SDMediaDevice.h"\r
+\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gSDMediaDeviceDriverBinding = {\r
+ SDMediaDeviceSupported,\r
+ SDMediaDeviceStart,\r
+ SDMediaDeviceStop,\r
+ 0x20,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+/**\r
+ Entry point for EFI drivers.\r
+\r
+ @param ImageHandle EFI_HANDLE.\r
+ @param SystemTable EFI_SYSTEM_TABLE.\r
+\r
+ @retval EFI_SUCCESS Driver is successfully loaded.\r
+ @return Others Failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSDMediaDevice (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ return EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gSDMediaDeviceDriverBinding,\r
+ ImageHandle,\r
+ &gSDMediaDeviceName,\r
+ &gSDMediaDeviceName2\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle. Any\r
+ ControllerHandle that has BlockIoProtocol installed will be supported.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @return EFI_SUCCESS This driver supports this device.\r
+ @return EFI_UNSUPPORTED This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDMediaDeviceSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+\r
+ //\r
+ // Test whether there is PCI IO Protocol attached on the controller handle.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ (VOID **)&SDHostIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Starting the SD Media Device Driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_UNSUPPORTED This driver does not support this device.\r
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDMediaDeviceStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ CARD_DATA *CardData;\r
+\r
+ CardData = NULL;\r
+\r
+ //\r
+ // Open PCI I/O Protocol and save pointer to open protocol\r
+ // in private data area.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ (VOID **) &SDHostIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to open gEfiSDHostIoProtocolGuid \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ Status = SDHostIo->DetectCardAndInitHost (SDHostIo);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: Fail to DetectCardAndInitHost \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ CardData = (CARD_DATA*)AllocateZeroPool(sizeof (CARD_DATA));\r
+ if (CardData == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to AllocateZeroPool(CARD_DATA) \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ ASSERT (SDHostIo->HostCapability.BoundarySize >= 4 * 1024);\r
+ CardData->RawBufferPointer = (UINT8*)((UINTN)DMA_MEMORY_TOP);\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiBootServicesData,\r
+ EFI_SIZE_TO_PAGES (2 * SDHostIo->HostCapability.BoundarySize),\r
+ (EFI_PHYSICAL_ADDRESS *)(&CardData->RawBufferPointer)\r
+ );\r
+\r
+ if (CardData->RawBufferPointer == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to AllocateZeroPool(2*x) \r\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+ CardData->AlignedBuffer = CardData->RawBufferPointer - ((UINTN)(CardData->RawBufferPointer) & (SDHostIo->HostCapability.BoundarySize - 1)) + SDHostIo->HostCapability.BoundarySize;\r
+\r
+ CardData->Signature = CARD_DATA_SIGNATURE;\r
+ CardData->SDHostIo = SDHostIo;\r
+\r
+ Status = MMCSDCardInit (CardData);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to MMCSDCardInit \r\n"));\r
+ goto Exit;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: MMCSDCardInit SuccessFul\n"));\r
+\r
+ if (CardData->CardType == CEATACard) {\r
+ Status = CEATABlockIoInit (CardData);\r
+ } else {\r
+ Status = MMCSDBlockIoInit (CardData);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to BlockIoInit \r\n"));\r
+ goto Exit;\r
+ }\r
+ DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: BlockIo is successfully installed\n"));\r
+\r
+\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &CardData->BlockIo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to install gEfiBlockIoProtocolGuid \r\n"));\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Install the component name protocol\r
+ //\r
+ CardData->ControllerNameTable = NULL;\r
+\r
+ AddUnicodeString2 (\r
+ "eng",\r
+ gSDMediaDeviceName.SupportedLanguages,\r
+ &CardData->ControllerNameTable,\r
+ L"MMC/SD Media Device",\r
+ TRUE\r
+ );\r
+ AddUnicodeString2 (\r
+ "en",\r
+ gSDMediaDeviceName2.SupportedLanguages,\r
+ &CardData->ControllerNameTable,\r
+ L"MMC/SD Media Device",\r
+ FALSE\r
+ );\r
+\r
+Exit:\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "SDMediaDeviceStart: End with failure\r\n"));\r
+ if (CardData != NULL) {\r
+ if (CardData->RawBufferPointer != NULL) {\r
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * SDHostIo->HostCapability.BoundarySize));\r
+ }\r
+ FreePool (CardData);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stop this driver on ControllerHandle. Support stoping any child handles\r
+ created by this driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to stop driver on.\r
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
+ @param ChildHandleBuffer List of handles for the children we need to stop.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDMediaDeviceStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CARD_DATA *CardData;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+\r
+ //\r
+ // First find BlockIo Protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **)&BlockIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ CardData = CARD_DATA_FROM_THIS(BlockIo);\r
+\r
+ //\r
+ // Uninstall Block I/O protocol from the device handle\r
+ //\r
+ Status = gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiBlockIoProtocolGuid,\r
+ BlockIo\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (CardData != NULL) {\r
+ if (CardData->RawBufferPointer != NULL) {\r
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * CardData->SDHostIo->HostCapability.BoundarySize));\r
+ }\r
+ FreeUnicodeStringTable (CardData->ControllerNameTable);\r
+ FreePool (CardData);\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiSDHostIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
--- /dev/null
+/** @file\r
+\r
+The definition for SD media device driver model and blkio protocol routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_MEDIA_DEVICE_H_\r
+#define _SD_MEDIA_DEVICE_H_\r
+\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/BlockIo.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <IndustryStandard/Pci22.h>\r
+\r
+#include "ComponentName.h"\r
+#include "SDHostIo.h"\r
+\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL gSDMediaDeviceDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gSDMediaDeviceName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gSDMediaDeviceName2;\r
+\r
+//\r
+// Define the region of memory used for DMA memory\r
+//\r
+#define DMA_MEMORY_TOP 0x0000000001FFFFFFULL\r
+\r
+#define CARD_DATA_SIGNATURE SIGNATURE_32 ('c', 'a', 'r', 'd')\r
+\r
+//\r
+// Command timeout will be max 100 ms\r
+//\r
+#define TIMEOUT_COMMAND 100\r
+#define TIMEOUT_DATA 5000\r
+\r
+typedef enum{\r
+ UnknownCard = 0,\r
+ MMCCard, // MMC card\r
+ MMCCardHighCap, // MMC Card High Capacity\r
+ CEATACard, // CE-ATA device\r
+ SDMemoryCard, // SD 1.1 card\r
+ SDMemoryCard2, // SD 2.0 or above standard card\r
+ SDMemoryCard2High // SD 2.0 or above high capacity card\r
+}CARD_TYPE;\r
+\r
+\r
+typedef struct {\r
+ //\r
+ //BlockIO\r
+ //\r
+ UINTN Signature;\r
+ EFI_BLOCK_IO_PROTOCOL BlockIo;\r
+\r
+ EFI_BLOCK_IO_MEDIA BlockIoMedia;\r
+\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+ CARD_TYPE CardType;\r
+\r
+ UINT8 CurrentBusWidth;\r
+ BOOLEAN DualVoltage;\r
+ BOOLEAN NeedFlush;\r
+ UINT8 Reserved[3];\r
+\r
+ UINT16 Address;\r
+ UINT32 BlockLen;\r
+ UINT32 MaxFrequency;\r
+ UINT64 BlockNumber;\r
+ //\r
+ //Common used\r
+ //\r
+ CARD_STATUS CardStatus;\r
+ OCR OCRRegister;\r
+ CID CIDRegister;\r
+ CSD CSDRegister;\r
+ EXT_CSD ExtCSDRegister;\r
+ UINT8 *RawBufferPointer;\r
+ UINT8 *AlignedBuffer;\r
+ //\r
+ //CE-ATA specific\r
+ //\r
+ TASK_FILE TaskFile;\r
+ IDENTIFY_DEVICE_DATA IndentifyDeviceData;\r
+ //\r
+ //SD specific\r
+ //\r
+ SCR SCRRegister;\r
+ SD_STATUS_REG SDSattus;\r
+ SWITCH_STATUS SwitchStatus;\r
+}CARD_DATA;\r
+\r
+#define CARD_DATA_FROM_THIS(a) \\r
+ CR(a, CARD_DATA, BlockIo, CARD_DATA_SIGNATURE)\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle. Any\r
+ ControllerHandle that has BlockIoProtocol installed will be supported.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @return EFI_SUCCESS This driver supports this device.\r
+ @return EFI_UNSUPPORTED This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDMediaDeviceSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Starting the SD Media Device Driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_UNSUPPORTED This driver does not support this device.\r
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDMediaDeviceStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Stop this driver on ControllerHandle. Support stoping any child handles\r
+ created by this driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to stop driver on.\r
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
+ @param ChildHandleBuffer List of handles for the children we need to stop.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDMediaDeviceStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+/**\r
+ MMC/SD card init function\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+MMCSDCardInit (\r
+ IN CARD_DATA *CardData\r
+ );\r
+\r
+/**\r
+ Send command by using Host IO protocol\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param CommandIndex The command index to set the command index field of command register.\r
+ @param Argument Command argument to set the argument field of command register.\r
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.\r
+ @param Buffer Contains the data read from / write to the device.\r
+ @param BufferSize The size of the buffer.\r
+ @param ResponseType RESPONSE_TYPE.\r
+ @param TimeOut Time out value in 1 ms unit.\r
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+SendCommand (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT16 CommandIndex,\r
+ IN UINT32 Argument,\r
+ IN TRANSFER_TYPE DataType,\r
+ IN UINT8 *Buffer, OPTIONAL\r
+ IN UINT32 BufferSize,\r
+ IN RESPONSE_TYPE ResponseType,\r
+ IN UINT32 TimeOut,\r
+ OUT UINT32 *ResponseData\r
+ );\r
+\r
+/**\r
+ Send the card APP_CMD command with the following command indicated by CommandIndex\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param CommandIndex The command index to set the command index field of command register.\r
+ @param Argument Command argument to set the argument field of command register.\r
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.\r
+ @param Buffer Contains the data read from / write to the device.\r
+ @param BufferSize The size of the buffer.\r
+ @param ResponseType RESPONSE_TYPE.\r
+ @param TimeOut Time out value in 1 ms unit.\r
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+SendAppCommand (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT16 CommandIndex,\r
+ IN UINT32 Argument,\r
+ IN TRANSFER_TYPE DataType,\r
+ IN UINT8 *Buffer, OPTIONAL\r
+ IN UINT32 BufferSize,\r
+ IN RESPONSE_TYPE ResponseType,\r
+ IN UINT32 TimeOut,\r
+ OUT UINT32 *ResponseData\r
+ );\r
+\r
+/**\r
+ Send the card FAST_IO command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param RegisterAddress Register Address.\r
+ @param RegisterData Pointer to register Data.\r
+ @param Write TRUE for write, FALSE for read.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+FastIO (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT8 RegisterAddress,\r
+ IN OUT UINT8 *RegisterData,\r
+ IN BOOLEAN Write\r
+ );\r
+\r
+/**\r
+ Judge whether it is CE-ATA device or not.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval TRUE\r
+ @retval FALSE\r
+\r
+**/\r
+BOOLEAN\r
+IsCEATADevice (\r
+ IN CARD_DATA *CardData\r
+ );\r
+\r
+/**\r
+ Send software reset\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+SoftwareReset (\r
+ IN CARD_DATA *CardData\r
+ );\r
+\r
+/**\r
+ SendATACommand specificed in Taskfile\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param TaskFile Pointer to TASK_FILE.\r
+ @param Write TRUE means write, FALSE means read.\r
+ @param Buffer If NULL, means no data transfer, neither read nor write.\r
+ @param SectorCount Buffer size in 512 bytes unit.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+SendATACommand (\r
+ IN CARD_DATA *CardData,\r
+ IN TASK_FILE *TaskFile,\r
+ IN BOOLEAN Write,\r
+ IN UINT8 *Buffer,\r
+ IN UINT16 SectorCount\r
+ );\r
+\r
+/**\r
+ IDENTIFY_DEVICE command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+IndentifyDevice (\r
+ IN CARD_DATA *CardData\r
+ );\r
+\r
+/**\r
+ FLUSH_CACHE_EXT command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+FlushCache (\r
+ IN CARD_DATA *CardData\r
+ );\r
+\r
+/**\r
+ STANDBY_IMMEDIATE command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+StandByImmediate (\r
+ IN CARD_DATA *CardData\r
+ );\r
+\r
+/**\r
+ READ_DMA_EXT command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller\r
+ is responsible for either having implicit or explicit ownership\r
+ of the buffer.\r
+ @param SectorCount Size in 512 bytes unit.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+ReadDMAExt (\r
+ IN CARD_DATA *CardData,\r
+ IN EFI_LBA LBA,\r
+ IN UINT8 *Buffer,\r
+ IN UINT16 SectorCount\r
+ );\r
+\r
+/**\r
+ WRITE_DMA_EXT command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param LBA The starting logical block address to read from on the device.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller\r
+ is responsible for either having implicit or explicit ownership\r
+ of the buffer.\r
+ @param SectorCount Size in 512 bytes unit.\r
+\r
+ @retval EFI_SUCCESS Success\r
+ @retval EFI_DEVICE_ERROR Hardware Error\r
+ @retval EFI_INVALID_PARAMETER Parameter is error\r
+ @retval EFI_NO_MEDIA No media\r
+ @retval EFI_MEDIA_CHANGED Media Change\r
+ @retval EFI_BAD_BUFFER_SIZE Buffer size is bad\r
+\r
+**/\r
+EFI_STATUS\r
+WriteDMAExt (\r
+ IN CARD_DATA *CardData,\r
+ IN EFI_LBA LBA,\r
+ IN UINT8 *Buffer,\r
+ IN UINT16 SectorCount\r
+ );\r
+\r
+/**\r
+ CEATA card BlockIo init function.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval Others\r
+**/\r
+EFI_STATUS\r
+CEATABlockIoInit (\r
+ IN CARD_DATA *CardData\r
+ );\r
+\r
+/**\r
+ MMC/SD card BlockIo init function.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval Others\r
+**/\r
+EFI_STATUS\r
+MMCSDBlockIoInit (\r
+ IN CARD_DATA *CardData\r
+ );\r
+#endif\r
--- /dev/null
+## @file\r
+#\r
+# Component Description File For SDMediaDeviceDxe Module.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = SDMediaDevice\r
+ FILE_GUID = 80897901-91F6-4efe-9579-3353A0C02DAB\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = InitializeSDMediaDevice\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+# DRIVER_BINDING = gSDMediaDeviceDriverBinding\r
+# COMPONENT_NAME = gSDMediaDeviceName\r
+# COMPONENT_NAME2 = gSDMediaDeviceName2\r
+#\r
+\r
+[Sources]\r
+ SDMediaDevice.c\r
+ SDMediaDevice.h\r
+ MMCSDTransfer.c\r
+ CEATA.c\r
+ CEATABlockIo.c\r
+ MMCSDBlockIo.c\r
+ ComponentName.c\r
+ ComponentName.h\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ MemoryAllocationLib\r
+ BaseLib\r
+ UefiLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ BaseMemoryLib\r
+ DebugLib\r
+ PcdLib\r
+\r
+[Protocols]\r
+ gEfiPciIoProtocolGuid ## TO_START\r
+ gEfiSDHostIoProtocolGuid ## TO_START\r
+ gEfiBlockIoProtocolGuid ## BY_START\r
+\r
+[Pcd.common]\r
--- /dev/null
+/** @file\r
+Implementation of Usb Controller PPI.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiPei.h>\r
+#include <Ppi/UsbController.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/IoLib.h>\r
+\r
+#include "UsbPei.h"\r
+\r
+//\r
+// Globals\r
+//\r
+//\r
+\r
+EFI_PEI_PPI_DESCRIPTOR mPpiList = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gPeiUsbControllerPpiGuid,\r
+ NULL\r
+};\r
+\r
+UINTN mIohOhciPciReg[IOH_MAX_OHCI_USB_CONTROLLERS] = {\r
+ PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USB_OHCI_DEVICE_NUMBER, IOH_OHCI_FUNCTION_NUMBER, 0)\r
+};\r
+\r
+UINTN mIohEhciPciReg[IOH_MAX_EHCI_USB_CONTROLLERS] = {\r
+ PCI_LIB_ADDRESS (IOH_USB_BUS_NUMBER, IOH_USB_EHCI_DEVICE_NUMBER, IOH_EHCI_FUNCTION_NUMBER, 0),\r
+};\r
+\r
+/**\r
+ When EHCI get started in DXE, OHCI couldn't get the ownership\r
+ of roothub after warm reset because CF@EHCI hasn't been cleared.\r
+ We should clear that reg before UpdateBootMode. But Reg@EHCI is\r
+ memory-mapped, so need assume a range of space without conflict\r
+ in PCI memory space.\r
+\r
+ @param[in] PeiServices The pointer of EFI_PEI_SERVICES\r
+\r
+**/\r
+\r
+VOID\r
+SwitchConfigFlag (\r
+ IN EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ UINT32 SavBaseAddr;\r
+ UINT32 UsbBaseAddr;\r
+ UINT16 SaveCmdData;\r
+ UINT8 EhciCapLen;\r
+ UINT8 Index;\r
+ UsbBaseAddr = 0;\r
+\r
+ for (Index = 0; Index < IOH_MAX_EHCI_USB_CONTROLLERS; Index++) {\r
+ UsbBaseAddr = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress);\r
+ //\r
+ // Manage EHCI on IOH, set UsbBaseAddr\r
+ //\r
+ SavBaseAddr = PciRead32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR);\r
+ PciWrite32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR, UsbBaseAddr);\r
+ //\r
+ // Save Cmd register\r
+ //\r
+ SaveCmdData = PciRead16 (mIohEhciPciReg[Index] | R_IOH_USB_COMMAND);\r
+ //\r
+ // Enable EHCI on IOH\r
+ //\r
+ PciOr16 (mIohEhciPciReg[Index] | R_IOH_USB_COMMAND, B_IOH_USB_COMMAND_BME | B_IOH_USB_COMMAND_MSE );\r
+ //\r
+ // Clear CF register on EHCI\r
+ //\r
+ EhciCapLen = MmioRead8 (UsbBaseAddr + R_IOH_EHCI_CAPLENGTH);\r
+ MmioWrite32 (UsbBaseAddr + EhciCapLen + R_IOH_EHCI_CONFIGFLAGS, 0);\r
+\r
+ DEBUG ((EFI_D_INFO, "CF@EHCI = %x \n", UsbBaseAddr + EhciCapLen + R_IOH_EHCI_CONFIGFLAGS));\r
+ //\r
+ // Restore EHCI UsbBaseAddr in PCI space\r
+ //\r
+ PciWrite32 (mIohEhciPciReg[Index] | R_IOH_USB_MEMBAR, SavBaseAddr);\r
+ //\r
+ // Restore EHCI Command register in PCI space\r
+ //\r
+ PciWrite16(mIohEhciPciReg[Index] | R_IOH_USB_COMMAND, SaveCmdData);\r
+ }\r
+}\r
+/**\r
+ Retrieved specified the USB controller information.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This This PEI_USB_CONTROLLER_PPI instance.\r
+ @param UsbControllerId Indicate which usb controller information will be retrieved.\r
+ @param ControllerType Indicate the controller is Ehci, Ohci, OHCI\r
+ @param BaseAddress Indicate the memory bar of the controller\r
+\r
+ @retval EFI_SUCCESS The reset operation succeeded.\r
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+GetOhciController (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_CONTROLLER_PPI *This,\r
+ IN UINT8 UsbControllerId,\r
+ IN UINTN *ControllerType,\r
+ IN UINTN *BaseAddress\r
+ )\r
+{\r
+ IOH_OHCI_DEVICE *PeiIohOhciDev;\r
+\r
+ PeiIohOhciDev = IOH_OHCI_DEVICE_FROM_THIS (This);\r
+\r
+ if (UsbControllerId >= IOH_MAX_OHCI_USB_CONTROLLERS) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ *ControllerType = PEI_OHCI_CONTROLLER;\r
+ *BaseAddress = PeiIohOhciDev->MmioBase[UsbControllerId];\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Retrieved specified the USB controller information.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This This PEI_USB_CONTROLLER_PPI instance.\r
+ @param UsbControllerId Indicate which usb controller information will be retrieved.\r
+ @param ControllerType Indicate the controller is Ehci, Ohci, OHCI\r
+ @param BaseAddress Indicate the memory bar of the controller\r
+\r
+ @retval EFI_SUCCESS The reset operation succeeded.\r
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+GetEhciController (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_CONTROLLER_PPI *This,\r
+ IN UINT8 UsbControllerId,\r
+ IN UINTN *ControllerType,\r
+ IN UINTN *BaseAddress\r
+ )\r
+{\r
+ IOH_EHCI_DEVICE *PeiIohEhciDev;\r
+\r
+ PeiIohEhciDev = IOH_EHCI_DEVICE_FROM_THIS (This);\r
+\r
+ if (UsbControllerId >= IOH_MAX_EHCI_USB_CONTROLLERS) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ *ControllerType = PEI_EHCI_CONTROLLER;\r
+ *BaseAddress = PeiIohEhciDev->MmioBase[UsbControllerId];\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Retrieved specified the USB controller information.\r
+\r
+ @param IohOhciPciReg Ohci device address list.\r
+ @param OhciCount The count of the OHCI\r
+ @param IohEhciPciReg Ehci device address list.\r
+ @param EhciCount The count of the EHCI\r
+\r
+**/\r
+\r
+VOID\r
+EnableBusMaster (\r
+ IN UINTN IohOhciPciReg[],\r
+ IN UINT8 OhciCount,\r
+ IN UINTN IohEhciPciReg[],\r
+ IN UINT8 EhciCount\r
+ )\r
+{\r
+ UINT8 Index;\r
+ UINT16 CmdReg;\r
+ for (Index = 0; Index < OhciCount; Index ++) {\r
+ CmdReg = PciRead16 (IohOhciPciReg[Index] | R_IOH_USB_COMMAND);\r
+ CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_BME );\r
+ PciWrite16 (IohOhciPciReg[Index] | R_IOH_USB_COMMAND, CmdReg);\r
+ }\r
+ for (Index = 0; Index < EhciCount; Index ++) {\r
+ CmdReg = PciRead16 (IohEhciPciReg[Index] | R_IOH_USB_COMMAND);\r
+ CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_BME );\r
+ PciWrite16 (IohEhciPciReg[Index] | R_IOH_USB_COMMAND, CmdReg);\r
+ }\r
+}\r
+\r
+PEI_USB_CONTROLLER_PPI mUsbControllerPpi[2] = { {GetOhciController}, {GetEhciController}};\r
+\r
+/**\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS PPI successfully installed\r
+\r
+**/\r
+EFI_STATUS\r
+PeimInitializeIchUsb (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN i;\r
+ EFI_PHYSICAL_ADDRESS AllocateAddress;\r
+ IOH_OHCI_DEVICE *PeiIohOhciDev;\r
+ IOH_EHCI_DEVICE *PeiIohEhciDev;\r
+ UINT16 CmdReg;\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ 1,\r
+ &AllocateAddress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ EnableBusMaster (\r
+ mIohOhciPciReg,\r
+ IOH_MAX_OHCI_USB_CONTROLLERS,\r
+ mIohEhciPciReg,\r
+ IOH_MAX_EHCI_USB_CONTROLLERS\r
+ );\r
+\r
+ if (FeaturePcdGet (PcdEhciRecoveryEnabled)) {\r
+ DEBUG ((EFI_D_INFO, "UsbPei:EHCI is used for recovery\n"));\r
+ //\r
+ // EHCI recovery is enabled\r
+ //\r
+ PeiIohEhciDev = (IOH_EHCI_DEVICE *)((UINTN)AllocateAddress);\r
+ ZeroMem (PeiIohEhciDev, sizeof(IOH_EHCI_DEVICE));\r
+\r
+ PeiIohEhciDev->Signature = PEI_IOH_EHCI_SIGNATURE;\r
+ CopyMem(&(PeiIohEhciDev->UsbControllerPpi), &mUsbControllerPpi[1], sizeof(PEI_USB_CONTROLLER_PPI));\r
+ CopyMem(&(PeiIohEhciDev->PpiList), &mPpiList, sizeof(mPpiList));\r
+ PeiIohEhciDev->PpiList.Ppi = &PeiIohEhciDev->UsbControllerPpi;\r
+\r
+ //\r
+ // Assign resources and enable Ehci controllers\r
+ //\r
+ for (i = 0; i < IOH_MAX_EHCI_USB_CONTROLLERS; i++) {\r
+ DEBUG ((EFI_D_INFO, "UsbPei:Enable the %dth EHCI controller for recovery\n", i));\r
+ PeiIohEhciDev->MmioBase[i] = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress) + IOH_USB_CONTROLLER_MMIO_RANGE * i;\r
+ //\r
+ // Assign base address register, Enable Bus Master and Memory Io\r
+ //\r
+ PciWrite32 (mIohEhciPciReg[i] | R_IOH_USB_MEMBAR, PeiIohEhciDev->MmioBase[i]);\r
+ CmdReg = PciRead16 (mIohEhciPciReg[i] | R_IOH_USB_COMMAND);\r
+ CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_MSE | B_IOH_USB_COMMAND_BME );\r
+ PciWrite16 (mIohEhciPciReg[i] | R_IOH_USB_COMMAND, CmdReg);\r
+ }\r
+ //\r
+ // Install USB Controller PPI\r
+ //\r
+ Status = (**PeiServices).InstallPpi (\r
+ PeiServices,\r
+ &PeiIohEhciDev->PpiList\r
+ );\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "UsbPei:OHCI is used for recovery\n"));\r
+ //\r
+ // OHCI recovery is enabled\r
+ //\r
+ SwitchConfigFlag ((EFI_PEI_SERVICES**)PeiServices);\r
+ PeiIohOhciDev = (IOH_OHCI_DEVICE *)((UINTN)AllocateAddress);\r
+ ZeroMem (PeiIohOhciDev, sizeof(IOH_OHCI_DEVICE));\r
+\r
+ PeiIohOhciDev->Signature = PEI_IOH_OHCI_SIGNATURE;\r
+ CopyMem(&(PeiIohOhciDev->UsbControllerPpi), &mUsbControllerPpi[0], sizeof(PEI_USB_CONTROLLER_PPI));\r
+ CopyMem(&(PeiIohOhciDev->PpiList), &mPpiList, sizeof(mPpiList));\r
+ PeiIohOhciDev->PpiList.Ppi = &PeiIohOhciDev->UsbControllerPpi;\r
+ //\r
+ // Assign resources and enable OHCI controllers\r
+ //\r
+ for (i = 0; i < IOH_MAX_OHCI_USB_CONTROLLERS; i++) {\r
+ DEBUG ((EFI_D_INFO, "UsbPei:Enable the %dth OHCI controller for recovery\n", i));\r
+ PeiIohOhciDev->MmioBase[i] = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress) + IOH_USB_CONTROLLER_MMIO_RANGE * i;\r
+ //\r
+ // Assign base address register, Enable Bus Master and Memory Io\r
+ //\r
+ PciWrite32 (mIohOhciPciReg[i] | R_IOH_USB_MEMBAR, PeiIohOhciDev->MmioBase[i]);\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ 1,\r
+ &AllocateAddress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ MmioWrite32(PeiIohOhciDev->MmioBase[i] + R_IOH_USB_OHCI_HCCABAR, (UINT32)AllocateAddress);\r
+\r
+ CmdReg = PciRead16 (mIohOhciPciReg[i] | R_IOH_USB_COMMAND);\r
+ CmdReg = (UINT16) (CmdReg | B_IOH_USB_COMMAND_MSE | B_IOH_USB_COMMAND_BME );\r
+ PciWrite16 (mIohOhciPciReg[i] | R_IOH_USB_COMMAND, CmdReg);\r
+ }\r
+ //\r
+ // Install USB Controller PPI\r
+ //\r
+ Status = (**PeiServices).InstallPpi (\r
+ PeiServices,\r
+ &PeiIohOhciDev->PpiList\r
+ );\r
+\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+Define private data structure for UHCI and EHCI.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _USB_PEI_H\r
+#define _USB_PEI_H\r
+\r
+#include "Ioh.h"\r
+\r
+#define PEI_IOH_OHCI_SIGNATURE SIGNATURE_32 ('O', 'H', 'C', 'I')\r
+#define PEI_IOH_EHCI_SIGNATURE SIGNATURE_32 ('E', 'H', 'C', 'I')\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ PEI_USB_CONTROLLER_PPI UsbControllerPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR PpiList;\r
+ UINTN MmioBase[IOH_MAX_OHCI_USB_CONTROLLERS];\r
+} IOH_OHCI_DEVICE;\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ PEI_USB_CONTROLLER_PPI UsbControllerPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR PpiList;\r
+ UINTN MmioBase[IOH_MAX_EHCI_USB_CONTROLLERS];\r
+} IOH_EHCI_DEVICE;\r
+\r
+#define IOH_OHCI_DEVICE_FROM_THIS(a) \\r
+ CR(a, IOH_OHCI_DEVICE, UsbControllerPpi, PEI_IOH_OHCI_SIGNATURE)\r
+\r
+#define IOH_EHCI_DEVICE_FROM_THIS(a) \\r
+ CR (a, IOH_EHCI_DEVICE, UsbControllerPpi, PEI_IOH_EHCI_SIGNATURE)\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Component description file for UsbPei module.\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = UsbPei\r
+ FILE_GUID = 73E6F6B4-D029-4e87-8405-6067C8BD02A6\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = PeimInitializeIchUsb\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ UsbPei.c\r
+ UsbPei.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ IoLib\r
+ PciLib\r
+ PcdLib\r
+ BaseMemoryLib\r
+ PeimEntryPoint\r
+ DebugLib\r
+\r
+[Ppis]\r
+ gPeiUsbControllerPpiGuid # PPI ALWAYS_PRODUCED\r
+\r
+[FeaturePcd]\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdEhciRecoveryEnabled\r
+\r
+[Pcd]\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiQNCUsbControllerMemoryBaseAddress\r
+ gEfiQuarkSCSocIdTokenSpaceGuid.PcdPeiP2PMemoryBaseAddress\r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
--- /dev/null
+/** @file\r
+UEFI Component Name and Name2 protocol for OHCI driver.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "Ohci.h"\r
+\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gOhciComponentName = {\r
+ OhciComponentNameGetDriverName,\r
+ OhciComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2 = {\r
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) OhciComponentNameGetDriverName,\r
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) OhciComponentNameGetControllerName,\r
+ "en"\r
+};\r
+\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mOhciDriverNameTable[] = {\r
+ { "eng;en", L"Usb Ohci Driver" },\r
+ { NULL, NULL }\r
+};\r
+\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mOhciDriverNameTable,\r
+ DriverName,\r
+ (BOOLEAN)(This == &gOhciComponentName)\r
+ );\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ USB_OHCI_HC_DEV *OhciDev;\r
+ EFI_USB_HC_PROTOCOL *UsbHc;\r
+\r
+ //\r
+ // This is a device driver, so ChildHandle must be NULL.\r
+ //\r
+ if (ChildHandle != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Make sure this driver is currently managing ControllerHandle\r
+ //\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gOhciDriverBinding.DriverBindingHandle,\r
+ &gEfiPciIoProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Get the device context\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiUsbHcProtocolGuid,\r
+ (VOID **) &UsbHc,\r
+ gOhciDriverBinding.DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ OhciDev = USB_OHCI_HC_DEV_FROM_THIS (UsbHc);\r
+\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ OhciDev->ControllerNameTable,\r
+ ControllerName,\r
+ (BOOLEAN)(This == &gOhciComponentName)\r
+ );\r
+\r
+}\r
--- /dev/null
+/** @file\r
+This file contains the delarations for componet name routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _COMPONENT_NAME_H_\r
+#define _COMPONENT_NAME_H_\r
+\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+This file contains the descriptor definination of OHCI spec\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#ifndef _DESCRIPTOR_H\r
+#define _DESCRIPTOR_H\r
+\r
+#define ED_FUNC_ADD 0x0001\r
+#define ED_ENDPT_NUM 0x0002\r
+#define ED_DIR 0x0004\r
+#define ED_SPEED 0x0008\r
+#define ED_SKIP 0x0010\r
+#define ED_FORMAT 0x0020\r
+#define ED_MAX_PACKET 0x0040\r
+#define ED_TDTAIL_PTR 0x0080\r
+#define ED_HALTED 0x0100\r
+#define ED_DTTOGGLE 0x0200\r
+#define ED_TDHEAD_PTR 0x0400\r
+#define ED_NEXT_EDPTR 0x0800\r
+#define ED_PDATA 0x1000\r
+#define ED_ZERO 0x2000\r
+\r
+#define TD_BUFFER_ROUND 0x0001\r
+#define TD_DIR_PID 0x0002\r
+#define TD_DELAY_INT 0x0004\r
+#define TD_DT_TOGGLE 0x0008\r
+#define TD_ERROR_CNT 0x0010\r
+#define TD_COND_CODE 0x0020\r
+#define TD_CURR_BUFFER_PTR 0x0040\r
+#define TD_NEXT_PTR 0x0080\r
+#define TD_BUFFER_END_PTR 0x0100\r
+#define TD_PDATA 0x0200\r
+\r
+#define ED_FROM_TD_DIR 0x0\r
+#define ED_OUT_DIR 0x1\r
+#define ED_IN_DIR 0x2\r
+#define ED_FROM_TD_ALSO_DIR 0x3\r
+\r
+#define TD_SETUP_PID 0x00\r
+#define TD_OUT_PID 0x01\r
+#define TD_IN_PID 0x02\r
+#define TD_NODATA_PID 0x03\r
+\r
+#define HI_SPEED 0\r
+#define LO_SPEED 1\r
+\r
+#define TD_NO_ERROR 0x00\r
+#define TD_CRC_ERROR 0x01\r
+#define TD_BITSTUFFING_ERROR 0x02\r
+#define TD_TOGGLE_ERROR 0x03\r
+#define TD_DEVICE_STALL 0x04\r
+#define TD_NO_RESPONSE 0x05\r
+#define TD_PIDCHK_FAIL 0x06\r
+#define TD_PID_UNEXPECTED 0x07\r
+#define TD_DATA_OVERRUN 0x08\r
+#define TD_DATA_UNDERRUN 0x09\r
+#define TD_BUFFER_OVERRUN 0x0C\r
+#define TD_BUFFER_UNDERRUN 0x0D\r
+#define TD_TOBE_PROCESSED 0x0E\r
+#define TD_TOBE_PROCESSED_2 0x0F\r
+\r
+#define TD_NO_DELAY 0x7\r
+\r
+#define TD_INT 0x1\r
+#define TD_CTL 0x2\r
+#define TD_BLK 0x3\r
+\r
+typedef struct {\r
+ UINT32 Reserved:18;\r
+ UINT32 BufferRounding:1;\r
+ UINT32 DirPID:2;\r
+ UINT32 DelayInterrupt:3;\r
+ UINT32 DataToggle:2;\r
+ UINT32 ErrorCount:2;\r
+ UINT32 ConditionCode:4;\r
+} TD_DESCRIPTOR_WORD0;\r
+\r
+typedef struct _TD_DESCRIPTOR {\r
+ TD_DESCRIPTOR_WORD0 Word0;\r
+ UINT32 CurrBufferPointer; // 32-bit Physical Address of buffer\r
+ UINT32 NextTD; // 32-bit Physical Address of TD_DESCRIPTOR\r
+ UINT32 BufferEndPointer; // 32-bit Physical Address of buffer\r
+ UINT32 NextTDPointer; // 32-bit Physical Address of TD_DESCRIPTOR\r
+ UINT32 DataBuffer; // 32-bit Physical Address of buffer\r
+ UINT32 ActualSendLength;\r
+ UINT32 Reserved;\r
+} TD_DESCRIPTOR;\r
+\r
+typedef struct {\r
+ UINT32 FunctionAddress:7;\r
+ UINT32 EndPointNum:4;\r
+ UINT32 Direction:2;\r
+ UINT32 Speed:1;\r
+ UINT32 Skip:1;\r
+ UINT32 Format:1;\r
+ UINT32 MaxPacketSize:11;\r
+ UINT32 FreeSpace:5;\r
+} ED_DESCRIPTOR_WORD0;\r
+\r
+typedef struct {\r
+ UINT32 Halted:1;\r
+ UINT32 ToggleCarry:1;\r
+ UINT32 Zero:2;\r
+ UINT32 TdHeadPointer:28;\r
+} ED_DESCRIPTOR_WORD2;\r
+\r
+typedef struct _ED_DESCRIPTOR {\r
+ ED_DESCRIPTOR_WORD0 Word0;\r
+ UINT32 TdTailPointer; // 32-bit Physical Address of TD_DESCRIPTOR\r
+ ED_DESCRIPTOR_WORD2 Word2;\r
+ UINT32 NextED; // 32-bit Physical Address of ED_DESCRIPTOR\r
+} ED_DESCRIPTOR;\r
+\r
+#define TD_PTR(p) ((TD_DESCRIPTOR *)(UINTN)((p) << 4))\r
+#define ED_PTR(p) ((ED_DESCRIPTOR *)(UINTN)((p) << 4))\r
+#define RIGHT_SHIFT_4(p) ((UINT32)(p) >> 4)\r
+\r
+typedef enum {\r
+ CONTROL_LIST,\r
+ BULK_LIST,\r
+ INTERRUPT_LIST,\r
+ ISOCHRONOUS_LIST\r
+} DESCRIPTOR_LIST_TYPE;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This file contains the implementation of Usb Hc Protocol.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "Ohci.h"\r
+\r
+/**\r
+ Provides software reset for the USB host controller.\r
+\r
+ @param This This EFI_USB_HC_PROTOCOL instance.\r
+ @param Attributes A bit mask of the reset operation to perform.\r
+\r
+ @retval EFI_SUCCESS The reset operation succeeded.\r
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.\r
+ @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is\r
+ not currently supported by the host controller.\r
+ @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciReset (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT16 Attributes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ UINT8 Index;\r
+ UINT8 NumOfPorts;\r
+ UINT32 PowerOnGoodTime;\r
+ UINT32 Data32;\r
+ BOOLEAN Flag = FALSE;\r
+\r
+ if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+ if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) {\r
+ gBS->Stall (50 * 1000);\r
+ Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ gBS->Stall (50 * 1000);\r
+ //\r
+ // Wait for host controller reset.\r
+ //\r
+ PowerOnGoodTime = 50;\r
+ do {\r
+ gBS->Stall (1 * 1000);\r
+ Data32 = OhciGetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ if ((Data32 & HC_RESET) == 0) {\r
+ Flag = TRUE;\r
+ break;\r
+ }\r
+ }while(PowerOnGoodTime--);\r
+ if (!Flag){\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ OhciFreeIntTransferMemory (Ohc);\r
+ Status = OhciInitializeInterruptList (Ohc);\r
+ OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);\r
+ if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) {\r
+ Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ gBS->Stall (50 * 1000);\r
+ }\r
+ //\r
+ // Initialize host controller operational registers\r
+ //\r
+ OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778);\r
+ OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);\r
+ OhciSetPeriodicStart (Ohc, 0x2a2f);\r
+ OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x3);\r
+ OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0);\r
+ OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0);\r
+ OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1);\r
+ //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0);\r
+ //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1);\r
+\r
+ OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0);\r
+ OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff);\r
+ OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE);\r
+ OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER);\r
+ OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
+ for (Index = 0; Index < NumOfPorts; Index++) {\r
+ if (!EFI_ERROR (OhciSetRootHubPortFeature (This, Index, EfiUsbPortReset))) {\r
+ gBS->Stall (200 * 1000);\r
+ OhciClearRootHubPortFeature (This, Index, EfiUsbPortReset);\r
+ gBS->Stall (1000);\r
+ OhciSetRootHubPortFeature (This, Index, EfiUsbPortEnable);\r
+ gBS->Stall (1000);\r
+ }\r
+ }\r
+ OhciSetMemoryPointer (Ohc, HC_HCCA, Ohc->HccaMemoryBlock);\r
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
+ OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | BULK_ENABLE, 1); /*ISOCHRONOUS_ENABLE*/\r
+ OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);\r
+ gBS->Stall (50*1000);\r
+ //\r
+ // Wait till first SOF occurs, and then clear it\r
+ //\r
+ while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0);\r
+ OhciClearInterruptStatus (Ohc, START_OF_FRAME);\r
+ gBS->Stall (1000);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Retrieve the current state of the USB host controller.\r
+\r
+ @param This This EFI_USB_HC_PROTOCOL instance.\r
+ @param State Variable to return the current host controller\r
+ state.\r
+\r
+ @retval EFI_SUCCESS Host controller state was returned in State.\r
+ @retval EFI_INVALID_PARAMETER State is NULL.\r
+ @retval EFI_DEVICE_ERROR An error was encountered while attempting to\r
+ retrieve the host controller's current state.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetState (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ OUT EFI_USB_HC_STATE *State\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ UINT32 FuncState;\r
+\r
+ if (State == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+ FuncState = OhciGetHcControl (Ohc, HC_FUNCTIONAL_STATE);\r
+\r
+ switch (FuncState) {\r
+ case HC_STATE_RESET:\r
+ case HC_STATE_RESUME:\r
+ *State = EfiUsbHcStateHalt;\r
+ break;\r
+\r
+ case HC_STATE_OPERATIONAL:\r
+ *State = EfiUsbHcStateOperational;\r
+ break;\r
+\r
+ case HC_STATE_SUSPEND:\r
+ *State = EfiUsbHcStateSuspend;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Sets the USB host controller to a specific state.\r
+\r
+ @param This This EFI_USB_HC_PROTOCOL instance.\r
+ @param State The state of the host controller that will be set.\r
+\r
+ @retval EFI_SUCCESS The USB host controller was successfully placed\r
+ in the state specified by State.\r
+ @retval EFI_INVALID_PARAMETER State is invalid.\r
+ @retval EFI_DEVICE_ERROR Failed to set the state due to device error.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciSetState(\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN EFI_USB_HC_STATE State\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ USB_OHCI_HC_DEV *Ohc;\r
+\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS(This);\r
+\r
+ switch (State) {\r
+ case EfiUsbHcStateHalt:\r
+ Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);\r
+ break;\r
+\r
+ case EfiUsbHcStateOperational:\r
+ Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);\r
+ break;\r
+\r
+ case EfiUsbHcStateSuspend:\r
+ Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_SUSPEND);\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ gBS->Stall (1000);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Submits control transfer to a target USB device.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param IsSlowDevice Indicates whether the target device is slow device\r
+ or full-speed device.\r
+ @param MaxPaketLength Indicates the maximum packet size that the\r
+ default control transfer endpoint is capable of\r
+ sending or receiving.\r
+ @param Request A pointer to the USB device request that will be sent\r
+ to the USB device.\r
+ @param TransferDirection Specifies the data direction for the transfer.\r
+ There are three values available, DataIn, DataOut\r
+ and NoData.\r
+ @param Data A pointer to the buffer of data that will be transmitted\r
+ to USB device or received from USB device.\r
+ @param DataLength Indicates the size, in bytes, of the data buffer\r
+ specified by Data.\r
+ @param TimeOut Indicates the maximum time, in microseconds,\r
+ which the transfer is allowed to complete.\r
+ @param TransferResult A pointer to the detailed result information generated\r
+ by this control transfer.\r
+\r
+ @retval EFI_SUCCESS The control transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT The control transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error.\r
+ Caller should check TranferResult for detailed error information.\r
+\r
+--*/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciControlTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN BOOLEAN IsSlowDevice,\r
+ IN UINT8 MaxPacketLength,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data OPTIONAL,\r
+ IN OUT UINTN *DataLength OPTIONAL,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ ED_DESCRIPTOR *HeadEd;\r
+ ED_DESCRIPTOR *Ed;\r
+ TD_DESCRIPTOR *HeadTd;\r
+ TD_DESCRIPTOR *SetupTd;\r
+ TD_DESCRIPTOR *DataTd;\r
+ TD_DESCRIPTOR *StatusTd;\r
+ TD_DESCRIPTOR *EmptyTd;\r
+ EFI_STATUS Status;\r
+ UINT32 DataPidDir;\r
+ UINT32 StatusPidDir;\r
+ UINTN TimeCount;\r
+ OHCI_ED_RESULT EdResult;\r
+\r
+ EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
+\r
+ UINTN ActualSendLength;\r
+ UINTN LeftLength;\r
+ UINT8 DataToggle;\r
+\r
+ VOID *ReqMapping = NULL;\r
+ UINTN ReqMapLength = 0;\r
+ EFI_PHYSICAL_ADDRESS ReqMapPhyAddr = 0;\r
+\r
+ VOID *DataMapping = NULL;\r
+ UINTN DataMapLength = 0;\r
+ EFI_PHYSICAL_ADDRESS DataMapPhyAddr = 0;\r
+\r
+ HeadTd = NULL;\r
+ DataTd = NULL;\r
+\r
+ if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn &&\r
+ TransferDirection != EfiUsbNoData) ||\r
+ Request == NULL || DataLength == NULL || TransferResult == NULL ||\r
+ (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) ||\r
+ (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) ||\r
+ (IsSlowDevice && MaxPacketLength != 8) ||\r
+ (MaxPacketLength != 8 && MaxPacketLength != 16 &&\r
+ MaxPacketLength != 32 && MaxPacketLength != 64)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (*DataLength > MAX_BYTES_PER_TD) {\r
+ DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\r\n"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS(This);\r
+\r
+ if (TransferDirection == EfiUsbDataIn) {\r
+ DataPidDir = TD_IN_PID;\r
+ StatusPidDir = TD_OUT_PID;\r
+ } else {\r
+ DataPidDir = TD_OUT_PID;\r
+ StatusPidDir = TD_IN_PID;\r
+ }\r
+\r
+ Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_ENABLE\r\n"));\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 0);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable CONTROL_LIST_FILLED\r\n"));\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ gBS->Stall(20 * 1000);\r
+\r
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
+ Ed = OhciCreateED (Ohc);\r
+ if (Ed == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\r\n"));\r
+ goto CTRL_EXIT;\r
+ }\r
+ OhciSetEDField (Ed, ED_SKIP, 1);\r
+ OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
+ OhciSetEDField (Ed, ED_ENDPT_NUM, 0);\r
+ OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
+ OhciSetEDField (Ed, ED_SPEED, IsSlowDevice);\r
+ OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);\r
+ OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
+ OhciSetEDField (Ed, ED_PDATA, 0);\r
+ OhciSetEDField (Ed, ED_ZERO, 0);\r
+ OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);\r
+ OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);\r
+ OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);\r
+ HeadEd = OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL);\r
+ //\r
+ // Setup Stage\r
+ //\r
+ if(Request != NULL) {\r
+ ReqMapLength = sizeof(EFI_USB_DEVICE_REQUEST);\r
+ MapOp = EfiPciIoOperationBusMasterRead;\r
+ Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Request, &ReqMapLength, &ReqMapPhyAddr, &ReqMapping);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to Map Request Buffer\r\n"));\r
+ goto FREE_ED_BUFF;\r
+ }\r
+ }\r
+ SetupTd = OhciCreateTD (Ohc);\r
+ if (SetupTd == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\r\n"));\r
+ goto UNMAP_SETUP_BUFF;\r
+ }\r
+ HeadTd = SetupTd;\r
+ OhciSetTDField (SetupTd, TD_PDATA, 0);\r
+ OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1);\r
+ OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID);\r
+ OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY);\r
+ OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2);\r
+ OhciSetTDField (SetupTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+ OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINT32)ReqMapPhyAddr);\r
+ OhciSetTDField (SetupTd, TD_NEXT_PTR, 0);\r
+ OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINT32)(ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1));\r
+ SetupTd->ActualSendLength = sizeof (EFI_USB_DEVICE_REQUEST);\r
+ SetupTd->DataBuffer = (UINT32)ReqMapPhyAddr;\r
+ SetupTd->NextTDPointer = 0;\r
+\r
+ if (TransferDirection == EfiUsbDataIn) {\r
+ MapOp = EfiPciIoOperationBusMasterWrite;\r
+ } else {\r
+ MapOp = EfiPciIoOperationBusMasterRead;\r
+ }\r
+ DataMapLength = *DataLength;\r
+ if ((Data != NULL) && (DataMapLength != 0)) {\r
+ Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, Data, &DataMapLength, &DataMapPhyAddr, &DataMapping);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail To Map Data Buffer\r\n"));\r
+ goto FREE_TD_BUFF;\r
+ }\r
+ }\r
+ //\r
+ //Data Stage\r
+ //\r
+ LeftLength = DataMapLength;\r
+ ActualSendLength = DataMapLength;\r
+ DataToggle = 1;\r
+ while (LeftLength > 0) {\r
+ ActualSendLength = LeftLength;\r
+ if (LeftLength > MaxPacketLength) {\r
+ ActualSendLength = MaxPacketLength;\r
+ }\r
+ DataTd = OhciCreateTD (Ohc);\r
+ if (DataTd == NULL) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Data Stage TD\r\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto UNMAP_DATA_BUFF;\r
+ }\r
+ OhciSetTDField (DataTd, TD_PDATA, 0);\r
+ OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
+ OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
+ OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle);\r
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+ OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr);\r
+ OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(DataMapPhyAddr + ActualSendLength - 1));\r
+ OhciSetTDField (DataTd, TD_NEXT_PTR, 0);\r
+ DataTd->ActualSendLength = (UINT32)ActualSendLength;\r
+ DataTd->DataBuffer = (UINT32)DataMapPhyAddr;\r
+ DataTd->NextTDPointer = 0;\r
+ OhciLinkTD (HeadTd, DataTd);\r
+ DataToggle ^= 1;\r
+ DataMapPhyAddr += ActualSendLength;\r
+ LeftLength -= ActualSendLength;\r
+ }\r
+ //\r
+ // Status Stage\r
+ //\r
+ StatusTd = OhciCreateTD (Ohc);\r
+ if (StatusTd == NULL) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate buffer for Status Stage TD\r\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto UNMAP_DATA_BUFF;\r
+ }\r
+ OhciSetTDField (StatusTd, TD_PDATA, 0);\r
+ OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1);\r
+ OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir);\r
+ OhciSetTDField (StatusTd, TD_DELAY_INT, 7);\r
+ OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3);\r
+ OhciSetTDField (StatusTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+ OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, 0);\r
+ OhciSetTDField (StatusTd, TD_NEXT_PTR, 0);\r
+ OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, 0);\r
+ StatusTd->ActualSendLength = 0;\r
+ StatusTd->DataBuffer = 0;\r
+ StatusTd->NextTDPointer = 0;\r
+ OhciLinkTD (HeadTd, StatusTd);\r
+ //\r
+ // Empty Stage\r
+ //\r
+ EmptyTd = OhciCreateTD (Ohc);\r
+ if (EmptyTd == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto UNMAP_DATA_BUFF;\r
+ }\r
+ OhciSetTDField (EmptyTd, TD_PDATA, 0);\r
+ OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);\r
+ OhciSetTDField (EmptyTd, TD_DIR_PID, 0);\r
+ OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);\r
+ //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);\r
+ EmptyTd->Word0.DataToggle = 0;\r
+ OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (EmptyTd, TD_COND_CODE, 0);\r
+ OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);\r
+ OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);\r
+ OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);\r
+ EmptyTd->ActualSendLength = 0;\r
+ EmptyTd->DataBuffer = 0;\r
+ EmptyTd->NextTDPointer = 0;\r
+ OhciLinkTD (HeadTd, EmptyTd);\r
+ Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd;\r
+ OhciAttachTDListToED (Ed, HeadTd);\r
+ //\r
+ // For debugging, dump ED & TD buffer befor transferring\r
+ //\r
+ //\r
+ //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, TRUE);\r
+ //\r
+ OhciSetEDField (Ed, ED_SKIP, 0);\r
+ Status = OhciSetHcControl (Ohc, CONTROL_ENABLE, 1);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_ENABLE\r\n"));\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto UNMAP_DATA_BUFF;\r
+ }\r
+ Status = OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to enable CONTROL_LIST_FILLED\r\n"));\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto UNMAP_DATA_BUFF;\r
+ }\r
+ gBS->Stall(20 * 1000);\r
+\r
+\r
+ TimeCount = 0;\r
+ Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult);\r
+\r
+ while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {\r
+ gBS->Stall (1000);\r
+ TimeCount++;\r
+ Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &EdResult);\r
+ }\r
+ //\r
+ // For debugging, dump ED & TD buffer after transferring\r
+ //\r
+ //OhciDumpEdTdInfo (Ohc, Ed, HeadTd, FALSE);\r
+ //\r
+ *TransferResult = ConvertErrorCode (EdResult.ErrorCode);\r
+\r
+ if (EdResult.ErrorCode != TD_NO_ERROR) {\r
+ if (EdResult.ErrorCode == TD_TOBE_PROCESSED) {\r
+ DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Control pipe broken\r\n"));\r
+ }\r
+ *DataLength = 0;\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Control transfer successed\r\n"));\r
+ }\r
+\r
+UNMAP_DATA_BUFF:\r
+ OhciSetEDField (Ed, ED_SKIP, 1);\r
+ if (HeadEd == Ed) {\r
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
+ } else {\r
+ HeadEd->NextED = Ed->NextED;\r
+ }\r
+ if(DataMapping != NULL) {\r
+ Ohc->PciIo->Unmap(Ohc->PciIo, DataMapping);\r
+ }\r
+\r
+FREE_TD_BUFF:\r
+ while (HeadTd) {\r
+ DataTd = HeadTd;\r
+ HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
+ UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
+ }\r
+\r
+UNMAP_SETUP_BUFF:\r
+ if(ReqMapping != NULL) {\r
+ Ohc->PciIo->Unmap(Ohc->PciIo, ReqMapping);\r
+ }\r
+\r
+FREE_ED_BUFF:\r
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
+\r
+CTRL_EXIT:\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress The combination of an endpoint number and an\r
+ endpoint direction of the target USB device.\r
+ Each endpoint address supports data transfer in\r
+ one direction except the control endpoint\r
+ (whose default endpoint address is 0).\r
+ It is the caller's responsibility to make sure that\r
+ the EndPointAddress represents a bulk endpoint.\r
+ @param MaximumPacketLength Indicates the maximum packet size the target endpoint\r
+ is capable of sending or receiving.\r
+ @param Data A pointer to the buffer of data that will be transmitted\r
+ to USB device or received from USB device.\r
+ @param DataLength When input, indicates the size, in bytes, of the data buffer\r
+ specified by Data. When output, indicates the actually\r
+ transferred data size.\r
+ @param DataToggle A pointer to the data toggle value. On input, it indicates\r
+ the initial data toggle value the bulk transfer should adopt;\r
+ on output, it is updated to indicate the data toggle value\r
+ of the subsequent bulk transfer.\r
+ @param TimeOut Indicates the maximum time, in microseconds, which the\r
+ transfer is allowed to complete.\r
+ TransferResult A pointer to the detailed result information of the\r
+ bulk transfer.\r
+\r
+ @retval EFI_SUCCESS The bulk transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT The bulk transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error.\r
+ Caller should check TranferResult for detailed error information.\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciBulkTransfer(\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaxPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ ED_DESCRIPTOR *HeadEd;\r
+ ED_DESCRIPTOR *Ed;\r
+ UINT8 EdDir;\r
+ UINT32 DataPidDir;\r
+ TD_DESCRIPTOR *HeadTd;\r
+ TD_DESCRIPTOR *DataTd;\r
+ TD_DESCRIPTOR *EmptyTd;\r
+ EFI_STATUS Status;\r
+ EFI_USB_DATA_DIRECTION TransferDirection;\r
+ UINT8 EndPointNum;\r
+ UINTN TimeCount;\r
+ OHCI_ED_RESULT EdResult;\r
+\r
+ EFI_PCI_IO_PROTOCOL_OPERATION MapOp;\r
+ VOID *Mapping;\r
+ UINTN MapLength;\r
+ EFI_PHYSICAL_ADDRESS MapPyhAddr;\r
+ UINTN LeftLength;\r
+ UINTN ActualSendLength;\r
+ BOOLEAN FirstTD;\r
+\r
+ Mapping = NULL;\r
+ MapLength = 0;\r
+ MapPyhAddr = 0;\r
+ LeftLength = 0;\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL ||\r
+ *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) ||\r
+ (MaxPacketLength != 8 && MaxPacketLength != 16 &&\r
+ MaxPacketLength != 32 && MaxPacketLength != 64)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+ if ((EndPointAddress & 0x80) != 0) {\r
+ TransferDirection = EfiUsbDataIn;\r
+ EdDir = ED_IN_DIR;\r
+ DataPidDir = TD_IN_PID;\r
+ MapOp = EfiPciIoOperationBusMasterWrite;\r
+ } else {\r
+ TransferDirection = EfiUsbDataOut;\r
+ EdDir = ED_OUT_DIR;\r
+ DataPidDir = TD_OUT_PID;\r
+ MapOp = EfiPciIoOperationBusMasterRead;\r
+ }\r
+\r
+ EndPointNum = (EndPointAddress & 0xF);\r
+ EdResult.NextToggle = *DataToggle;\r
+\r
+ Status = OhciSetHcControl (Ohc, BULK_ENABLE, 0);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_ENABLE\r\n"));\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 0);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: fail to disable BULK_LIST_FILLED\r\n"));\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ gBS->Stall(20 * 1000);\r
+\r
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
+\r
+ Ed = OhciCreateED (Ohc);\r
+ if (Ed == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ OhciSetEDField (Ed, ED_SKIP, 1);\r
+ OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
+ OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);\r
+ OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
+ OhciSetEDField (Ed, ED_SPEED, HI_SPEED);\r
+ OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);\r
+ OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
+ OhciSetEDField (Ed, ED_PDATA, 0);\r
+ OhciSetEDField (Ed, ED_ZERO, 0);\r
+ OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);\r
+ OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);\r
+ OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);\r
+ HeadEd = OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL);\r
+\r
+ if(Data != NULL) {\r
+ MapLength = *DataLength;\r
+ Status = Ohc->PciIo->Map (Ohc->PciIo, MapOp, (UINT8 *)Data, &MapLength, &MapPyhAddr, &Mapping);\r
+ if (EFI_ERROR(Status)) {\r
+ DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to Map Data Buffer for Bulk\r\n"));\r
+ goto FREE_ED_BUFF;\r
+ }\r
+ }\r
+ //\r
+ //Data Stage\r
+ //\r
+ LeftLength = MapLength;\r
+ ActualSendLength = MapLength;\r
+ HeadTd = NULL;\r
+ FirstTD = TRUE;\r
+ while (LeftLength > 0) {\r
+ ActualSendLength = LeftLength;\r
+ if (LeftLength > MaxPacketLength) {\r
+ ActualSendLength = MaxPacketLength;\r
+ }\r
+ DataTd = OhciCreateTD (Ohc);\r
+ if (DataTd == NULL) {\r
+ DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Data Stage TD\r\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FREE_OHCI_TDBUFF;\r
+ }\r
+ OhciSetTDField (DataTd, TD_PDATA, 0);\r
+ OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
+ OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
+ OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);\r
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+ OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);\r
+ OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));\r
+ OhciSetTDField (DataTd, TD_NEXT_PTR, 0);\r
+ DataTd->ActualSendLength = (UINT32)ActualSendLength;\r
+ DataTd->DataBuffer = (UINT32)MapPyhAddr;\r
+ DataTd->NextTDPointer = 0;\r
+ if (FirstTD) {\r
+ HeadTd = DataTd;\r
+ FirstTD = FALSE;\r
+ } else {\r
+ OhciLinkTD (HeadTd, DataTd);\r
+ }\r
+ *DataToggle ^= 1;\r
+ MapPyhAddr += ActualSendLength;\r
+ LeftLength -= ActualSendLength;\r
+ }\r
+ //\r
+ // Empty Stage\r
+ //\r
+ EmptyTd = OhciCreateTD (Ohc);\r
+ if (EmptyTd == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((EFI_D_INFO, "OhciBulkTransfer: Fail to allocate buffer for Empty TD\r\n"));\r
+ goto FREE_OHCI_TDBUFF;\r
+ }\r
+ OhciSetTDField (EmptyTd, TD_PDATA, 0);\r
+ OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);\r
+ OhciSetTDField (EmptyTd, TD_DIR_PID, 0);\r
+ OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);\r
+ //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);\r
+ EmptyTd->Word0.DataToggle = 0;\r
+ OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (EmptyTd, TD_COND_CODE, 0);\r
+ OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);\r
+ OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);\r
+ OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);\r
+ EmptyTd->ActualSendLength = 0;\r
+ EmptyTd->DataBuffer = 0;\r
+ EmptyTd->NextTDPointer = 0;\r
+ OhciLinkTD (HeadTd, EmptyTd);\r
+ Ed->TdTailPointer = (UINT32)(UINTN)EmptyTd;\r
+ OhciAttachTDListToED (Ed, HeadTd);\r
+\r
+ OhciSetEDField (Ed, ED_SKIP, 0);\r
+ Status = OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1);\r
+ if (EFI_ERROR(Status)) {\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_LIST_FILLED\r\n"));\r
+ goto FREE_OHCI_TDBUFF;\r
+ }\r
+ Status = OhciSetHcControl (Ohc, BULK_ENABLE, 1);\r
+ if (EFI_ERROR(Status)) {\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable BULK_ENABLE\r\n"));\r
+ goto FREE_OHCI_TDBUFF;\r
+ }\r
+ gBS->Stall(20 * 1000);\r
+\r
+ TimeCount = 0;\r
+ Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);\r
+ while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {\r
+ gBS->Stall (1000);\r
+ TimeCount++;\r
+ Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &EdResult);\r
+ }\r
+\r
+ *TransferResult = ConvertErrorCode (EdResult.ErrorCode);\r
+\r
+ if (EdResult.ErrorCode != TD_NO_ERROR) {\r
+ if (EdResult.ErrorCode == TD_TOBE_PROCESSED) {\r
+ DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n"));\r
+ *DataToggle = EdResult.NextToggle;\r
+ }\r
+ *DataLength = 0;\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Bulk transfer successed\r\n"));\r
+ }\r
+ //*DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);\r
+\r
+FREE_OHCI_TDBUFF:\r
+ OhciSetEDField (Ed, ED_SKIP, 1);\r
+ if (HeadEd == Ed) {\r
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
+ }else {\r
+ HeadEd->NextED = Ed->NextED;\r
+ }\r
+ while (HeadTd) {\r
+ DataTd = HeadTd;\r
+ HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
+ UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
+ }\r
+\r
+ if(Mapping != NULL) {\r
+ Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);\r
+ }\r
+\r
+FREE_ED_BUFF:\r
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
+\r
+ return Status;\r
+}\r
+/**\r
+\r
+ Submits an interrupt transfer to an interrupt endpoint of a USB device.\r
+\r
+ @param Ohc Device private data\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress The combination of an endpoint number and an endpoint\r
+ direction of the target USB device. Each endpoint address\r
+ supports data transfer in one direction except the\r
+ control endpoint (whose default endpoint address is 0).\r
+ It is the caller's responsibility to make sure that\r
+ the EndPointAddress represents an interrupt endpoint.\r
+ @param IsSlowDevice Indicates whether the target device is slow device\r
+ or full-speed device.\r
+ @param MaxPacketLength Indicates the maximum packet size the target endpoint\r
+ is capable of sending or receiving.\r
+ @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between\r
+ the host and the target interrupt endpoint.\r
+ If FALSE, the specified asynchronous interrupt pipe\r
+ is canceled.\r
+ @param DataToggle A pointer to the data toggle value. On input, it is valid\r
+ when IsNewTransfer is TRUE, and it indicates the initial\r
+ data toggle value the asynchronous interrupt transfer\r
+ should adopt.\r
+ On output, it is valid when IsNewTransfer is FALSE,\r
+ and it is updated to indicate the data toggle value of\r
+ the subsequent asynchronous interrupt transfer.\r
+ @param PollingInterval Indicates the interval, in milliseconds, that the\r
+ asynchronous interrupt transfer is polled.\r
+ This parameter is required when IsNewTransfer is TRUE.\r
+ @param UCBuffer Uncacheable buffer\r
+ @param DataLength Indicates the length of data to be received at the\r
+ rate specified by PollingInterval from the target\r
+ asynchronous interrupt endpoint. This parameter\r
+ is only required when IsNewTransfer is TRUE.\r
+ @param CallBackFunction The Callback function.This function is called at the\r
+ rate specified by PollingInterval.This parameter is\r
+ only required when IsNewTransfer is TRUE.\r
+ @param Context The context that is passed to the CallBackFunction.\r
+ This is an optional parameter and may be NULL.\r
+ @param IsPeriodic Periodic interrupt or not\r
+ @param OutputED The correspoding ED carried out\r
+ @param OutputTD The correspoding TD carried out\r
+\r
+\r
+ @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully\r
+ submitted or canceled.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciInterruptTransfer (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN BOOLEAN IsSlowDevice,\r
+ IN UINT8 MaxPacketLength,\r
+ IN BOOLEAN IsNewTransfer,\r
+ IN OUT UINT8 *DataToggle OPTIONAL,\r
+ IN UINTN PollingInterval OPTIONAL,\r
+ IN VOID *UCBuffer OPTIONAL,\r
+ IN UINTN DataLength OPTIONAL,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,\r
+ IN VOID *Context OPTIONAL,\r
+ IN BOOLEAN IsPeriodic OPTIONAL,\r
+ OUT ED_DESCRIPTOR **OutputED OPTIONAL,\r
+ OUT TD_DESCRIPTOR **OutputTD OPTIONAL\r
+ )\r
+{\r
+ ED_DESCRIPTOR *Ed;\r
+ UINT8 EdDir;\r
+ ED_DESCRIPTOR *HeadEd;\r
+ TD_DESCRIPTOR *HeadTd;\r
+ TD_DESCRIPTOR *DataTd;\r
+ TD_DESCRIPTOR *EmptTd;\r
+ UINTN Depth;\r
+ UINTN Index;\r
+ EFI_STATUS Status;\r
+ UINT8 EndPointNum;\r
+ UINT32 DataPidDir;\r
+ EFI_USB_DATA_DIRECTION TransferDirection;\r
+ INTERRUPT_CONTEXT_ENTRY *Entry;\r
+ EFI_TPL OldTpl;\r
+ BOOLEAN FirstTD;\r
+\r
+ VOID *Mapping;\r
+ UINTN MapLength;\r
+ EFI_PHYSICAL_ADDRESS MapPyhAddr;\r
+ UINTN LeftLength;\r
+ UINTN ActualSendLength;\r
+\r
+\r
+ if (DataLength > MAX_BYTES_PER_TD) {\r
+ DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Error param\r\n"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((EndPointAddress & 0x80) != 0) {\r
+ TransferDirection = EfiUsbDataIn;\r
+ EdDir = ED_IN_DIR;\r
+ DataPidDir = TD_IN_PID;\r
+ } else {\r
+ TransferDirection = EfiUsbDataOut;\r
+ EdDir = ED_OUT_DIR;\r
+ DataPidDir = TD_OUT_PID;\r
+ }\r
+\r
+ EndPointNum = (EndPointAddress & 0xF);\r
+\r
+ if (!IsNewTransfer) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ OhciSetHcControl (Ohc, PERIODIC_ENABLE, 0);\r
+ OhciFreeInterruptContext (Ohc, DeviceAddress, EndPointAddress, DataToggle);\r
+ Status = OhciFreeInterruptEdByAddr (Ohc, DeviceAddress, EndPointNum);\r
+ OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+ }\r
+ MapLength = DataLength;\r
+ Status = Ohc->PciIo->Map(\r
+ Ohc->PciIo,\r
+ EfiPciIoOperationBusMasterWrite,\r
+ UCBuffer,\r
+ &MapLength,\r
+ &MapPyhAddr,\r
+ &Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Failt to PciIo->Map buffer \r\n"));\r
+ goto EXIT;\r
+ }\r
+ Depth = 5;\r
+ Index = 1;\r
+ while (PollingInterval >= Index * 2 && Depth > 0) {\r
+ Index *= 2;\r
+ Depth--;\r
+ }\r
+ //\r
+ //ED Stage\r
+ //\r
+ HeadEd = OhciFindMinInterruptEDList (Ohc, (UINT32)Depth);\r
+ if ((Ed = OhciFindWorkingEd (HeadEd, DeviceAddress, EndPointNum, EdDir)) != NULL) {\r
+ OhciSetEDField (Ed, ED_SKIP, 1);\r
+ } else {\r
+ Ed = OhciCreateED (Ohc);\r
+ if (Ed == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for ED\r\n"));\r
+ goto UNMAP_OHCI_XBUFF;\r
+ }\r
+ OhciSetEDField (Ed, ED_SKIP, 1);\r
+ OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
+ OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);\r
+ OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
+ OhciSetEDField (Ed, ED_SPEED, IsSlowDevice);\r
+ OhciSetEDField (Ed, ED_FORMAT, 0);\r
+ OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
+ OhciSetEDField (Ed, ED_PDATA | ED_ZERO | ED_HALTED | ED_DTTOGGLE, 0);\r
+ OhciSetEDField (Ed, ED_TDHEAD_PTR, 0);\r
+ OhciSetEDField (Ed, ED_TDTAIL_PTR, 0);\r
+ OhciSetEDField (Ed, ED_NEXT_EDPTR, 0);\r
+ OhciAttachEDToList (Ohc, INTERRUPT_LIST, Ed, HeadEd);\r
+ }\r
+ //\r
+ //Data Stage\r
+ //\r
+ LeftLength = MapLength;\r
+ ActualSendLength = MapLength;\r
+ HeadTd = NULL;\r
+ FirstTD = TRUE;\r
+ while (LeftLength > 0) {\r
+ ActualSendLength = LeftLength;\r
+ if (LeftLength > MaxPacketLength) {\r
+ ActualSendLength = MaxPacketLength;\r
+ }\r
+ DataTd = OhciCreateTD (Ohc);\r
+ if (DataTd == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Data Stage TD\r\n"));\r
+ goto FREE_OHCI_TDBUFF;\r
+ }\r
+ OhciSetTDField (DataTd, TD_PDATA, 0);\r
+ OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
+ OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
+ OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, *DataToggle);\r
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+ OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);\r
+ OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32)(MapPyhAddr + ActualSendLength - 1));\r
+ OhciSetTDField (DataTd, TD_NEXT_PTR, 0);\r
+ DataTd->ActualSendLength = (UINT32)ActualSendLength;\r
+ DataTd->DataBuffer = (UINT32)MapPyhAddr;\r
+ DataTd->NextTDPointer = 0;\r
+ if (FirstTD) {\r
+ HeadTd = DataTd;\r
+ FirstTD = FALSE;\r
+ } else {\r
+ OhciLinkTD (HeadTd, DataTd);\r
+ }\r
+ *DataToggle ^= 1;\r
+ MapPyhAddr += ActualSendLength;\r
+ LeftLength -= ActualSendLength;\r
+ }\r
+\r
+ EmptTd = OhciCreateTD (Ohc);\r
+ if (EmptTd == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((EFI_D_ERROR, "OhciInterruptTransfer: Fail to allocate buffer for Empty Stage TD\r\n"));\r
+ goto FREE_OHCI_TDBUFF;\r
+ }\r
+ OhciSetTDField (EmptTd, TD_PDATA, 0);\r
+ OhciSetTDField (EmptTd, TD_BUFFER_ROUND, 0);\r
+ OhciSetTDField (EmptTd, TD_DIR_PID, 0);\r
+ OhciSetTDField (EmptTd, TD_DELAY_INT, 0);\r
+ //OhciSetTDField (EmptTd, TD_DT_TOGGLE, CurrentToggle);\r
+ EmptTd->Word0.DataToggle = 0;\r
+ OhciSetTDField (EmptTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (EmptTd, TD_COND_CODE, 0);\r
+ OhciSetTDField (EmptTd, TD_CURR_BUFFER_PTR, 0);\r
+ OhciSetTDField (EmptTd, TD_BUFFER_END_PTR, 0);\r
+ OhciSetTDField (EmptTd, TD_NEXT_PTR, 0);\r
+ EmptTd->ActualSendLength = 0;\r
+ EmptTd->DataBuffer = 0;\r
+ EmptTd->NextTDPointer = 0;\r
+ OhciLinkTD (HeadTd, EmptTd);\r
+ Ed->TdTailPointer = (UINT32)(UINTN)EmptTd;\r
+ OhciAttachTDListToED (Ed, HeadTd);\r
+\r
+ if (OutputED != NULL) {\r
+ *OutputED = Ed;\r
+ }\r
+ if (OutputTD != NULL) {\r
+ *OutputTD = HeadTd;\r
+ }\r
+\r
+ if (CallBackFunction != NULL) {\r
+ Entry = AllocatePool (sizeof (INTERRUPT_CONTEXT_ENTRY));\r
+ if (Entry == NULL) {\r
+ goto FREE_OHCI_TDBUFF;\r
+ }\r
+\r
+ Entry->DeviceAddress = DeviceAddress;\r
+ Entry->EndPointAddress = EndPointAddress;\r
+ Entry->Ed = Ed;\r
+ Entry->DataTd = HeadTd;\r
+ Entry->IsSlowDevice = IsSlowDevice;\r
+ Entry->MaxPacketLength = MaxPacketLength;\r
+ Entry->PollingInterval = PollingInterval;\r
+ Entry->CallBackFunction = CallBackFunction;\r
+ Entry->Context = Context;\r
+ Entry->IsPeriodic = IsPeriodic;\r
+ Entry->UCBuffer = UCBuffer;\r
+ Entry->UCBufferMapping = Mapping;\r
+ Entry->DataLength = DataLength;\r
+ Entry->Toggle = DataToggle;\r
+ Entry->NextEntry = NULL;\r
+ OhciAddInterruptContextEntry (Ohc, Entry);\r
+ }\r
+ OhciSetEDField (Ed, ED_SKIP, 0);\r
+\r
+ if (OhciGetHcControl (Ohc, PERIODIC_ENABLE) == 0) {\r
+ Status = OhciSetHcControl (Ohc, PERIODIC_ENABLE, 1);\r
+ gBS->Stall (1000);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+FREE_OHCI_TDBUFF:\r
+ while (HeadTd) {\r
+ DataTd = HeadTd;\r
+ HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
+ UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
+ }\r
+\r
+//FREE_OHCI_EDBUFF:\r
+ if ((HeadEd != Ed) && HeadEd && Ed) {\r
+ while(HeadEd->NextED != (UINT32)(UINTN)Ed) {\r
+ HeadEd = (ED_DESCRIPTOR *)(UINTN)(HeadEd->NextED);\r
+ }\r
+ HeadEd->NextED = Ed->NextED;\r
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
+ }\r
+\r
+UNMAP_OHCI_XBUFF:\r
+ Ohc->PciIo->Unmap(Ohc->PciIo, Mapping);\r
+\r
+EXIT:\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress The combination of an endpoint number and an endpoint\r
+ direction of the target USB device. Each endpoint address\r
+ supports data transfer in one direction except the\r
+ control endpoint (whose default endpoint address is 0).\r
+ It is the caller's responsibility to make sure that\r
+ the EndPointAddress represents an interrupt endpoint.\r
+ @param IsSlowDevice Indicates whether the target device is slow device\r
+ or full-speed device.\r
+ @param MaxiumPacketLength Indicates the maximum packet size the target endpoint\r
+ is capable of sending or receiving.\r
+ @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between\r
+ the host and the target interrupt endpoint.\r
+ If FALSE, the specified asynchronous interrupt pipe\r
+ is canceled.\r
+ @param DataToggle A pointer to the data toggle value. On input, it is valid\r
+ when IsNewTransfer is TRUE, and it indicates the initial\r
+ data toggle value the asynchronous interrupt transfer\r
+ should adopt.\r
+ On output, it is valid when IsNewTransfer is FALSE,\r
+ and it is updated to indicate the data toggle value of\r
+ the subsequent asynchronous interrupt transfer.\r
+ @param PollingInterval Indicates the interval, in milliseconds, that the\r
+ asynchronous interrupt transfer is polled.\r
+ This parameter is required when IsNewTransfer is TRUE.\r
+ @param DataLength Indicates the length of data to be received at the\r
+ rate specified by PollingInterval from the target\r
+ asynchronous interrupt endpoint. This parameter\r
+ is only required when IsNewTransfer is TRUE.\r
+ @param CallBackFunction The Callback function.This function is called at the\r
+ rate specified by PollingInterval.This parameter is\r
+ only required when IsNewTransfer is TRUE.\r
+ @param Context The context that is passed to the CallBackFunction.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully\r
+ submitted or canceled.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciAsyncInterruptTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN BOOLEAN IsSlowDevice,\r
+ IN UINT8 MaxPacketLength,\r
+ IN BOOLEAN IsNewTransfer,\r
+ IN OUT UINT8 *DataToggle OPTIONAL,\r
+ IN UINTN PollingInterval OPTIONAL,\r
+ IN UINTN DataLength OPTIONAL,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,\r
+ IN VOID *Context OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ VOID *UCBuffer;\r
+\r
+ if (DataToggle == NULL || (EndPointAddress & 0x80) == 0 ||\r
+ (IsNewTransfer && (DataLength == 0 ||\r
+ (*DataToggle != 0 && *DataToggle != 1) || (PollingInterval < 1 || PollingInterval > 255)))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+ if ( IsNewTransfer ) {\r
+ UCBuffer = AllocatePool(DataLength);\r
+ if (UCBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else {\r
+ UCBuffer = NULL;\r
+ }\r
+ Status = OhciInterruptTransfer (\r
+ Ohc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ IsSlowDevice,\r
+ MaxPacketLength,\r
+ IsNewTransfer,\r
+ DataToggle,\r
+ PollingInterval,\r
+ UCBuffer,\r
+ DataLength,\r
+ CallBackFunction,\r
+ Context,\r
+ TRUE,\r
+ NULL,\r
+ NULL\r
+ );\r
+ if ( IsNewTransfer ) {\r
+ if (EFI_ERROR(Status)) {\r
+ gBS->FreePool (UCBuffer);\r
+ }\r
+ }\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Submits synchronous interrupt transfer to an interrupt endpoint\r
+ of a USB device.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress The combination of an endpoint number and an endpoint\r
+ direction of the target USB device. Each endpoint\r
+ address supports data transfer in one direction\r
+ except the control endpoint (whose default\r
+ endpoint address is 0). It is the caller's responsibility\r
+ to make sure that the EndPointAddress represents\r
+ an interrupt endpoint.\r
+ @param IsSlowDevice Indicates whether the target device is slow device\r
+ or full-speed device.\r
+ @param MaxPacketLength Indicates the maximum packet size the target endpoint\r
+ is capable of sending or receiving.\r
+ @param Data A pointer to the buffer of data that will be transmitted\r
+ to USB device or received from USB device.\r
+ @param DataLength On input, the size, in bytes, of the data buffer specified\r
+ by Data. On output, the number of bytes transferred.\r
+ @param DataToggle A pointer to the data toggle value. On input, it indicates\r
+ the initial data toggle value the synchronous interrupt\r
+ transfer should adopt;\r
+ on output, it is updated to indicate the data toggle value\r
+ of the subsequent synchronous interrupt transfer.\r
+ @param TimeOut Indicates the maximum time, in microseconds, which the\r
+ transfer is allowed to complete.\r
+ @param TransferResult A pointer to the detailed result information from\r
+ the synchronous interrupt transfer.\r
+\r
+ @retval EFI_UNSUPPORTED This interface not available.\r
+ @retval EFI_INVALID_PARAMETER Parameters not follow spec\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciSyncInterruptTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN BOOLEAN IsSlowDevice,\r
+ IN UINT8 MaxPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ EFI_STATUS Status;\r
+ ED_DESCRIPTOR *Ed;\r
+ TD_DESCRIPTOR *HeadTd;\r
+ OHCI_ED_RESULT EdResult;\r
+ VOID *UCBuffer;\r
+\r
+ if ((EndPointAddress & 0x80) == 0 || Data == NULL || DataLength == NULL || *DataLength == 0 ||\r
+ (IsSlowDevice && MaxPacketLength > 8) || (!IsSlowDevice && MaxPacketLength > 64) ||\r
+ DataToggle == NULL || (*DataToggle != 0 && *DataToggle != 1) || TransferResult == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+ UCBuffer = AllocatePool (*DataLength);\r
+ if (UCBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Status = OhciInterruptTransfer (\r
+ Ohc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ IsSlowDevice,\r
+ MaxPacketLength,\r
+ TRUE,\r
+ DataToggle,\r
+ 1,\r
+ UCBuffer,\r
+ *DataLength,\r
+ NULL,\r
+ NULL,\r
+ FALSE,\r
+ &Ed,\r
+ &HeadTd\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);\r
+ while (Status == EFI_NOT_READY && TimeOut > 0) {\r
+ gBS->Stall (1000);\r
+ TimeOut--;\r
+ Status = CheckIfDone (Ohc, INTERRUPT_LIST, Ed, HeadTd, &EdResult);\r
+ }\r
+\r
+ *TransferResult = ConvertErrorCode (EdResult.ErrorCode);\r
+ }\r
+ CopyMem(Data, UCBuffer, *DataLength);\r
+ Status = OhciInterruptTransfer (\r
+ Ohc,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ IsSlowDevice,\r
+ MaxPacketLength,\r
+ FALSE,\r
+ DataToggle,\r
+ 0,\r
+ NULL,\r
+ 0,\r
+ NULL,\r
+ NULL,\r
+ FALSE,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ return Status;\r
+}\r
+/**\r
+\r
+ Submits isochronous transfer to a target USB device.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress End point address\r
+ @param MaximumPacketLength Indicates the maximum packet size that the\r
+ default control transfer endpoint is capable of\r
+ sending or receiving.\r
+ @param Data A pointer to the buffer of data that will be transmitted\r
+ to USB device or received from USB device.\r
+ @param DataLength Indicates the size, in bytes, of the data buffer\r
+ specified by Data.\r
+ @param TransferResult A pointer to the detailed result information generated\r
+ by this control transfer.\r
+\r
+ @retval EFI_UNSUPPORTED This interface not available\r
+ @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciIsochronousTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaximumPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN DataLength,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ if (Data == NULL || DataLength == 0 || TransferResult == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+\r
+ Submits Async isochronous transfer to a target USB device.\r
+\r
+ @param his A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress End point address\r
+ @param MaximumPacketLength Indicates the maximum packet size that the\r
+ default control transfer endpoint is capable of\r
+ sending or receiving.\r
+ @param Data A pointer to the buffer of data that will be transmitted\r
+ to USB device or received from USB device.\r
+ @param IsochronousCallBack When the transfer complete, the call back function will be called\r
+ @param Context Pass to the call back function as parameter\r
+\r
+ @retval EFI_UNSUPPORTED This interface not available\r
+ @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciAsyncIsochronousTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaximumPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN DataLength,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
+ IN VOID *Context OPTIONAL\r
+ )\r
+{\r
+\r
+ if (Data == NULL || DataLength == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+\r
+ Retrieves the number of root hub ports.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param NumOfPorts A pointer to the number of the root hub ports.\r
+\r
+ @retval EFI_SUCCESS The port number was retrieved successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetRootHubNumOfPorts (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ OUT UINT8 *NumOfPorts\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+ if (NumOfPorts == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+\r
+ Retrieves the current status of a USB root hub port.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL.\r
+ @param PortNumber Specifies the root hub port from which the status\r
+ is to be retrieved. This value is zero-based. For example,\r
+ if a root hub has two ports, then the first port is numbered 0,\r
+ and the second port is numbered 1.\r
+ @param PortStatus A pointer to the current port status bits and\r
+ port status change bits.\r
+\r
+ @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber\r
+ was returned in PortStatus.\r
+ @retval EFI_INVALID_PARAMETER Port number not valid\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetRootHubPortStatus (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ UINT8 NumOfPorts;\r
+\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+ OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
+ if (PortNumber >= NumOfPorts) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ PortStatus->PortStatus = 0;\r
+ PortStatus->PortChangeStatus = 0;\r
+\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_POWER;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+\r
+ Sets a feature for the specified root hub port.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL.\r
+ @param PortNumber Specifies the root hub port whose feature\r
+ is requested to be set.\r
+ @param PortFeature Indicates the feature selector associated\r
+ with the feature set request.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was set for the\r
+ USB root hub port specified by PortNumber.\r
+ @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciSetRootHubPortFeature (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ EFI_STATUS Status;\r
+ UINT8 NumOfPorts;\r
+ UINTN RetryTimes;\r
+\r
+ OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
+ if (PortNumber >= NumOfPorts) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortPower:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 ||\r
+ OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
+ break;\r
+\r
+ case EfiUsbPortEnable:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+\r
+ case EfiUsbPortSuspend:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Clears a feature for the specified root hub port.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param PortNumber Specifies the root hub port whose feature\r
+ is requested to be cleared.\r
+ @param PortFeature Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the\r
+ USB root hub port specified by PortNumber.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+ @retval EFI_DEVICE_ERROR Some error happened when clearing feature\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciClearRootHubPortFeature (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ EFI_STATUS Status;\r
+ UINT8 NumOfPorts;\r
+ UINTN RetryTimes;\r
+\r
+\r
+ OhciGetRootHubNumOfPorts (This, &NumOfPorts);\r
+ if (PortNumber >= NumOfPorts) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortEnable:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortSuspend:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ break;\r
+\r
+ case EfiUsbPortPower:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortConnectChange:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortResetChange:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+\r
+ case EfiUsbPortEnableChange:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortSuspendChange:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortOverCurrentChange:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ gBS->Stall (1000);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding = {\r
+ OHCIDriverBindingSupported,\r
+ OHCIDriverBindingStart,\r
+ OHCIDriverBindingStop,\r
+ 0x10,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+\r
+/**\r
+ Entry point for EFI drivers.\r
+\r
+ @param ImageHandle EFI_HANDLE.\r
+ @param SystemTable EFI_SYSTEM_TABLE.\r
+\r
+ @retval EFI_SUCCESS Driver is successfully loaded.\r
+ @return Others Failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OHCIDriverEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ return EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gOhciDriverBinding,\r
+ ImageHandle,\r
+ &gOhciComponentName,\r
+ &gOhciComponentName2\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle. Any\r
+ ControllerHandle that has UsbHcProtocol installed will be supported.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @return EFI_SUCCESS This driver supports this device.\r
+ @return EFI_UNSUPPORTED This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OHCIDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ USB_CLASSC UsbClassCReg;\r
+ //\r
+ // Test whether there is PCI IO Protocol attached on the controller handle.\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ PCI_CLASSCODE_OFFSET,\r
+ sizeof (USB_CLASSC) / sizeof (UINT8),\r
+ &UsbClassCReg\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto ON_EXIT;\r
+ }\r
+ //\r
+ // Test whether the controller belongs to OHCI type\r
+ //\r
+ if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
+ (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
+ (UsbClassCReg.ProgInterface != PCI_IF_OHCI)\r
+ ) {\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+ON_EXIT:\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+\r
+ Allocate and initialize the empty OHCI device.\r
+\r
+ @param PciIo The PCIIO to use.\r
+ @param OriginalPciAttributes The original PCI attributes.\r
+\r
+ @return Allocated OHCI device If err, return NULL.\r
+\r
+**/\r
+\r
+USB_OHCI_HC_DEV *\r
+OhciAllocateDev (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT64 OriginalPciAttributes\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ EFI_STATUS Status;\r
+ VOID *Buf;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+ VOID *Map;\r
+ UINTN Pages;\r
+ UINTN Bytes;\r
+\r
+ Ohc = AllocateZeroPool (sizeof (USB_OHCI_HC_DEV));\r
+ if (Ohc == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE;\r
+ Ohc->PciIo = PciIo;\r
+\r
+ Ohc->UsbHc.Reset = OhciReset;\r
+ Ohc->UsbHc.GetState = OhciGetState;\r
+ Ohc->UsbHc.SetState = OhciSetState;\r
+ Ohc->UsbHc.ControlTransfer = OhciControlTransfer;\r
+ Ohc->UsbHc.BulkTransfer = OhciBulkTransfer;\r
+ Ohc->UsbHc.AsyncInterruptTransfer = OhciAsyncInterruptTransfer;\r
+ Ohc->UsbHc.SyncInterruptTransfer = OhciSyncInterruptTransfer;\r
+ Ohc->UsbHc.IsochronousTransfer = OhciIsochronousTransfer;\r
+ Ohc->UsbHc.AsyncIsochronousTransfer = OhciAsyncIsochronousTransfer;\r
+ Ohc->UsbHc.GetRootHubPortNumber = OhciGetRootHubNumOfPorts;\r
+ Ohc->UsbHc.GetRootHubPortStatus = OhciGetRootHubPortStatus;\r
+ Ohc->UsbHc.SetRootHubPortFeature = OhciSetRootHubPortFeature;\r
+ Ohc->UsbHc.ClearRootHubPortFeature = OhciClearRootHubPortFeature;\r
+ Ohc->UsbHc.MajorRevision = 0x1;\r
+ Ohc->UsbHc.MinorRevision = 0x1;\r
+\r
+ Ohc->OriginalPciAttributes = OriginalPciAttributes;\r
+\r
+ Ohc->HccaMemoryBlock = NULL;\r
+ Ohc->HccaMemoryMapping = NULL;\r
+ Ohc->HccaMemoryBuf = NULL;\r
+ Ohc->HccaMemoryPages = 0;\r
+ Ohc->InterruptContextList = NULL;\r
+ Ohc->ControllerNameTable = NULL;\r
+ Ohc->HouseKeeperTimer = NULL;\r
+\r
+ Ohc->MemPool = UsbHcInitMemPool(PciIo, TRUE, 0);\r
+ if(Ohc->MemPool == NULL) {\r
+ goto FREE_DEV_BUFFER;\r
+ }\r
+\r
+ Bytes = 4096;\r
+ Pages = EFI_SIZE_TO_PAGES (Bytes);\r
+\r
+ Status = PciIo->AllocateBuffer (\r
+ PciIo,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ Pages,\r
+ &Buf,\r
+ 0\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto FREE_MEM_POOL;\r
+ }\r
+\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ Buf,\r
+ &Bytes,\r
+ &PhyAddr,\r
+ &Map\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || (Bytes != 4096)) {\r
+ goto FREE_MEM_PAGE;\r
+ }\r
+\r
+ Ohc->HccaMemoryBlock = (HCCA_MEMORY_BLOCK *)(UINTN)PhyAddr;\r
+ Ohc->HccaMemoryMapping = Map;\r
+ Ohc->HccaMemoryBuf = (VOID *)(UINTN)Buf;\r
+ Ohc->HccaMemoryPages = Pages;\r
+\r
+ return Ohc;\r
+\r
+FREE_MEM_PAGE:\r
+ PciIo->FreeBuffer (PciIo, Pages, Buf);\r
+FREE_MEM_POOL:\r
+ UsbHcFreeMemPool (Ohc->MemPool);\r
+FREE_DEV_BUFFER:\r
+ FreePool(Ohc);\r
+\r
+ return NULL;\r
+}\r
+/**\r
+\r
+ Free the OHCI device and release its associated resources.\r
+\r
+ @param Ohc The OHCI device to release.\r
+\r
+**/\r
+VOID\r
+OhciFreeDev (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ OhciFreeFixedIntMemory (Ohc);\r
+\r
+ if (Ohc->HouseKeeperTimer != NULL) {\r
+ gBS->CloseEvent (Ohc->HouseKeeperTimer);\r
+ }\r
+\r
+ if (Ohc->ExitBootServiceEvent != NULL) {\r
+ gBS->CloseEvent (Ohc->ExitBootServiceEvent);\r
+ }\r
+\r
+ if (Ohc->MemPool != NULL) {\r
+ UsbHcFreeMemPool (Ohc->MemPool);\r
+ }\r
+\r
+ if (Ohc->HccaMemoryMapping != NULL ) {\r
+ Ohc->PciIo->FreeBuffer (Ohc->PciIo, Ohc->HccaMemoryPages, Ohc->HccaMemoryBuf);\r
+ }\r
+\r
+ if (Ohc->ControllerNameTable != NULL) {\r
+ FreeUnicodeStringTable (Ohc->ControllerNameTable);\r
+ }\r
+\r
+ FreePool (Ohc);\r
+}\r
+/**\r
+\r
+ Uninstall all Ohci Interface.\r
+\r
+ @param Controller Controller handle.\r
+ @param This Protocol instance pointer.\r
+\r
+**/\r
+VOID\r
+OhciCleanDevUp (\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_USB_HC_PROTOCOL *This\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+\r
+ //\r
+ // Retrieve private context structure\r
+ //\r
+ Ohc = USB_OHCI_HC_DEV_FROM_THIS (This);\r
+\r
+ //\r
+ // Uninstall the USB_HC and USB_HC2 protocol\r
+ //\r
+ gBS->UninstallProtocolInterface (\r
+ Controller,\r
+ &gEfiUsbHcProtocolGuid,\r
+ &Ohc->UsbHc\r
+ );\r
+\r
+ //\r
+ // Cancel the timer event\r
+ //\r
+ gBS->SetTimer (Ohc->HouseKeeperTimer, TimerCancel, 0);\r
+\r
+ //\r
+ // Stop the host controller\r
+ //\r
+ OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);\r
+ This->Reset (This, EFI_USB_HC_RESET_GLOBAL);\r
+ This->SetState (This, EfiUsbHcStateHalt);\r
+\r
+ //\r
+ // Free resources\r
+ //\r
+ OhciFreeDynamicIntMemory (Ohc);\r
+\r
+ //\r
+ // Restore original PCI attributes\r
+ //\r
+ Ohc->PciIo->Attributes (\r
+ Ohc->PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ Ohc->OriginalPciAttributes,\r
+ NULL\r
+ );\r
+\r
+ //\r
+ // Free the private context structure\r
+ //\r
+ OhciFreeDev (Ohc);\r
+}\r
+\r
+/**\r
+\r
+ One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
+\r
+ @param Event Pointer to this event\r
+ @param Context Event hanlder private data\r
+**/\r
+VOID\r
+EFIAPI\r
+OhcExitBootService (\r
+ EFI_EVENT Event,\r
+ VOID *Context\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ EFI_USB_HC_PROTOCOL *UsbHc;\r
+ Ohc = (USB_OHCI_HC_DEV *) Context;\r
+\r
+ UsbHc = &Ohc->UsbHc;\r
+ //\r
+ // Stop the Host Controller\r
+ //\r
+ //OhciStopHc (Ohc, OHC_GENERIC_TIMEOUT);\r
+ OhciSetHcControl (Ohc, PERIODIC_ENABLE | CONTROL_ENABLE | ISOCHRONOUS_ENABLE | BULK_ENABLE, 0);\r
+ UsbHc->Reset (UsbHc, EFI_USB_HC_RESET_GLOBAL);\r
+ UsbHc->SetState (UsbHc, EfiUsbHcStateHalt);\r
+\r
+ return;\r
+}\r
+\r
+\r
+/**\r
+ Starting the Usb OHCI Driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_UNSUPPORTED This driver does not support this device.\r
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OHCIDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ UINT64 Supports;\r
+ UINT64 OriginalPciAttributes;\r
+ BOOLEAN PciAttributesSaved;\r
+\r
+ //\r
+ // Open PCIIO, then enable the HC device and turn off emulation\r
+ //\r
+ Ohc = NULL;\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PciAttributesSaved = FALSE;\r
+ //\r
+ // Save original PCI attributes\r
+ //\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationGet,\r
+ 0,\r
+ &OriginalPciAttributes\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto CLOSE_PCIIO;\r
+ }\r
+ PciAttributesSaved = TRUE;\r
+\r
+ //\r
+ // Robustnesss improvement such as for UoL\r
+ // Default is not required.\r
+ //\r
+ //if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {\r
+ // OhciTurnOffUsbEmulation (PciIo);\r
+ //}\r
+\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationSupported,\r
+ 0,\r
+ &Supports\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Supports &= EFI_PCI_DEVICE_ENABLE;\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ Supports,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto CLOSE_PCIIO;\r
+ }\r
+ //\r
+ //Allocate memory for OHC private data structure\r
+ //\r
+ Ohc = OhciAllocateDev(PciIo, OriginalPciAttributes);\r
+ if (Ohc == NULL){\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto CLOSE_PCIIO;\r
+ }\r
+\r
+ //Status = OhciInitializeInterruptList ( Uhc );\r
+ //if (EFI_ERROR (Status)) {\r
+ // goto FREE_OHC;\r
+ //}\r
+\r
+ //\r
+ // Set 0.01 s timer\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ OhciHouseKeeper,\r
+ Ohc,\r
+ &Ohc->HouseKeeperTimer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto FREE_OHC;\r
+ }\r
+\r
+ Status = gBS->SetTimer (Ohc->HouseKeeperTimer, TimerPeriodic, 10 * 1000 * 10);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FREE_OHC;\r
+ }\r
+\r
+ //\r
+ //Install Host Controller Protocol\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &Controller,\r
+ &gEfiUsbHcProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ &Ohc->UsbHc\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "Install protocol error"));\r
+ goto FREE_OHC;\r
+ }\r
+ //\r
+ // Create event to stop the HC when exit boot service.\r
+ //\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ OhcExitBootService,\r
+ Ohc,\r
+ &gEfiEventExitBootServicesGuid,\r
+ &Ohc->ExitBootServiceEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "Create exit boot event error"));\r
+ goto UNINSTALL_USBHC;\r
+ }\r
+ AddUnicodeString2 (\r
+ "eng",\r
+ gOhciComponentName.SupportedLanguages,\r
+ &Ohc->ControllerNameTable,\r
+ L"Usb Universal Host Controller",\r
+ TRUE\r
+ );\r
+ AddUnicodeString2 (\r
+ "en",\r
+ gOhciComponentName2.SupportedLanguages,\r
+ &Ohc->ControllerNameTable,\r
+ L"Usb Universal Host Controller",\r
+ FALSE\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+\r
+UNINSTALL_USBHC:\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ Controller,\r
+ &gEfiUsbHcProtocolGuid,\r
+ &Ohc->UsbHc,\r
+ NULL\r
+ );\r
+\r
+FREE_OHC:\r
+ OhciFreeDev (Ohc);\r
+\r
+CLOSE_PCIIO:\r
+ if (PciAttributesSaved) {\r
+ //\r
+ // Restore original PCI attributes\r
+ //\r
+ PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationSet,\r
+ OriginalPciAttributes,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Stop this driver on ControllerHandle. Support stoping any child handles\r
+ created by this driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to stop driver on.\r
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
+ @param ChildHandleBuffer List of handles for the children we need to stop.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OHCIDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_USB_HC_PROTOCOL *UsbHc;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiUsbHcProtocolGuid,\r
+ (VOID **)&UsbHc,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ OhciCleanDevUp(Controller, UsbHc);\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
--- /dev/null
+/** @file\r
+Provides the definition of Usb Hc Protocol and OHCI controller\r
+private data structure.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#ifndef _OHCI_H\r
+#define _OHCI_H\r
+\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Protocol/UsbHostController.h>\r
+#include <Protocol/PciIo.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+\r
+typedef struct _USB_OHCI_HC_DEV USB_OHCI_HC_DEV;\r
+\r
+#include "UsbHcMem.h"\r
+#include "OhciReg.h"\r
+#include "OhciSched.h"\r
+#include "OhciUrb.h"\r
+#include "Descriptor.h"\r
+#include "ComponentName.h"\r
+#include "OhciDebug.h"\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL gOhciDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gOhciComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gOhciComponentName2;\r
+\r
+#define USB_OHCI_HC_DEV_SIGNATURE SIGNATURE_32('o','h','c','i')\r
+\r
+typedef struct _HCCA_MEMORY_BLOCK{\r
+ UINT32 HccaInterruptTable[32]; // 32-bit Physical Address to ED_DESCRIPTOR\r
+ UINT16 HccaFrameNumber;\r
+ UINT16 HccaPad;\r
+ UINT32 HccaDoneHead; // 32-bit Physical Address to TD_DESCRIPTOR\r
+ UINT8 Reserved[116];\r
+} HCCA_MEMORY_BLOCK;\r
+\r
+\r
+struct _USB_OHCI_HC_DEV {\r
+ UINTN Signature;\r
+ EFI_USB_HC_PROTOCOL UsbHc;\r
+ EFI_USB2_HC_PROTOCOL Usb2Hc;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT64 OriginalPciAttributes;\r
+\r
+ HCCA_MEMORY_BLOCK *HccaMemoryBlock;\r
+ VOID *HccaMemoryBuf;\r
+ VOID *HccaMemoryMapping;\r
+ UINTN HccaMemoryPages;\r
+\r
+ ED_DESCRIPTOR *IntervalList[6][32];\r
+ INTERRUPT_CONTEXT_ENTRY *InterruptContextList;\r
+ VOID *MemPool;\r
+\r
+ UINT32 ToggleFlag;\r
+\r
+ EFI_EVENT HouseKeeperTimer;\r
+ //\r
+ // ExitBootServicesEvent is used to stop the OHC DMA operation\r
+ // after exit boot service.\r
+ //\r
+ EFI_EVENT ExitBootServiceEvent;\r
+\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+};\r
+\r
+#define USB_OHCI_HC_DEV_FROM_THIS(a) CR(a, USB_OHCI_HC_DEV, UsbHc, USB_OHCI_HC_DEV_SIGNATURE)\r
+#define USB2_OHCI_HC_DEV_FROM_THIS(a) CR(a, USB_OHCI_HC_DEV, Usb2Hc, USB_OHCI_HC_DEV_SIGNATURE)\r
+\r
+//\r
+// Func List\r
+//\r
+\r
+/**\r
+ Provides software reset for the USB host controller.\r
+\r
+ @param This This EFI_USB_HC_PROTOCOL instance.\r
+ @param Attributes A bit mask of the reset operation to perform.\r
+\r
+ @retval EFI_SUCCESS The reset operation succeeded.\r
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.\r
+ @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is\r
+ not currently supported by the host controller.\r
+ @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciReset (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT16 Attributes\r
+ );\r
+/**\r
+ Retrieve the current state of the USB host controller.\r
+\r
+ @param This This EFI_USB_HC_PROTOCOL instance.\r
+ @param State Variable to return the current host controller\r
+ state.\r
+\r
+ @retval EFI_SUCCESS Host controller state was returned in State.\r
+ @retval EFI_INVALID_PARAMETER State is NULL.\r
+ @retval EFI_DEVICE_ERROR An error was encountered while attempting to\r
+ retrieve the host controller's current state.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetState (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ OUT EFI_USB_HC_STATE *State\r
+ );\r
+/**\r
+ Sets the USB host controller to a specific state.\r
+\r
+ @param This This EFI_USB_HC_PROTOCOL instance.\r
+ @param State The state of the host controller that will be set.\r
+\r
+ @retval EFI_SUCCESS The USB host controller was successfully placed\r
+ in the state specified by State.\r
+ @retval EFI_INVALID_PARAMETER State is invalid.\r
+ @retval EFI_DEVICE_ERROR Failed to set the state due to device error.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciSetState(\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN EFI_USB_HC_STATE State\r
+ );\r
+/**\r
+\r
+ Submits control transfer to a target USB device.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param IsSlowDevice Indicates whether the target device is slow device\r
+ or full-speed device.\r
+ @param MaxPaketLength Indicates the maximum packet size that the\r
+ default control transfer endpoint is capable of\r
+ sending or receiving.\r
+ @param Request A pointer to the USB device request that will be sent\r
+ to the USB device.\r
+ @param TransferDirection Specifies the data direction for the transfer.\r
+ There are three values available, DataIn, DataOut\r
+ and NoData.\r
+ @param Data A pointer to the buffer of data that will be transmitted\r
+ to USB device or received from USB device.\r
+ @param DataLength Indicates the size, in bytes, of the data buffer\r
+ specified by Data.\r
+ @param TimeOut Indicates the maximum time, in microseconds,\r
+ which the transfer is allowed to complete.\r
+ @param TransferResult A pointer to the detailed result information generated\r
+ by this control transfer.\r
+\r
+ @retval EFI_SUCCESS The control transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The control transfer could not be completed due to a lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT The control transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The control transfer failed due to host controller or device error.\r
+ Caller should check TranferResult for detailed error information.\r
+\r
+--*/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciControlTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN BOOLEAN IsSlowDevice,\r
+ IN UINT8 MaxPacketLength,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data OPTIONAL,\r
+ IN OUT UINTN *DataLength OPTIONAL,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+/**\r
+\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress The combination of an endpoint number and an\r
+ endpoint direction of the target USB device.\r
+ Each endpoint address supports data transfer in\r
+ one direction except the control endpoint\r
+ (whose default endpoint address is 0).\r
+ It is the caller's responsibility to make sure that\r
+ the EndPointAddress represents a bulk endpoint.\r
+ @param MaximumPacketLength Indicates the maximum packet size the target endpoint\r
+ is capable of sending or receiving.\r
+ @param Data A pointer to the buffer of data that will be transmitted\r
+ to USB device or received from USB device.\r
+ @param DataLength When input, indicates the size, in bytes, of the data buffer\r
+ specified by Data. When output, indicates the actually\r
+ transferred data size.\r
+ @param DataToggle A pointer to the data toggle value. On input, it indicates\r
+ the initial data toggle value the bulk transfer should adopt;\r
+ on output, it is updated to indicate the data toggle value\r
+ of the subsequent bulk transfer.\r
+ @param TimeOut Indicates the maximum time, in microseconds, which the\r
+ transfer is allowed to complete.\r
+ TransferResult A pointer to the detailed result information of the\r
+ bulk transfer.\r
+\r
+ @retval EFI_SUCCESS The bulk transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The bulk transfer could not be submitted due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT The bulk transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The bulk transfer failed due to host controller or device error.\r
+ Caller should check TranferResult for detailed error information.\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciBulkTransfer(\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaxPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+/**\r
+\r
+ Submits an interrupt transfer to an interrupt endpoint of a USB device.\r
+\r
+ @param Ohc Device private data\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress The combination of an endpoint number and an endpoint\r
+ direction of the target USB device. Each endpoint address\r
+ supports data transfer in one direction except the\r
+ control endpoint (whose default endpoint address is 0).\r
+ It is the caller's responsibility to make sure that\r
+ the EndPointAddress represents an interrupt endpoint.\r
+ @param IsSlowDevice Indicates whether the target device is slow device\r
+ or full-speed device.\r
+ @param MaxPacketLength Indicates the maximum packet size the target endpoint\r
+ is capable of sending or receiving.\r
+ @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between\r
+ the host and the target interrupt endpoint.\r
+ If FALSE, the specified asynchronous interrupt pipe\r
+ is canceled.\r
+ @param DataToggle A pointer to the data toggle value. On input, it is valid\r
+ when IsNewTransfer is TRUE, and it indicates the initial\r
+ data toggle value the asynchronous interrupt transfer\r
+ should adopt.\r
+ On output, it is valid when IsNewTransfer is FALSE,\r
+ and it is updated to indicate the data toggle value of\r
+ the subsequent asynchronous interrupt transfer.\r
+ @param PollingInterval Indicates the interval, in milliseconds, that the\r
+ asynchronous interrupt transfer is polled.\r
+ This parameter is required when IsNewTransfer is TRUE.\r
+ @param UCBuffer Uncacheable buffer\r
+ @param DataLength Indicates the length of data to be received at the\r
+ rate specified by PollingInterval from the target\r
+ asynchronous interrupt endpoint. This parameter\r
+ is only required when IsNewTransfer is TRUE.\r
+ @param CallBackFunction The Callback function.This function is called at the\r
+ rate specified by PollingInterval.This parameter is\r
+ only required when IsNewTransfer is TRUE.\r
+ @param Context The context that is passed to the CallBackFunction.\r
+ This is an optional parameter and may be NULL.\r
+ @param IsPeriodic Periodic interrupt or not\r
+ @param OutputED The correspoding ED carried out\r
+ @param OutputTD The correspoding TD carried out\r
+\r
+\r
+ @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully\r
+ submitted or canceled.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciInterruptTransfer (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN BOOLEAN IsSlowDevice,\r
+ IN UINT8 MaxPacketLength,\r
+ IN BOOLEAN IsNewTransfer,\r
+ IN OUT UINT8 *DataToggle OPTIONAL,\r
+ IN UINTN PollingInterval OPTIONAL,\r
+ IN VOID *UCBuffer OPTIONAL,\r
+ IN UINTN DataLength OPTIONAL,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,\r
+ IN VOID *Context OPTIONAL,\r
+ IN BOOLEAN IsPeriodic OPTIONAL,\r
+ OUT ED_DESCRIPTOR **OutputED OPTIONAL,\r
+ OUT TD_DESCRIPTOR **OutputTD OPTIONAL\r
+ );\r
+/**\r
+\r
+ Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress The combination of an endpoint number and an endpoint\r
+ direction of the target USB device. Each endpoint address\r
+ supports data transfer in one direction except the\r
+ control endpoint (whose default endpoint address is 0).\r
+ It is the caller's responsibility to make sure that\r
+ the EndPointAddress represents an interrupt endpoint.\r
+ @param IsSlowDevice Indicates whether the target device is slow device\r
+ or full-speed device.\r
+ @param MaxiumPacketLength Indicates the maximum packet size the target endpoint\r
+ is capable of sending or receiving.\r
+ @param IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between\r
+ the host and the target interrupt endpoint.\r
+ If FALSE, the specified asynchronous interrupt pipe\r
+ is canceled.\r
+ @param DataToggle A pointer to the data toggle value. On input, it is valid\r
+ when IsNewTransfer is TRUE, and it indicates the initial\r
+ data toggle value the asynchronous interrupt transfer\r
+ should adopt.\r
+ On output, it is valid when IsNewTransfer is FALSE,\r
+ and it is updated to indicate the data toggle value of\r
+ the subsequent asynchronous interrupt transfer.\r
+ @param PollingInterval Indicates the interval, in milliseconds, that the\r
+ asynchronous interrupt transfer is polled.\r
+ This parameter is required when IsNewTransfer is TRUE.\r
+ @param DataLength Indicates the length of data to be received at the\r
+ rate specified by PollingInterval from the target\r
+ asynchronous interrupt endpoint. This parameter\r
+ is only required when IsNewTransfer is TRUE.\r
+ @param CallBackFunction The Callback function.This function is called at the\r
+ rate specified by PollingInterval.This parameter is\r
+ only required when IsNewTransfer is TRUE.\r
+ @param Context The context that is passed to the CallBackFunction.\r
+ This is an optional parameter and may be NULL.\r
+\r
+ @retval EFI_SUCCESS The asynchronous interrupt transfer request has been successfully\r
+ submitted or canceled.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciAsyncInterruptTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN BOOLEAN IsSlowDevice,\r
+ IN UINT8 MaxPacketLength,\r
+ IN BOOLEAN IsNewTransfer,\r
+ IN OUT UINT8 *DataToggle OPTIONAL,\r
+ IN UINTN PollingInterval OPTIONAL,\r
+ IN UINTN DataLength OPTIONAL,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,\r
+ IN VOID *Context OPTIONAL\r
+ );\r
+/**\r
+\r
+ Submits synchronous interrupt transfer to an interrupt endpoint\r
+ of a USB device.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress The combination of an endpoint number and an endpoint\r
+ direction of the target USB device. Each endpoint\r
+ address supports data transfer in one direction\r
+ except the control endpoint (whose default\r
+ endpoint address is 0). It is the caller's responsibility\r
+ to make sure that the EndPointAddress represents\r
+ an interrupt endpoint.\r
+ @param IsSlowDevice Indicates whether the target device is slow device\r
+ or full-speed device.\r
+ @param MaxPacketLength Indicates the maximum packet size the target endpoint\r
+ is capable of sending or receiving.\r
+ @param Data A pointer to the buffer of data that will be transmitted\r
+ to USB device or received from USB device.\r
+ @param DataLength On input, the size, in bytes, of the data buffer specified\r
+ by Data. On output, the number of bytes transferred.\r
+ @param DataToggle A pointer to the data toggle value. On input, it indicates\r
+ the initial data toggle value the synchronous interrupt\r
+ transfer should adopt;\r
+ on output, it is updated to indicate the data toggle value\r
+ of the subsequent synchronous interrupt transfer.\r
+ @param TimeOut Indicates the maximum time, in microseconds, which the\r
+ transfer is allowed to complete.\r
+ @param TransferResult A pointer to the detailed result information from\r
+ the synchronous interrupt transfer.\r
+\r
+ @retval EFI_UNSUPPORTED This interface not available.\r
+ @retval EFI_INVALID_PARAMETER Parameters not follow spec\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciSyncInterruptTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN BOOLEAN IsSlowDevice,\r
+ IN UINT8 MaxPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+/**\r
+\r
+ Submits isochronous transfer to a target USB device.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress End point address\r
+ @param MaximumPacketLength Indicates the maximum packet size that the\r
+ default control transfer endpoint is capable of\r
+ sending or receiving.\r
+ @param Data A pointer to the buffer of data that will be transmitted\r
+ to USB device or received from USB device.\r
+ @param DataLength Indicates the size, in bytes, of the data buffer\r
+ specified by Data.\r
+ @param TransferResult A pointer to the detailed result information generated\r
+ by this control transfer.\r
+\r
+ @retval EFI_UNSUPPORTED This interface not available\r
+ @retval EFI_INVALID_PARAMETER Data is NULL or DataLength is 0 or TransferResult is NULL\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciIsochronousTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaximumPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN DataLength,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+/**\r
+\r
+ Submits Async isochronous transfer to a target USB device.\r
+\r
+ @param his A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param DeviceAddress Represents the address of the target device on the USB,\r
+ which is assigned during USB enumeration.\r
+ @param EndPointAddress End point address\r
+ @param MaximumPacketLength Indicates the maximum packet size that the\r
+ default control transfer endpoint is capable of\r
+ sending or receiving.\r
+ @param Data A pointer to the buffer of data that will be transmitted\r
+ to USB device or received from USB device.\r
+ @param IsochronousCallBack When the transfer complete, the call back function will be called\r
+ @param Context Pass to the call back function as parameter\r
+\r
+ @retval EFI_UNSUPPORTED This interface not available\r
+ @retval EFI_INVALID_PARAMETER Data is NULL or Datalength is 0\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciAsyncIsochronousTransfer (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaximumPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN DataLength,\r
+ IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
+ IN VOID *Context OPTIONAL\r
+ );\r
+\r
+/**\r
+\r
+ Retrieves the number of root hub ports.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param NumOfPorts A pointer to the number of the root hub ports.\r
+\r
+ @retval EFI_SUCCESS The port number was retrieved successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetRootHubNumOfPorts (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ OUT UINT8 *NumOfPorts\r
+ );\r
+/**\r
+\r
+ Retrieves the current status of a USB root hub port.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL.\r
+ @param PortNumber Specifies the root hub port from which the status\r
+ is to be retrieved. This value is zero-based. For example,\r
+ if a root hub has two ports, then the first port is numbered 0,\r
+ and the second port is numbered 1.\r
+ @param PortStatus A pointer to the current port status bits and\r
+ port status change bits.\r
+\r
+ @retval EFI_SUCCESS The status of the USB root hub port specified by PortNumber\r
+ was returned in PortStatus.\r
+ @retval EFI_INVALID_PARAMETER Port number not valid\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetRootHubPortStatus (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ );\r
+\r
+/**\r
+\r
+ Sets a feature for the specified root hub port.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL.\r
+ @param PortNumber Specifies the root hub port whose feature\r
+ is requested to be set.\r
+ @param PortFeature Indicates the feature selector associated\r
+ with the feature set request.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was set for the\r
+ USB root hub port specified by PortNumber.\r
+ @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciSetRootHubPortFeature (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ );\r
+/**\r
+\r
+ Clears a feature for the specified root hub port.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL instance.\r
+ @param PortNumber Specifies the root hub port whose feature\r
+ is requested to be cleared.\r
+ @param PortFeature Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared for the\r
+ USB root hub port specified by PortNumber.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+ @retval EFI_DEVICE_ERROR Some error happened when clearing feature\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciClearRootHubPortFeature (\r
+ IN EFI_USB_HC_PROTOCOL *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ );\r
+\r
+\r
+/**\r
+ Test to see if this driver supports ControllerHandle. Any\r
+ ControllerHandle that has UsbHcProtocol installed will be supported.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @return EFI_SUCCESS This driver supports this device.\r
+ @return EFI_UNSUPPORTED This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+\r
+OHCIDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Starting the Usb OHCI Driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to test.\r
+ @param RemainingDevicePath Not used.\r
+\r
+ @retval EFI_SUCCESS This driver supports this device.\r
+ @retval EFI_UNSUPPORTED This driver does not support this device.\r
+ @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.\r
+ EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OHCIDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Stop this driver on ControllerHandle. Support stoping any child handles\r
+ created by this driver.\r
+\r
+ @param This Protocol instance pointer.\r
+ @param Controller Handle of device to stop driver on.\r
+ @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
+ @param ChildHandleBuffer List of handles for the children we need to stop.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OHCIDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This file provides the information dump support for OHCI when in debug mode.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "Ohci.h"\r
+\r
+\r
+/*++\r
+\r
+ Print the data of ED and the TDs attached to the ED\r
+\r
+ @param Uhc Pointer to OHCI private data\r
+ @param Ed Pointer to a ED to free\r
+ @param Td Pointer to the Td head\r
+\r
+ @retval EFI_SUCCESS ED\r
+\r
+**/\r
+EFI_STATUS\r
+OhciDumpEdTdInfo (\r
+ IN USB_OHCI_HC_DEV *Uhc,\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *Td,\r
+ BOOLEAN Stage\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ if (Stage) {\r
+ DEBUG ((EFI_D_INFO, "\n Before executing command\n"));\r
+ }else{\r
+ DEBUG ((EFI_D_INFO, "\n after executing command\n"));\r
+ }\r
+ if (Ed != NULL) {\r
+ DEBUG ((EFI_D_INFO, "\nED Address:%p, ED buffer:\n", Ed));\r
+ DEBUG ((EFI_D_INFO, "DWord0 :TD Tail :TD Head :Next ED\n"));\r
+ for (Index = 0; Index < sizeof (ED_DESCRIPTOR)/4; Index ++) {\r
+ DEBUG ((EFI_D_INFO, "%8x ", *((UINT32*)(Ed) + Index) ));\r
+ }\r
+ DEBUG ((EFI_D_INFO, "\nNext TD buffer:%p\n", Td));\r
+ }\r
+ while (Td != NULL) {\r
+ if (Td->Word0.DirPID == TD_SETUP_PID) {\r
+ DEBUG ((EFI_D_INFO, "\nSetup PID "));\r
+ }else if (Td->Word0.DirPID == TD_OUT_PID) {\r
+ DEBUG ((EFI_D_INFO, "\nOut PID "));\r
+ }else if (Td->Word0.DirPID == TD_IN_PID) {\r
+ DEBUG ((EFI_D_INFO, "\nIn PID "));\r
+ }else if (Td->Word0.DirPID == TD_NODATA_PID) {\r
+ DEBUG ((EFI_D_INFO, "\nNo data PID "));\r
+ }\r
+ DEBUG ((EFI_D_INFO, "TD Address:%p, TD buffer:\n", Td));\r
+ DEBUG ((EFI_D_INFO, "DWord0 :CuBuffer:Next TD :Buff End:Next TD :DataBuff:ActLength\n"));\r
+ for (Index = 0; Index < sizeof (TD_DESCRIPTOR)/4; Index ++) {\r
+ DEBUG ((EFI_D_INFO, "%8x ", *((UINT32*)(Td) + Index) ));\r
+ }\r
+ DEBUG ((EFI_D_INFO, "\nCurrent TD Data buffer(size%d)\n", (UINT32)Td->ActualSendLength));\r
+ for (Index = 0; Index < Td->ActualSendLength; Index ++) {\r
+ DEBUG ((EFI_D_INFO, "%2x ", *(UINT8 *)(UINTN)(Td->DataBuffer + Index) ));\r
+ }\r
+ Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer);\r
+ }\r
+ DEBUG ((EFI_D_INFO, "\n TD buffer End\n"));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
--- /dev/null
+/** @file\r
+This file contains the definination for host controller\r
+debug support routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Print the data of ED and the TDs attached to the ED\r
+\r
+ @param Uhc Pointer to OHCI private data\r
+ @param Ed Pointer to a ED to free\r
+ @param Td Pointer to the Td head\r
+\r
+ @retval EFI_SUCCESS ED\r
+\r
+**/\r
+EFI_STATUS\r
+OhciDumpEdTdInfo (\r
+ IN USB_OHCI_HC_DEV *Uhc,\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *Td,\r
+ BOOLEAN Stage\r
+ );\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
--- /dev/null
+## @file\r
+# OHCI USB Host Controller UEFI Driver\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = OhciDxe\r
+ FILE_GUID = 4ACA697E-F883-446f-98F7-096416FFFFFF\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = OHCIDriverEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+# DRIVER_BINDING = gOhciDriverBinding\r
+# COMPONENT_NAME = gOhciComponentName\r
+# COMPONENT_NAME2 = gOhciComponentName2\r
+#\r
+[Sources]\r
+ Descriptor.h\r
+ Ohci.c\r
+ Ohci.h\r
+ OhciSched.c\r
+ OhciSched.h\r
+ OhciReg.c\r
+ OhciReg.h\r
+ OhciUrb.c\r
+ OhciUrb.h\r
+ OhciDebug.c\r
+ OhciDebug.h\r
+ ComponentName.c\r
+ ComponentName.h\r
+ UsbHcMem.c\r
+ UsbHcMem.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ MemoryAllocationLib\r
+ BaseLib\r
+ UefiLib\r
+ UefiBootServicesTableLib\r
+ UefiDriverEntryPoint\r
+ BaseMemoryLib\r
+ DebugLib\r
+\r
+[Guids]\r
+ gEfiEventExitBootServicesGuid ## SOMETIMES_CONSUMES ## Event\r
+\r
+[Protocols]\r
+ gEfiPciIoProtocolGuid ## TO_START\r
+ gEfiUsbHcProtocolGuid ## BY_START\r
+\r
+#\r
+# [Event]\r
+# ##\r
+# # Periodic timer event for checking the result of interrupt transfer execution.\r
+# #\r
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES\r
+#\r
--- /dev/null
+/** @file\r
+The OHCI register operation routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "Ohci.h"\r
+\r
+/**\r
+\r
+ Get OHCI operational reg value\r
+\r
+ @param PciIo PciIo protocol instance\r
+ @param Offset Offset of the operational reg\r
+\r
+ @retval Value of the register\r
+\r
+**/\r
+UINT32\r
+OhciGetOperationalReg (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+ UINT32 Value;\r
+ EFI_STATUS Status;\r
+\r
+ Status = PciIo->Mem.Read(PciIo, EfiPciIoWidthUint32, OHC_BAR_INDEX, Offset, 1, &Value);\r
+\r
+ return Value;\r
+}\r
+/**\r
+\r
+ Set OHCI operational reg value\r
+\r
+ @param PciIo PCI Bus Io protocol instance\r
+ @param Offset Offset of the operational reg\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set to the reg\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+OhciSetOperationalReg (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT32 Offset,\r
+ IN VOID *Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = PciIo->Mem.Write(PciIo, EfiPciIoWidthUint32, OHC_BAR_INDEX, Offset, 1, Value);\r
+\r
+ return Status;\r
+}\r
+/**\r
+\r
+ Get HcRevision reg value\r
+\r
+ @param PciIo PCI Bus Io protocol instance\r
+\r
+ @retval Value of the register\r
+\r
+**/\r
+\r
+\r
+UINT32\r
+OhciGetHcRevision (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo\r
+ )\r
+{\r
+ return OhciGetOperationalReg (PciIo, HC_REVISION);\r
+}\r
+/**\r
+\r
+ Set HcReset reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcReset (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcRESET Reset;\r
+\r
+ Status = EFI_SUCCESS;\r
+ *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR);\r
+\r
+ if (Field & RESET_SYSTEM_BUS) {\r
+ Reset.FSBIR = Value;\r
+ }\r
+\r
+ if (Field & RESET_HOST_CONTROLLER) {\r
+ Reset.FHR = Value;\r
+ }\r
+\r
+ if (Field & RESET_CLOCK_GENERATION) {\r
+ Reset.CGR = Value;\r
+ }\r
+\r
+ if (Field & RESET_SSE_GLOBAL) {\r
+ Reset.SSE = Value;\r
+ }\r
+\r
+ if (Field & RESET_PSPL) {\r
+ Reset.PSPL = Value;\r
+ }\r
+\r
+ if (Field & RESET_PCPL) {\r
+ Reset.PCPL = Value;\r
+ }\r
+\r
+ if (Field & RESET_SSEP1) {\r
+ Reset.SSEP1 = Value;\r
+ }\r
+\r
+ if (Field & RESET_SSEP2) {\r
+ Reset.SSEP2 = Value;\r
+ }\r
+\r
+ if (Field & RESET_SSEP3) {\r
+ Reset.SSEP3 = Value;\r
+ }\r
+\r
+ OhciSetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR, &Reset);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Get specific field of HcReset reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcReset (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Field\r
+ )\r
+{\r
+ HcRESET Reset;\r
+ UINT32 Value;\r
+\r
+\r
+ *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc->PciIo, USBHOST_OFFSET_UHCHR);\r
+ Value = 0;\r
+\r
+ switch (Field) {\r
+ case RESET_SYSTEM_BUS:\r
+ Value = Reset.FSBIR;\r
+ break;\r
+\r
+ case RESET_HOST_CONTROLLER:\r
+ Value = Reset.FHR;\r
+ break;\r
+\r
+ case RESET_CLOCK_GENERATION:\r
+ Value = Reset.CGR;\r
+ break;\r
+\r
+ case RESET_SSE_GLOBAL:\r
+ Value = Reset.SSE;\r
+ break;\r
+\r
+ case RESET_PSPL:\r
+ Value = Reset.PSPL;\r
+ break;\r
+\r
+ case RESET_PCPL:\r
+ Value = Reset.PCPL;\r
+ break;\r
+\r
+ case RESET_SSEP1:\r
+ Value = Reset.SSEP1;\r
+ break;\r
+\r
+ case RESET_SSEP2:\r
+ Value = Reset.SSEP2;\r
+ break;\r
+\r
+ case RESET_SSEP3:\r
+ Value = Reset.SSEP3;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+\r
+ return Value;\r
+}\r
+\r
+/**\r
+\r
+ Set HcControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcCONTROL Control;\r
+\r
+\r
+\r
+ *(UINT32 *) &Control = OhciGetOperationalReg (Ohc->PciIo, HC_CONTROL);\r
+\r
+ if (Field & CONTROL_BULK_RATIO) {\r
+ Control.ControlBulkRatio = Value;\r
+ }\r
+\r
+ if (Field & HC_FUNCTIONAL_STATE) {\r
+ Control.FunctionalState = Value;\r
+ }\r
+\r
+ if (Field & PERIODIC_ENABLE) {\r
+ Control.PeriodicEnable = Value;\r
+ }\r
+\r
+ if (Field & CONTROL_ENABLE) {\r
+ Control.ControlEnable = Value;\r
+ }\r
+\r
+ if (Field & ISOCHRONOUS_ENABLE) {\r
+ Control.IsochronousEnable = Value;\r
+ }\r
+\r
+ if (Field & BULK_ENABLE) {\r
+ Control.BulkEnable = Value;\r
+ }\r
+\r
+ if (Field & INTERRUPT_ROUTING) {\r
+ Control.InterruptRouting = Value;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_CONTROL, &Control);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get specific field of HcControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+\r
+UINT32\r
+OhciGetHcControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcCONTROL Control;\r
+\r
+ *(UINT32 *) &Control = OhciGetOperationalReg (Ohc->PciIo, HC_CONTROL);\r
+\r
+ switch (Field) {\r
+ case CONTROL_BULK_RATIO:\r
+ return Control.ControlBulkRatio;\r
+ break;\r
+ case PERIODIC_ENABLE:\r
+ return Control.PeriodicEnable;\r
+ break;\r
+ case CONTROL_ENABLE:\r
+ return Control.ControlEnable;\r
+ break;\r
+ case BULK_ENABLE:\r
+ return Control.BulkEnable;\r
+ break;\r
+ case ISOCHRONOUS_ENABLE:\r
+ return Control.IsochronousEnable;\r
+ break;\r
+ case HC_FUNCTIONAL_STATE:\r
+ return Control.FunctionalState;\r
+ break;\r
+ case INTERRUPT_ROUTING:\r
+ return Control.InterruptRouting;\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Set HcCommand reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcCommandStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcCOMMAND_STATUS CommandStatus;\r
+\r
+ ZeroMem (&CommandStatus, sizeof (HcCOMMAND_STATUS));\r
+\r
+ if(Field & HC_RESET){\r
+ CommandStatus.HcReset = Value;\r
+ }\r
+\r
+ if(Field & CONTROL_LIST_FILLED){\r
+ CommandStatus.ControlListFilled = Value;\r
+ }\r
+\r
+ if(Field & BULK_LIST_FILLED){\r
+ CommandStatus.BulkListFilled = Value;\r
+ }\r
+\r
+ if(Field & CHANGE_OWNER_REQUEST){\r
+ CommandStatus.ChangeOwnerRequest = Value;\r
+ }\r
+\r
+ if(Field & SCHEDULE_OVERRUN_COUNT){\r
+ CommandStatus.ScheduleOverrunCount = Value;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS, &CommandStatus);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Get specific field of HcCommand reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcCommandStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcCOMMAND_STATUS CommandStatus;\r
+\r
+ *(UINT32 *) &CommandStatus = OhciGetOperationalReg (Ohc->PciIo, HC_COMMAND_STATUS);\r
+\r
+ switch (Field){\r
+ case HC_RESET:\r
+ return CommandStatus.HcReset;\r
+ break;\r
+ case CONTROL_LIST_FILLED:\r
+ return CommandStatus.ControlListFilled;\r
+ break;\r
+ case BULK_LIST_FILLED:\r
+ return CommandStatus.BulkListFilled;\r
+ break;\r
+ case CHANGE_OWNER_REQUEST:\r
+ return CommandStatus.ChangeOwnerRequest;\r
+ break;\r
+ case SCHEDULE_OVERRUN_COUNT:\r
+ return CommandStatus.ScheduleOverrunCount;\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Clear specific fields of Interrupt Status\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to clear\r
+\r
+ @retval EFI_SUCCESS Fields cleared\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciClearInterruptStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcINTERRUPT_STATUS InterruptStatus;\r
+\r
+ ZeroMem (&InterruptStatus, sizeof (HcINTERRUPT_STATUS));\r
+\r
+ if(Field & SCHEDULE_OVERRUN){\r
+ InterruptStatus.SchedulingOverrun = 1;\r
+ }\r
+\r
+ if(Field & WRITEBACK_DONE_HEAD){\r
+ InterruptStatus.WriteBackDone = 1;\r
+ }\r
+ if(Field & START_OF_FRAME){\r
+ InterruptStatus.Sof = 1;\r
+ }\r
+\r
+ if(Field & RESUME_DETECT){\r
+ InterruptStatus.ResumeDetected = 1;\r
+ }\r
+\r
+ if(Field & UNRECOVERABLE_ERROR){\r
+ InterruptStatus.UnrecoverableError = 1;\r
+ }\r
+\r
+ if(Field & FRAME_NUMBER_OVERFLOW){\r
+ InterruptStatus.FrameNumOverflow = 1;\r
+ }\r
+\r
+ if(Field & ROOTHUB_STATUS_CHANGE){\r
+ InterruptStatus.RHStatusChange = 1;\r
+ }\r
+\r
+ if(Field & OWNERSHIP_CHANGE){\r
+ InterruptStatus.OwnerChange = 1;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_STATUS, &InterruptStatus);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Get fields of HcInterrupt reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcInterruptStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcINTERRUPT_STATUS InterruptStatus;\r
+\r
+ *(UINT32 *) &InterruptStatus = OhciGetOperationalReg (Ohc->PciIo, HC_INTERRUPT_STATUS);\r
+\r
+ switch (Field){\r
+ case SCHEDULE_OVERRUN:\r
+ return InterruptStatus.SchedulingOverrun;\r
+ break;\r
+\r
+ case WRITEBACK_DONE_HEAD:\r
+ return InterruptStatus.WriteBackDone;\r
+ break;\r
+\r
+ case START_OF_FRAME:\r
+ return InterruptStatus.Sof;\r
+ break;\r
+\r
+ case RESUME_DETECT:\r
+ return InterruptStatus.ResumeDetected;\r
+ break;\r
+\r
+ case UNRECOVERABLE_ERROR:\r
+ return InterruptStatus.UnrecoverableError;\r
+ break;\r
+\r
+ case FRAME_NUMBER_OVERFLOW:\r
+ return InterruptStatus.FrameNumOverflow;\r
+ break;\r
+\r
+ case ROOTHUB_STATUS_CHANGE:\r
+ return InterruptStatus.RHStatusChange;\r
+ break;\r
+\r
+ case OWNERSHIP_CHANGE:\r
+ return InterruptStatus.OwnerChange;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Set Interrupt Control reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param StatEnable Enable or Disable\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetInterruptControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN BOOLEAN StatEnable,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcINTERRUPT_CONTROL InterruptState;\r
+\r
+\r
+ ZeroMem (&InterruptState, sizeof (HcINTERRUPT_CONTROL));\r
+\r
+ if(Field & SCHEDULE_OVERRUN) {\r
+ InterruptState.SchedulingOverrunInt = Value;\r
+ }\r
+\r
+ if(Field & WRITEBACK_DONE_HEAD) {\r
+ InterruptState.WriteBackDoneInt = Value;\r
+ }\r
+ if(Field & START_OF_FRAME) {\r
+ InterruptState.SofInt = Value;\r
+ }\r
+\r
+ if(Field & RESUME_DETECT) {\r
+ InterruptState.ResumeDetectedInt = Value;\r
+ }\r
+\r
+ if(Field & UNRECOVERABLE_ERROR) {\r
+ InterruptState.UnrecoverableErrorInt = Value;\r
+ }\r
+\r
+ if(Field & FRAME_NUMBER_OVERFLOW) {\r
+ InterruptState.FrameNumOverflowInt = Value;\r
+ }\r
+\r
+ if(Field & ROOTHUB_STATUS_CHANGE) {\r
+ InterruptState.RHStatusChangeInt = Value;\r
+ }\r
+\r
+ if(Field & OWNERSHIP_CHANGE) {\r
+ InterruptState.OwnerChangedInt = Value;\r
+ }\r
+\r
+ if(Field & MASTER_INTERRUPT) {\r
+ InterruptState.MasterInterruptEnable = Value;\r
+ }\r
+\r
+ if (StatEnable) {\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_ENABLE, &InterruptState);\r
+ } else {\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_INTERRUPT_DISABLE, &InterruptState);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Get field of HcInterruptControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcInterruptControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcINTERRUPT_CONTROL InterruptState;\r
+\r
+ *(UINT32 *) &InterruptState = OhciGetOperationalReg (Ohc->PciIo, HC_INTERRUPT_ENABLE);\r
+\r
+ switch (Field){\r
+ case SCHEDULE_OVERRUN:\r
+ return InterruptState.SchedulingOverrunInt;\r
+ break;\r
+\r
+ case WRITEBACK_DONE_HEAD:\r
+ return InterruptState.WriteBackDoneInt;\r
+ break;\r
+\r
+ case START_OF_FRAME:\r
+ return InterruptState.SofInt;\r
+ break;\r
+\r
+ case RESUME_DETECT:\r
+ return InterruptState.ResumeDetectedInt;\r
+ break;\r
+\r
+ case UNRECOVERABLE_ERROR:\r
+ return InterruptState.UnrecoverableErrorInt;\r
+ break;\r
+\r
+ case FRAME_NUMBER_OVERFLOW:\r
+ return InterruptState.FrameNumOverflowInt;\r
+ break;\r
+\r
+ case ROOTHUB_STATUS_CHANGE:\r
+ return InterruptState.RHStatusChangeInt;\r
+ break;\r
+\r
+ case OWNERSHIP_CHANGE:\r
+ return InterruptState.OwnerChangedInt;\r
+ break;\r
+\r
+ case MASTER_INTERRUPT:\r
+ return InterruptState.MasterInterruptEnable;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Set memory pointer of specific type\r
+\r
+ @param Ohc UHC private data\r
+ @param PointerType Type of the pointer to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Memory pointer set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetMemoryPointer(\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 PointerType,\r
+ IN VOID *Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Verify;\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, PointerType, &Value);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Verify = OhciGetOperationalReg (Ohc->PciIo, PointerType);\r
+\r
+ while (Verify != (UINT32)(UINTN) Value) {\r
+ gBS->Stall(1000);\r
+ Verify = OhciGetOperationalReg (Ohc->PciIo, PointerType);\r
+ };\r
+\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Get memory pointer of specific type\r
+\r
+ @param Ohc UHC private data\r
+ @param PointerType Type of pointer\r
+\r
+ @retval Memory pointer of the specific type\r
+\r
+**/\r
+\r
+VOID *\r
+OhciGetMemoryPointer (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 PointerType\r
+ )\r
+{\r
+\r
+ return (VOID *)(UINTN) OhciGetOperationalReg (Ohc->PciIo, PointerType);\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set Frame Interval value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameInterval (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcFRM_INTERVAL FrameInterval;\r
+\r
+\r
+ *(UINT32 *) &FrameInterval = OhciGetOperationalReg(Ohc->PciIo, HC_FRM_INTERVAL);\r
+\r
+ if (Field & FRAME_INTERVAL) {\r
+ FrameInterval.FrmIntervalToggle = !FrameInterval.FrmIntervalToggle;\r
+ FrameInterval.FrameInterval = Value;\r
+ }\r
+\r
+ if (Field & FS_LARGEST_DATA_PACKET) {\r
+ FrameInterval.FSMaxDataPacket = Value;\r
+ }\r
+\r
+ if (Field & FRMINT_TOGGLE) {\r
+ FrameInterval.FrmIntervalToggle = Value;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (\r
+ Ohc->PciIo,\r
+ HC_FRM_INTERVAL,\r
+ &FrameInterval\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get field of frame interval reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetFrameInterval (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcFRM_INTERVAL FrameInterval;\r
+\r
+ *(UINT32 *) &FrameInterval = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_INTERVAL);\r
+\r
+ switch (Field){\r
+ case FRAME_INTERVAL:\r
+ return FrameInterval.FrameInterval;\r
+ break;\r
+\r
+ case FS_LARGEST_DATA_PACKET:\r
+ return FrameInterval.FSMaxDataPacket;\r
+ break;\r
+\r
+ case FRMINT_TOGGLE:\r
+ return FrameInterval.FrmIntervalToggle;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Set Frame Remaining reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameRemaining (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcFRAME_REMAINING FrameRemaining;\r
+\r
+\r
+ *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING);\r
+\r
+ FrameRemaining.FrameRemaining = Value;\r
+ FrameRemaining.FrameRemainingToggle = !FrameRemaining.FrameRemainingToggle;\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING, &FrameRemaining);\r
+\r
+ return Status;\r
+}\r
+/**\r
+\r
+ Get value of frame remaining reg\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of frame remaining reg\r
+\r
+**/\r
+UINT32\r
+OhciGetFrameRemaining (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+\r
+{\r
+ HcFRAME_REMAINING FrameRemaining;\r
+\r
+\r
+ *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc->PciIo, HC_FRM_REMAINING);\r
+\r
+ switch (Field){\r
+ case FRAME_REMAINING:\r
+ return FrameRemaining.FrameRemaining;\r
+ break;\r
+\r
+ case FRAME_REMAIN_TOGGLE:\r
+ return FrameRemaining.FrameRemainingToggle;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Set frame number reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameNumber(\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_FRM_NUMBER, &Value);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Get frame number reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @retval Value of frame number reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetFrameNumber (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ return OhciGetOperationalReg(Ohc->PciIo, HC_FRM_NUMBER);\r
+}\r
+\r
+/**\r
+\r
+ Set period start reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetPeriodicStart (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_PERIODIC_START, &Value);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get periodic start reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @param Value of periodic start reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetPeriodicStart (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ return OhciGetOperationalReg(Ohc->PciIo, HC_PERIODIC_START);\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set Ls Threshold reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetLsThreshold (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_LS_THREASHOLD, &Value);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get Ls Threshold reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @retval Value of Ls Threshold reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetLsThreshold (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ return OhciGetOperationalReg(Ohc->PciIo, HC_LS_THREASHOLD);\r
+}\r
+\r
+/**\r
+\r
+ Set Root Hub Descriptor reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetRootHubDescriptor (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcRH_DESC_A DescriptorA;\r
+ HcRH_DESC_B DescriptorB;\r
+\r
+\r
+ if (Field & (RH_DEV_REMOVABLE | RH_PORT_PWR_CTRL_MASK)) {\r
+ *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_B);\r
+\r
+ if(Field & RH_DEV_REMOVABLE) {\r
+ DescriptorB.DeviceRemovable = Value;\r
+ }\r
+ if(Field & RH_PORT_PWR_CTRL_MASK) {\r
+ DescriptorB.PortPowerControlMask = Value;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_DESC_B, &DescriptorB);\r
+\r
+ return Status;\r
+ }\r
+\r
+ *(UINT32 *)&DescriptorA = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_A);\r
+\r
+ if(Field & RH_NUM_DS_PORTS) {\r
+ DescriptorA.NumDownStrmPorts = Value;\r
+ }\r
+ if(Field & RH_NO_PSWITCH) {\r
+ DescriptorA.NoPowerSwitch = Value;\r
+ }\r
+ if(Field & RH_PSWITCH_MODE) {\r
+ DescriptorA.PowerSwitchMode = Value;\r
+ }\r
+ if(Field & RH_DEVICE_TYPE) {\r
+ DescriptorA.DeviceType = Value;\r
+ }\r
+ if(Field & RH_OC_PROT_MODE) {\r
+ DescriptorA.OverCurrentProtMode = Value;\r
+ }\r
+ if(Field & RH_NOC_PROT) {\r
+ DescriptorA.NoOverCurrentProtMode = Value;\r
+ }\r
+ if(Field & RH_NO_POTPGT) {\r
+ DescriptorA.PowerOnToPowerGoodTime = Value;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_DESC_A, &DescriptorA);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get Root Hub Descriptor reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetRootHubDescriptor (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcRH_DESC_A DescriptorA;\r
+ HcRH_DESC_B DescriptorB;\r
+\r
+\r
+ *(UINT32 *) &DescriptorA = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_A);\r
+ *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc->PciIo, HC_RH_DESC_B);\r
+\r
+ switch (Field){\r
+ case RH_DEV_REMOVABLE:\r
+ return DescriptorB.DeviceRemovable;\r
+ break;\r
+\r
+ case RH_PORT_PWR_CTRL_MASK:\r
+ return DescriptorB.PortPowerControlMask;\r
+ break;\r
+\r
+ case RH_NUM_DS_PORTS:\r
+ return DescriptorA.NumDownStrmPorts;\r
+ break;\r
+\r
+ case RH_NO_PSWITCH:\r
+ return DescriptorA.NoPowerSwitch;\r
+ break;\r
+\r
+ case RH_PSWITCH_MODE:\r
+ return DescriptorA.PowerSwitchMode;\r
+ break;\r
+\r
+ case RH_DEVICE_TYPE:\r
+ return DescriptorA.DeviceType;\r
+ break;\r
+\r
+ case RH_OC_PROT_MODE:\r
+ return DescriptorA.OverCurrentProtMode;\r
+ break;\r
+\r
+ case RH_NOC_PROT:\r
+ return DescriptorA.NoOverCurrentProtMode;\r
+ break;\r
+\r
+ case RH_NO_POTPGT:\r
+ return DescriptorA.PowerOnToPowerGoodTime;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set Root Hub Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetRootHubStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcRH_STATUS RootHubStatus;\r
+\r
+\r
+ ZeroMem (&RootHubStatus, sizeof(HcRH_STATUS));\r
+\r
+ if(Field & RH_LOCAL_PSTAT){\r
+ RootHubStatus.LocalPowerStat = 1;\r
+ }\r
+ if(Field & RH_OC_ID){\r
+ RootHubStatus.OverCurrentIndicator = 1;\r
+ }\r
+ if(Field & RH_REMOTE_WK_ENABLE){\r
+ RootHubStatus.DevRemoteWakeupEnable = 1;\r
+ }\r
+ if(Field & RH_LOCAL_PSTAT_CHANGE){\r
+ RootHubStatus.LocalPowerStatChange = 1;\r
+ }\r
+ if(Field & RH_OC_ID_CHANGE){\r
+ RootHubStatus.OverCurrentIndicatorChange = 1;\r
+ }\r
+ if(Field & RH_CLR_RMT_WK_ENABLE){\r
+ RootHubStatus.ClearRemoteWakeupEnable = 1;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_STATUS, &RootHubStatus);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get Root Hub Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetRootHubStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcRH_STATUS RootHubStatus;\r
+\r
+\r
+ *(UINT32 *) &RootHubStatus = OhciGetOperationalReg (Ohc->PciIo, HC_RH_STATUS);\r
+\r
+ switch (Field) {\r
+ case RH_LOCAL_PSTAT:\r
+ return RootHubStatus.LocalPowerStat;\r
+ break;\r
+ case RH_OC_ID:\r
+ return RootHubStatus.OverCurrentIndicator;\r
+ break;\r
+ case RH_REMOTE_WK_ENABLE:\r
+ return RootHubStatus.DevRemoteWakeupEnable;\r
+ break;\r
+ case RH_LOCAL_PSTAT_CHANGE:\r
+ return RootHubStatus.LocalPowerStatChange;\r
+ break;\r
+ case RH_OC_ID_CHANGE:\r
+ return RootHubStatus.OverCurrentIndicatorChange;\r
+ break;\r
+ case RH_CLR_RMT_WK_ENABLE:\r
+ return RootHubStatus.ClearRemoteWakeupEnable;\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set Root Hub Port Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Index Index of the port\r
+ @param Field Field to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetRootHubPortStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Index,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcRHPORT_STATUS PortStatus;\r
+\r
+\r
+ ZeroMem (&PortStatus, sizeof(HcRHPORT_STATUS));\r
+\r
+ if (Field & RH_CLEAR_PORT_ENABLE) {\r
+ PortStatus.CurrentConnectStat = 1;\r
+ }\r
+ if (Field & RH_SET_PORT_ENABLE) {\r
+ PortStatus.EnableStat = 1;\r
+ }\r
+ if (Field & RH_SET_PORT_SUSPEND) {\r
+ PortStatus.SuspendStat = 1;\r
+ }\r
+ if (Field & RH_CLEAR_SUSPEND_STATUS) {\r
+ PortStatus.OCIndicator = 1;\r
+ }\r
+ if (Field & RH_SET_PORT_RESET) {\r
+ PortStatus.ResetStat = 1;\r
+ }\r
+ if (Field & RH_SET_PORT_POWER) {\r
+ PortStatus.PowerStat = 1;\r
+ }\r
+ if (Field & RH_CLEAR_PORT_POWER) {\r
+ PortStatus.LsDeviceAttached = 1;\r
+ }\r
+ if (Field & RH_CONNECT_STATUS_CHANGE) {\r
+ PortStatus.ConnectStatChange = 1;\r
+ }\r
+ if (Field & RH_PORT_ENABLE_STAT_CHANGE) {\r
+ PortStatus.EnableStatChange = 1;\r
+ }\r
+ if (Field & RH_PORT_SUSPEND_STAT_CHANGE) {\r
+ PortStatus.SuspendStatChange = 1;\r
+ }\r
+ if (Field & RH_OC_INDICATOR_CHANGE) {\r
+ PortStatus.OCIndicatorChange = 1;\r
+ }\r
+ if (Field & RH_PORT_RESET_STAT_CHANGE ) {\r
+ PortStatus.ResetStatChange = 1;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc->PciIo, HC_RH_PORT_STATUS + (Index * 4), &PortStatus);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get Root Hub Port Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Index Index of the port\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field and index\r
+\r
+**/\r
+\r
+UINT32\r
+OhciReadRootHubPortStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Index,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcRHPORT_STATUS PortStatus;\r
+\r
+ *(UINT32 *) &PortStatus = OhciGetOperationalReg (\r
+ Ohc->PciIo,\r
+ HC_RH_PORT_STATUS + (Index * 4)\r
+ );\r
+\r
+ switch (Field){\r
+ case RH_CURR_CONNECT_STAT:\r
+ return PortStatus.CurrentConnectStat;\r
+ break;\r
+ case RH_PORT_ENABLE_STAT:\r
+ return PortStatus.EnableStat;\r
+ break;\r
+ case RH_PORT_SUSPEND_STAT:\r
+ return PortStatus.SuspendStat;\r
+ break;\r
+ case RH_PORT_OC_INDICATOR:\r
+ return PortStatus.OCIndicator;\r
+ break;\r
+ case RH_PORT_RESET_STAT:\r
+ return PortStatus.ResetStat;\r
+ break;\r
+ case RH_PORT_POWER_STAT:\r
+ return PortStatus.PowerStat;\r
+ break;\r
+ case RH_LSDEVICE_ATTACHED:\r
+ return PortStatus.LsDeviceAttached;\r
+ break;\r
+ case RH_CONNECT_STATUS_CHANGE:\r
+ return PortStatus.ConnectStatChange;\r
+ break;\r
+ case RH_PORT_ENABLE_STAT_CHANGE:\r
+ return PortStatus.EnableStatChange;\r
+ break;\r
+ case RH_PORT_SUSPEND_STAT_CHANGE:\r
+ return PortStatus.SuspendStatChange;\r
+ break;\r
+ case RH_OC_INDICATOR_CHANGE:\r
+ return PortStatus.OCIndicatorChange;\r
+ break;\r
+ case RH_PORT_RESET_STAT_CHANGE:\r
+ return PortStatus.ResetStatChange;\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
--- /dev/null
+/** @file\r
+This file contains the definination for host controller\r
+register operation routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#ifndef _OHCI_REG_H\r
+#define _OHCI_REG_H\r
+\r
+#define HC_STATE_RESET 0x0\r
+#define HC_STATE_RESUME 0x1\r
+#define HC_STATE_OPERATIONAL 0x2\r
+#define HC_STATE_SUSPEND 0x3\r
+\r
+#define PERIODIC_ENABLE 0x01\r
+#define ISOCHRONOUS_ENABLE 0x02\r
+#define CONTROL_ENABLE 0x04\r
+#define BULK_ENABLE 0x08\r
+#define CONTROL_BULK_RATIO 0x10\r
+\r
+#define HC_FUNCTIONAL_STATE 0x20\r
+#define INTERRUPT_ROUTING 0x40\r
+\r
+#define HC_RESET 0x01\r
+#define CONTROL_LIST_FILLED 0x02\r
+#define BULK_LIST_FILLED 0x04\r
+#define CHANGE_OWNER_REQUEST 0x08\r
+\r
+#define SCHEDULE_OVERRUN_COUNT 0x10\r
+\r
+#define SCHEDULE_OVERRUN 0x00001\r
+#define WRITEBACK_DONE_HEAD 0x00002\r
+#define START_OF_FRAME 0x00004\r
+#define RESUME_DETECT 0x00008\r
+#define UNRECOVERABLE_ERROR 0x00010\r
+#define FRAME_NUMBER_OVERFLOW 0x00020\r
+#define ROOTHUB_STATUS_CHANGE 0x00040\r
+#define OWNERSHIP_CHANGE 0x00080\r
+\r
+#define MASTER_INTERRUPT 0x00400\r
+\r
+#define CONTROL_HEAD 0x001\r
+#define BULK_HEAD 0x002\r
+#define DONE_HEAD 0x004\r
+\r
+#define Hc_HCCA 0x001\r
+#define Hc_PERIODIC_CURRENT 0x002\r
+#define Hc_CONTOL_HEAD 0x004\r
+#define Hc_CONTROL_CURRENT_PTR 0x008\r
+#define Hc_BULK_HEAD 0x010\r
+#define Hc_BULK_CURRENT_PTR 0x020\r
+#define Hc_DONE_HEAD 0x040\r
+\r
+#define FRAME_INTERVAL 0x008\r
+#define FS_LARGEST_DATA_PACKET 0x010\r
+#define FRMINT_TOGGLE 0x020\r
+#define FRAME_REMAINING 0x040\r
+#define FRAME_REMAIN_TOGGLE 0x080\r
+\r
+#define RH_DESC_A 0x00001\r
+#define RH_DESC_B 0x00002\r
+#define RH_NUM_DS_PORTS 0x00004\r
+#define RH_NO_PSWITCH 0x00008\r
+#define RH_PSWITCH_MODE 0x00010\r
+#define RH_DEVICE_TYPE 0x00020\r
+#define RH_OC_PROT_MODE 0x00040\r
+#define RH_NOC_PROT 0x00080\r
+#define RH_POTPGT 0x00100\r
+#define RH_NO_POTPGT 0x00200\r
+#define RH_DEV_REMOVABLE 0x00400\r
+#define RH_PORT_PWR_CTRL_MASK 0x00800\r
+\r
+#define RH_LOCAL_PSTAT 0x00001\r
+#define RH_OC_ID 0x00002\r
+#define RH_REMOTE_WK_ENABLE 0x00004\r
+#define RH_LOCAL_PSTAT_CHANGE 0x00008\r
+#define RH_OC_ID_CHANGE 0x00010\r
+#define RH_CLR_RMT_WK_ENABLE 0x00020\r
+\r
+#define RH_CLEAR_PORT_ENABLE 0x0001\r
+#define RH_SET_PORT_ENABLE 0x0002\r
+#define RH_SET_PORT_SUSPEND 0x0004\r
+#define RH_CLEAR_SUSPEND_STATUS 0x0008\r
+#define RH_SET_PORT_RESET 0x0010\r
+#define RH_SET_PORT_POWER 0x0020\r
+#define RH_CLEAR_PORT_POWER 0x0040\r
+#define RH_CONNECT_STATUS_CHANGE 0x10000\r
+#define RH_PORT_ENABLE_STAT_CHANGE 0x20000\r
+#define RH_PORT_SUSPEND_STAT_CHANGE 0x40000\r
+#define RH_OC_INDICATOR_CHANGE 0x80000\r
+#define RH_PORT_RESET_STAT_CHANGE 0x100000\r
+\r
+#define RH_CURR_CONNECT_STAT 0x0001\r
+#define RH_PORT_ENABLE_STAT 0x0002\r
+#define RH_PORT_SUSPEND_STAT 0x0004\r
+#define RH_PORT_OC_INDICATOR 0x0008\r
+#define RH_PORT_RESET_STAT 0x0010\r
+#define RH_PORT_POWER_STAT 0x0020\r
+#define RH_LSDEVICE_ATTACHED 0x0040\r
+\r
+#define RESET_SYSTEM_BUS (1 << 0)\r
+#define RESET_HOST_CONTROLLER (1 << 1)\r
+#define RESET_CLOCK_GENERATION (1 << 2)\r
+#define RESET_SSE_GLOBAL (1 << 5)\r
+#define RESET_PSPL (1 << 6)\r
+#define RESET_PCPL (1 << 7)\r
+#define RESET_SSEP1 (1 << 9)\r
+#define RESET_SSEP2 (1 << 10)\r
+#define RESET_SSEP3 (1 << 11)\r
+\r
+#define ONE_SECOND 1000000\r
+#define ONE_MILLI_SEC 1000\r
+#define MAX_BYTES_PER_TD 0x1000\r
+#define MAX_RETRY_TIMES 100\r
+#define PORT_NUMBER_ON_MAINSTONE2 1\r
+\r
+\r
+//\r
+// Operational Register Offsets\r
+//\r
+\r
+//\r
+// Command & Status Registers Offsets\r
+//\r
+#define HC_REVISION 0x00\r
+#define HC_CONTROL 0x04\r
+#define HC_COMMAND_STATUS 0x08\r
+#define HC_INTERRUPT_STATUS 0x0C\r
+#define HC_INTERRUPT_ENABLE 0x10\r
+#define HC_INTERRUPT_DISABLE 0x14\r
+\r
+//\r
+// Memory Pointer Offsets\r
+//\r
+#define HC_HCCA 0x18\r
+#define HC_PERIODIC_CURRENT 0x1C\r
+#define HC_CONTROL_HEAD 0x20\r
+#define HC_CONTROL_CURRENT_PTR 0x24\r
+#define HC_BULK_HEAD 0x28\r
+#define HC_BULK_CURRENT_PTR 0x2C\r
+#define HC_DONE_HEAD 0x30\r
+\r
+//\r
+// Frame Register Offsets\r
+//\r
+#define HC_FRM_INTERVAL 0x34\r
+#define HC_FRM_REMAINING 0x38\r
+#define HC_FRM_NUMBER 0x3C\r
+#define HC_PERIODIC_START 0x40\r
+#define HC_LS_THREASHOLD 0x44\r
+\r
+//\r
+// Root Hub Register Offsets\r
+//\r
+#define HC_RH_DESC_A 0x48\r
+#define HC_RH_DESC_B 0x4C\r
+#define HC_RH_STATUS 0x50\r
+#define HC_RH_PORT_STATUS 0x54\r
+\r
+#define USBHOST_OFFSET_UHCHR 0x64 // Usb Host reset register\r
+\r
+#define OHC_BAR_INDEX 0\r
+\r
+//\r
+// Usb Host controller register offset\r
+//\r
+#define USBHOST_OFFSET_UHCREV 0x0 // Usb Host revision register\r
+#define USBHOST_OFFSET_UHCHCON 0x4 // Usb Host control register\r
+#define USBHOST_OFFSET_UHCCOMS 0x8 // Usb Host Command Status register\r
+#define USBHOST_OFFSET_UHCINTS 0xC // Usb Host Interrupt Status register\r
+#define USBHOST_OFFSET_UHCINTE 0x10 // Usb Host Interrupt Enable register\r
+#define USBHOST_OFFSET_UHCINTD 0x14 // Usb Host Interrupt Disable register\r
+#define USBHOST_OFFSET_UHCHCCA 0x18 // Usb Host Controller Communication Area\r
+#define USBHOST_OFFSET_UHCPCED 0x1C // Usb Host Period Current Endpoint Descriptor\r
+#define USBHOST_OFFSET_UHCCHED 0x20 // Usb Host Control Head Endpoint Descriptor\r
+#define USBHOST_OFFSET_UHCCCED 0x24 // Usb Host Control Current Endpoint Descriptor\r
+#define USBHOST_OFFSET_UHCBHED 0x28 // Usb Host Bulk Head Endpoint Descriptor\r
+#define USBHOST_OFFSET_UHCBCED 0x2C // Usb Host Bulk Current Endpoint Descriptor\r
+#define USBHOST_OFFSET_UHCDHEAD 0x30 // Usb Host Done Head register\r
+#define USBHOST_OFFSET_UHCFMI 0x34 // Usb Host Frame Interval register\r
+#define USBHOST_OFFSET_UHCFMR 0x38 // Usb Host Frame Remaining register\r
+#define USBHOST_OFFSET_UHCFMN 0x3C // Usb Host Frame Number register\r
+#define USBHOST_OFFSET_UHCPERS 0x40 // Usb Host Periodic Start register\r
+#define USBHOST_OFFSET_UHCLST 0x44 // Usb Host Low-Speed Threshold register\r
+#define USBHOST_OFFSET_UHCRHDA 0x48 // Usb Host Root Hub Descriptor A register\r
+#define USBHOST_OFFSET_UHCRHDB 0x4C // Usb Host Root Hub Descriptor B register\r
+#define USBHOST_OFFSET_UHCRHS 0x50 // Usb Host Root Hub Status register\r
+#define USBHOST_OFFSET_UHCRHPS1 0x54 // Usb Host Root Hub Port Status 1 register\r
+\r
+//\r
+// Usb Host controller register bit fields\r
+//\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+ UINT8 ProgInterface;\r
+ UINT8 SubClassCode;\r
+ UINT8 BaseCode;\r
+} USB_CLASSC;\r
+\r
+typedef struct {\r
+ UINT32 Revision:8;\r
+ UINT32 Rsvd:24;\r
+} HcREVISION;\r
+\r
+typedef struct {\r
+ UINT32 ControlBulkRatio:2;\r
+ UINT32 PeriodicEnable:1;\r
+ UINT32 IsochronousEnable:1;\r
+ UINT32 ControlEnable:1;\r
+ UINT32 BulkEnable:1;\r
+ UINT32 FunctionalState:2;\r
+ UINT32 InterruptRouting:1;\r
+ UINT32 RemoteWakeup:1;\r
+ UINT32 RemoteWakeupEnable:1;\r
+ UINT32 Reserved:21;\r
+} HcCONTROL;\r
+\r
+typedef struct {\r
+ UINT32 HcReset:1;\r
+ UINT32 ControlListFilled:1;\r
+ UINT32 BulkListFilled:1;\r
+ UINT32 ChangeOwnerRequest:1;\r
+ UINT32 Reserved1:12;\r
+ UINT32 ScheduleOverrunCount:2;\r
+ UINT32 Reserved:14;\r
+} HcCOMMAND_STATUS;\r
+\r
+typedef struct {\r
+ UINT32 SchedulingOverrun:1;\r
+ UINT32 WriteBackDone:1;\r
+ UINT32 Sof:1;\r
+ UINT32 ResumeDetected:1;\r
+ UINT32 UnrecoverableError:1;\r
+ UINT32 FrameNumOverflow:1;\r
+ UINT32 RHStatusChange:1;\r
+ UINT32 Reserved1:23;\r
+ UINT32 OwnerChange:1;\r
+ UINT32 Reserved2:1;\r
+} HcINTERRUPT_STATUS;\r
+\r
+typedef struct {\r
+ UINT32 SchedulingOverrunInt:1;\r
+ UINT32 WriteBackDoneInt:1;\r
+ UINT32 SofInt:1;\r
+ UINT32 ResumeDetectedInt:1;\r
+ UINT32 UnrecoverableErrorInt:1;\r
+ UINT32 FrameNumOverflowInt:1;\r
+ UINT32 RHStatusChangeInt:1;\r
+ UINT32 Reserved:23;\r
+ UINT32 OwnerChangedInt:1;\r
+ UINT32 MasterInterruptEnable:1;\r
+} HcINTERRUPT_CONTROL;\r
+\r
+typedef struct {\r
+ UINT32 Rerserved:8;\r
+ UINT32 Hcca:24;\r
+} HcHCCA;\r
+\r
+typedef struct {\r
+ UINT32 Reserved:4;\r
+ UINT32 MemoryPtr:28;\r
+} HcMEMORY_PTR;\r
+\r
+typedef struct {\r
+ UINT32 FrameInterval:14;\r
+ UINT32 Reserved:2;\r
+ UINT32 FSMaxDataPacket:15;\r
+ UINT32 FrmIntervalToggle:1;\r
+} HcFRM_INTERVAL;\r
+\r
+typedef struct {\r
+ UINT32 FrameRemaining:14;\r
+ UINT32 Reserved:17;\r
+ UINT32 FrameRemainingToggle:1;\r
+} HcFRAME_REMAINING;\r
+\r
+typedef struct {\r
+ UINT32 FrameNumber:16;\r
+ UINT32 Reserved:16;\r
+} HcFRAME_NUMBER;\r
+\r
+typedef struct {\r
+ UINT32 PeriodicStart:14;\r
+ UINT32 Reserved:18;\r
+} HcPERIODIC_START;\r
+\r
+typedef struct {\r
+ UINT32 LsThreshold:12;\r
+ UINT32 Reserved:20;\r
+} HcLS_THRESHOLD;\r
+\r
+typedef struct {\r
+ UINT32 NumDownStrmPorts:8;\r
+ UINT32 PowerSwitchMode:1;\r
+ UINT32 NoPowerSwitch:1;\r
+ UINT32 DeviceType:1;\r
+ UINT32 OverCurrentProtMode:1;\r
+ UINT32 NoOverCurrentProtMode:1;\r
+ UINT32 Reserved:11;\r
+ UINT32 PowerOnToPowerGoodTime:8;\r
+} HcRH_DESC_A;\r
+\r
+typedef struct {\r
+ UINT32 DeviceRemovable:16;\r
+ UINT32 PortPowerControlMask:16;\r
+} HcRH_DESC_B;\r
+\r
+typedef struct {\r
+ UINT32 LocalPowerStat:1;\r
+ UINT32 OverCurrentIndicator:1;\r
+ UINT32 Reserved1:13;\r
+ UINT32 DevRemoteWakeupEnable:1;\r
+ UINT32 LocalPowerStatChange:1;\r
+ UINT32 OverCurrentIndicatorChange:1;\r
+ UINT32 Reserved2:13;\r
+ UINT32 ClearRemoteWakeupEnable:1;\r
+} HcRH_STATUS;\r
+\r
+typedef struct {\r
+ UINT32 CurrentConnectStat:1;\r
+ UINT32 EnableStat:1;\r
+ UINT32 SuspendStat:1;\r
+ UINT32 OCIndicator:1;\r
+ UINT32 ResetStat:1;\r
+ UINT32 Reserved1:3;\r
+ UINT32 PowerStat:1;\r
+ UINT32 LsDeviceAttached:1;\r
+ UINT32 Reserved2:6;\r
+ UINT32 ConnectStatChange:1;\r
+ UINT32 EnableStatChange:1;\r
+ UINT32 SuspendStatChange:1;\r
+ UINT32 OCIndicatorChange:1;\r
+ UINT32 ResetStatChange:1;\r
+ UINT32 Reserved3:11;\r
+} HcRHPORT_STATUS;\r
+\r
+typedef struct {\r
+ UINT32 FSBIR:1;\r
+ UINT32 FHR:1;\r
+ UINT32 CGR:1;\r
+ UINT32 SSDC:1;\r
+ UINT32 UIT:1;\r
+ UINT32 SSE:1;\r
+ UINT32 PSPL:1;\r
+ UINT32 PCPL:1;\r
+ UINT32 Reserved0:1;\r
+ UINT32 SSEP1:1;\r
+ UINT32 SSEP2:1;\r
+ UINT32 SSEP3:1;\r
+ UINT32 Reserved1:20;\r
+} HcRESET;\r
+\r
+\r
+#pragma pack()\r
+\r
+//\r
+// Func List\r
+//\r
+\r
+\r
+/**\r
+\r
+ Get OHCI operational reg value\r
+\r
+ @param PciIo PciIo protocol instance\r
+ @param Offset Offset of the operational reg\r
+\r
+ @retval Value of the register\r
+\r
+**/\r
+UINT32\r
+OhciGetOperationalReg (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT32 Offset\r
+ );\r
+\r
+/**\r
+\r
+ Set OHCI operational reg value\r
+\r
+ @param PciIo PCI Bus Io protocol instance\r
+ @param Offset Offset of the operational reg\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set to the reg\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+OhciSetOperationalReg (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT32 Offset,\r
+ IN VOID *Value\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Get HcRevision reg value\r
+\r
+ @param PciIo PCI Bus Io protocol instance\r
+\r
+ @retval Value of the register\r
+\r
+**/\r
+\r
+\r
+UINT32\r
+OhciGetHcRevision (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo\r
+ );\r
+\r
+/**\r
+\r
+ Set HcReset reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcReset (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ );\r
+/**\r
+\r
+ Get specific field of HcReset reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcReset (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Field\r
+ );\r
+/**\r
+\r
+ Set HcControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Get specific field of HcControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+\r
+UINT32\r
+OhciGetHcControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Set HcCommand reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcCommandStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ );\r
+\r
+/**\r
+\r
+ Get specific field of HcCommand reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcCommandStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+\r
+/**\r
+\r
+ Clear specific fields of Interrupt Status\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to clear\r
+\r
+ @retval EFI_SUCCESS Fields cleared\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciClearInterruptStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+\r
+/**\r
+\r
+ Get fields of HcInterrupt reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcInterruptStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+\r
+/**\r
+\r
+ Set Interrupt Control reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param StatEnable Enable or Disable\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetInterruptControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN BOOLEAN StatEnable,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ );\r
+\r
+/**\r
+\r
+ Get field of HcInterruptControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcInterruptControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Set memory pointer of specific type\r
+\r
+ @param Ohc UHC private data\r
+ @param PointerType Type of the pointer to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Memory pointer set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetMemoryPointer(\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 PointerType,\r
+ IN VOID *Value\r
+ );\r
+\r
+/**\r
+\r
+ Get memory pointer of specific type\r
+\r
+ @param Ohc UHC private data\r
+ @param PointerType Type of pointer\r
+\r
+ @retval Memory pointer of the specific type\r
+\r
+**/\r
+\r
+VOID *\r
+OhciGetMemoryPointer (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 PointerType\r
+ );\r
+\r
+/**\r
+\r
+ Set Frame Interval value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameInterval (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Get field of frame interval reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetFrameInterval (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Set Frame Remaining reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameRemaining (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ );\r
+\r
+/**\r
+\r
+ Get value of frame remaining reg\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of frame remaining reg\r
+\r
+**/\r
+UINT32\r
+OhciGetFrameRemaining (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+\r
+/**\r
+\r
+ Set frame number reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameNumber(\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ );\r
+\r
+/**\r
+\r
+ Get frame number reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @retval Value of frame number reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetFrameNumber (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Set period start reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetPeriodicStart (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Get periodic start reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @param Value of periodic start reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetPeriodicStart (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Set Ls Threshold reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetLsThreshold (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ );\r
+\r
+/**\r
+\r
+ Get Ls Threshold reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @retval Value of Ls Threshold reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetLsThreshold (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ );\r
+\r
+/**\r
+\r
+ Set Root Hub Descriptor reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetRootHubDescriptor (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Get Root Hub Descriptor reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetRootHubDescriptor (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+\r
+/**\r
+\r
+ Set Root Hub Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetRootHubStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Get Root Hub Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetRootHubStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Set Root Hub Port Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Index Index of the port\r
+ @param Field Field to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetRootHubPortStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Index,\r
+ IN UINTN Field\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Get Root Hub Port Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Index Index of the port\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field and index\r
+\r
+**/\r
+\r
+UINT32\r
+OhciReadRootHubPortStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Index,\r
+ IN UINTN Field\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+OHCI transfer scheduling routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "Ohci.h"\r
+\r
+/**\r
+\r
+ Add an item of interrupt context\r
+\r
+ @param Ohc UHC private data\r
+ @param NewEntry New entry to add\r
+\r
+ @retval EFI_SUCCESS Item successfully added\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAddInterruptContextEntry (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN INTERRUPT_CONTEXT_ENTRY *NewEntry\r
+ )\r
+{\r
+ INTERRUPT_CONTEXT_ENTRY *Entry;\r
+ EFI_TPL OriginalTPL;\r
+\r
+ OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ if (Ohc->InterruptContextList == NULL) {\r
+ Ohc->InterruptContextList = NewEntry;\r
+ } else {\r
+ Entry = Ohc->InterruptContextList;\r
+ while (Entry->NextEntry != NULL) {\r
+ Entry = Entry->NextEntry;\r
+ }\r
+ Entry->NextEntry = NewEntry;\r
+ }\r
+\r
+ gBS->RestoreTPL (OriginalTPL);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Free a interrupt context entry\r
+\r
+ @param Ohc UHC private data\r
+ @param Entry Pointer to an interrupt context entry\r
+\r
+ @retval EFI_SUCCESS Entry freed\r
+ @retval EFI_INVALID_PARAMETER Entry is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeInterruptContextEntry (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN INTERRUPT_CONTEXT_ENTRY *Entry\r
+ )\r
+{\r
+ TD_DESCRIPTOR *Td;\r
+ if (Entry == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (Entry->UCBufferMapping != NULL) {\r
+ Ohc->PciIo->Unmap(Ohc->PciIo, Entry->UCBufferMapping);\r
+ }\r
+ if (Entry->UCBuffer != NULL) {\r
+ FreePool(Entry->UCBuffer);\r
+ }\r
+ while (Entry->DataTd) {\r
+ Td = Entry->DataTd;\r
+ Entry->DataTd = (TD_DESCRIPTOR *)(UINTN)(Entry->DataTd->NextTDPointer);\r
+ UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR));\r
+ }\r
+ FreePool(Entry);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Free entries match the device address and endpoint address\r
+\r
+ @Param Ohc UHC private date\r
+ @Param DeviceAddress Item to free must match this device address\r
+ @Param EndPointAddress Item to free must match this end point address\r
+ @Param DataToggle DataToggle for output\r
+\r
+ @retval EFI_SUCCESS Items match the requirement removed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeInterruptContext(\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ OUT UINT8 *DataToggle\r
+ )\r
+{\r
+ INTERRUPT_CONTEXT_ENTRY *Entry;\r
+ INTERRUPT_CONTEXT_ENTRY *TempEntry;\r
+ EFI_TPL OriginalTPL;\r
+\r
+\r
+ OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ while (Ohc->InterruptContextList != NULL &&\r
+ Ohc->InterruptContextList->DeviceAddress == DeviceAddress &&\r
+ Ohc->InterruptContextList->EndPointAddress == EndPointAddress) {\r
+ TempEntry = Ohc->InterruptContextList;\r
+ Ohc->InterruptContextList = Ohc->InterruptContextList->NextEntry;\r
+ if (DataToggle != NULL) {\r
+ *DataToggle = (UINT8) (TempEntry->DataTd->Word0.DataToggle & 0x1);\r
+ }\r
+ OhciFreeInterruptContextEntry (Ohc, TempEntry);\r
+ }\r
+\r
+ Entry = Ohc->InterruptContextList;\r
+ if (Entry == NULL) {\r
+ gBS->RestoreTPL (OriginalTPL);\r
+ return EFI_SUCCESS;\r
+ }\r
+ while (Entry->NextEntry != NULL) {\r
+ if (Entry->NextEntry->DeviceAddress == DeviceAddress &&\r
+ Entry->NextEntry->EndPointAddress == EndPointAddress) {\r
+ TempEntry = Entry->NextEntry;\r
+ Entry->NextEntry = Entry->NextEntry->NextEntry;\r
+ if (DataToggle != NULL) {\r
+ *DataToggle = (UINT8) (TempEntry->DataTd->Word0.DataToggle & 0x1);\r
+ }\r
+ OhciFreeInterruptContextEntry (Ohc, TempEntry);\r
+ } else {\r
+ Entry = Entry->NextEntry;\r
+ }\r
+ }\r
+\r
+ gBS->RestoreTPL (OriginalTPL);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Convert Error code from OHCI format to EFI format\r
+\r
+ @Param ErrorCode ErrorCode in OHCI format\r
+\r
+ @retval ErrorCode in EFI format\r
+\r
+**/\r
+UINT32\r
+ConvertErrorCode (\r
+ IN UINT32 ErrorCode\r
+ )\r
+{\r
+ UINT32 TransferResult;\r
+\r
+ switch (ErrorCode) {\r
+ case TD_NO_ERROR:\r
+ TransferResult = EFI_USB_NOERROR;\r
+ break;\r
+\r
+ case TD_TOBE_PROCESSED:\r
+ case TD_TOBE_PROCESSED_2:\r
+ TransferResult = EFI_USB_ERR_NOTEXECUTE;\r
+ break;\r
+\r
+ case TD_DEVICE_STALL:\r
+ TransferResult = EFI_USB_ERR_STALL;\r
+ break;\r
+\r
+ case TD_BUFFER_OVERRUN:\r
+ case TD_BUFFER_UNDERRUN:\r
+ TransferResult = EFI_USB_ERR_BUFFER;\r
+ break;\r
+\r
+ case TD_CRC_ERROR:\r
+ TransferResult = EFI_USB_ERR_CRC;\r
+ break;\r
+\r
+ case TD_NO_RESPONSE:\r
+ TransferResult = EFI_USB_ERR_TIMEOUT;\r
+ break;\r
+\r
+ case TD_BITSTUFFING_ERROR:\r
+ TransferResult = EFI_USB_ERR_BITSTUFF;\r
+ break;\r
+\r
+ default:\r
+ TransferResult = EFI_USB_ERR_SYSTEM;\r
+ }\r
+\r
+ return TransferResult;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Check TDs Results\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Td TD_DESCRIPTOR\r
+ @Param Result Result to return\r
+\r
+ @retval TRUE means OK\r
+ @retval FLASE means Error or Short packet\r
+\r
+**/\r
+BOOLEAN\r
+OhciCheckTDsResults (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN TD_DESCRIPTOR *Td,\r
+ OUT UINT32 *Result\r
+ )\r
+{\r
+ UINT32 TdCompletionCode;\r
+\r
+ *Result = EFI_USB_NOERROR;\r
+\r
+ while (Td) {\r
+ TdCompletionCode = Td->Word0.ConditionCode;\r
+\r
+ *Result |= ConvertErrorCode(TdCompletionCode);\r
+ //\r
+ // if any error encountered, stop processing the left TDs.\r
+ //\r
+ if (*Result) {\r
+ return FALSE;\r
+ }\r
+\r
+ Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer);\r
+ }\r
+ return TRUE;\r
+\r
+}\r
+\r
+\r
+/**\r
+\r
+ Check the task status on an ED\r
+\r
+ @Param Ed Pointer to the ED task that TD hooked on\r
+ @Param HeadTd TD header for current transaction\r
+\r
+ @retval Task Status Code\r
+\r
+**/\r
+\r
+UINT32\r
+CheckEDStatus (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd,\r
+ OUT OHCI_ED_RESULT *EdResult\r
+ )\r
+{\r
+ while(HeadTd != NULL) {\r
+ if (HeadTd->NextTDPointer == 0) {\r
+ return TD_NO_ERROR;\r
+ }\r
+ if (HeadTd->Word0.ConditionCode != 0) {\r
+ return HeadTd->Word0.ConditionCode;\r
+ }\r
+ EdResult->NextToggle = ((UINT8)(HeadTd->Word0.DataToggle) & BIT0) ^ BIT0;\r
+ HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer);\r
+ }\r
+ if (OhciGetEDField (Ed, ED_TDHEAD_PTR) != OhciGetEDField (Ed, ED_TDTAIL_PTR)) {\r
+ return TD_TOBE_PROCESSED;\r
+ }\r
+ return TD_NO_ERROR;\r
+}\r
+\r
+/**\r
+\r
+ Check the task status\r
+\r
+ @Param Ohc UHC private data\r
+ @Param ListType Pipe type\r
+ @Param Ed Pointer to the ED task hooked on\r
+ @Param HeadTd Head of TD corresponding to the task\r
+ @Param ErrorCode return the ErrorCode\r
+\r
+ @retval EFI_SUCCESS Task done\r
+ @retval EFI_NOT_READY Task on processing\r
+ @retval EFI_DEVICE_ERROR Some error occured\r
+\r
+**/\r
+EFI_STATUS\r
+CheckIfDone (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN DESCRIPTOR_LIST_TYPE ListType,\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd,\r
+ OUT OHCI_ED_RESULT *EdResult\r
+ )\r
+{\r
+ EdResult->ErrorCode = TD_TOBE_PROCESSED;\r
+\r
+ switch (ListType) {\r
+ case CONTROL_LIST:\r
+ if (OhciGetHcCommandStatus (Ohc, CONTROL_LIST_FILLED) != 0) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ break;\r
+ case BULK_LIST:\r
+ if (OhciGetHcCommandStatus (Ohc, BULK_LIST_FILLED) != 0) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+\r
+ EdResult->ErrorCode = CheckEDStatus (Ed, HeadTd, EdResult);\r
+\r
+ if (EdResult->ErrorCode == TD_NO_ERROR) {\r
+ return EFI_SUCCESS;\r
+ } else if (EdResult->ErrorCode == TD_TOBE_PROCESSED) {\r
+ return EFI_NOT_READY;\r
+ } else {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+\r
+ Convert TD condition code to Efi Status\r
+\r
+ @Param ConditionCode Condition code to convert\r
+\r
+ @retval EFI_SUCCESS No error occured\r
+ @retval EFI_NOT_READY TD still on processing\r
+ @retval EFI_DEVICE_ERROR Error occured in processing TD\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciTDConditionCodeToStatus (\r
+ IN UINT32 ConditionCode\r
+ )\r
+{\r
+ if (ConditionCode == TD_NO_ERROR) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (ConditionCode == TD_TOBE_PROCESSED) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ return EFI_DEVICE_ERROR;\r
+}\r
+\r
+/**\r
+\r
+ Invoke callbacks hooked on done TDs\r
+\r
+ @Param Entry Interrupt transfer transaction information data structure\r
+ @Param Context Ohc private data\r
+\r
+**/\r
+\r
+VOID\r
+OhciInvokeInterruptCallBack(\r
+ IN INTERRUPT_CONTEXT_ENTRY *Entry,\r
+ IN UINT32 Result\r
+)\r
+{\r
+ //Generally speaking, Keyboard driver should not\r
+ //check the Keyboard buffer if an error happens, it will be robust\r
+ //if we NULLed the buffer once error happens\r
+ if (Result) {\r
+ Entry->CallBackFunction (\r
+ NULL,\r
+ 0,\r
+ Entry->Context,\r
+ Result\r
+ );\r
+ }else{\r
+ Entry->CallBackFunction (\r
+ (VOID *)(UINTN)(Entry->DataTd->DataBuffer),\r
+ Entry->DataTd->ActualSendLength,\r
+ Entry->Context,\r
+ Result\r
+ );\r
+ }\r
+}\r
+\r
+\r
+/**\r
+\r
+ Timer to submit periodic interrupt transfer, and invoke callbacks hooked on done TDs\r
+\r
+ @param Event Event handle\r
+ @param Context Device private data\r
+\r
+**/\r
+\r
+VOID\r
+EFIAPI\r
+OhciHouseKeeper (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ INTERRUPT_CONTEXT_ENTRY *Entry;\r
+ INTERRUPT_CONTEXT_ENTRY *PreEntry;\r
+ ED_DESCRIPTOR *Ed;\r
+ TD_DESCRIPTOR *DataTd;\r
+ TD_DESCRIPTOR *HeadTd;\r
+\r
+ UINT8 Toggle;\r
+ EFI_TPL OriginalTPL;\r
+ UINT32 Result;\r
+\r
+ Ohc = (USB_OHCI_HC_DEV *) Context;\r
+ OriginalTPL = gBS->RaiseTPL(TPL_NOTIFY);\r
+\r
+ Entry = Ohc->InterruptContextList;\r
+ PreEntry = NULL;\r
+\r
+ while(Entry != NULL) {\r
+\r
+ OhciCheckTDsResults(Ohc, Entry->DataTd, &Result );\r
+ if (((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) ||\r
+ ((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE)) {\r
+ PreEntry = Entry;\r
+ Entry = Entry->NextEntry;\r
+ continue;\r
+ }\r
+\r
+ if (Entry->CallBackFunction != NULL) {\r
+ OhciInvokeInterruptCallBack (Entry, Result);\r
+ if (Ohc->InterruptContextList == NULL) {\r
+ gBS->RestoreTPL (OriginalTPL);\r
+ return;\r
+ }\r
+ }\r
+ if (Entry->IsPeriodic) {\r
+\r
+ Ed = Entry->Ed;\r
+ HeadTd = Entry->DataTd;\r
+ DataTd = HeadTd;\r
+ Toggle = 0;\r
+ if (Result == EFI_USB_NOERROR) {\r
+ //\r
+ // Update toggle if there is no error, and re-submit the interrupt Ed&Tds\r
+ //\r
+ if ((Ed != NULL) && (DataTd != NULL)) {\r
+ Ed->Word0.Skip = 1;\r
+ }\r
+ //\r
+ // From hcir1_0a.pdf 4.2.2\r
+ // ToggleCarry:This bit is the data toggle carry bit,\r
+ // Whenever a TD is retired, this bit is written to\r
+ // contain the last data toggle value(LSb of data Toggel\r
+ // file) from the retired TD.\r
+ // This field is not used for Isochronous Endpoints\r
+ //\r
+ if (Ed == NULL) {\r
+ return;\r
+ }\r
+ Toggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);\r
+ while(DataTd != NULL) {\r
+ if (DataTd->NextTDPointer == 0) {\r
+ DataTd->Word0.DataToggle = 0;\r
+ break;\r
+ } else {\r
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, Toggle);\r
+ }\r
+ DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer);\r
+ Toggle ^= 1;\r
+ }\r
+ //\r
+ // HC will only update DataToggle, ErrorCount, ConditionCode\r
+ // CurrentBufferPointer & NextTD, so we only need to update\r
+ // them once we want to active them again\r
+ //\r
+ DataTd = HeadTd;\r
+ while (DataTd != NULL) {\r
+ if (DataTd->NextTDPointer == 0) {\r
+ OhciSetTDField (DataTd, TD_ERROR_CNT | TD_COND_CODE | TD_CURR_BUFFER_PTR | TD_NEXT_PTR, 0);\r
+ break;\r
+ }\r
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+ DataTd->NextTD = DataTd->NextTDPointer;\r
+ DataTd->CurrBufferPointer = DataTd->DataBuffer;\r
+ DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer);\r
+ }\r
+ //\r
+ // Active current Ed,Td\r
+ //\r
+ // HC will only update Halted, ToggleCarry & TDQueueHeadPointer,\r
+ // So we only need to update them once we want to active them again.\r
+ //\r
+ if ((Ed != NULL) && (DataTd != NULL)) {\r
+ Ed->Word2.TdHeadPointer = (UINT32)((UINTN)HeadTd>>4);\r
+ OhciSetEDField (Ed, ED_HALTED | ED_DTTOGGLE, 0);\r
+ Ed->Word0.Skip = 0;\r
+ }\r
+ }\r
+ } else {\r
+ if (PreEntry == NULL) {\r
+ Ohc->InterruptContextList = Entry->NextEntry;\r
+ } else {\r
+ PreEntry = Entry;\r
+ PreEntry->NextEntry = Entry->NextEntry;\r
+ }\r
+ OhciFreeInterruptContextEntry (Ohc, PreEntry);\r
+ gBS->RestoreTPL (OriginalTPL);\r
+ return;\r
+ }\r
+ PreEntry = Entry;\r
+ Entry = Entry->NextEntry;\r
+ }\r
+ gBS->RestoreTPL (OriginalTPL);\r
+}\r
+\r
--- /dev/null
+/** @file\r
+This file contains the definination for host controller schedule routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#ifndef _OHCI_SCHED_H\r
+#define _OHCI_SCHED_H\r
+\r
+#include "Descriptor.h"\r
+\r
+#define HCCA_MEM_SIZE 256\r
+#define GRID_SIZE 16\r
+#define GRID_SHIFT 4\r
+\r
+typedef struct _INTERRUPT_CONTEXT_ENTRY INTERRUPT_CONTEXT_ENTRY;\r
+\r
+struct _INTERRUPT_CONTEXT_ENTRY{\r
+ UINT8 DeviceAddress;\r
+ UINT8 EndPointAddress;\r
+ ED_DESCRIPTOR *Ed;\r
+ TD_DESCRIPTOR *DataTd;\r
+ BOOLEAN IsSlowDevice;\r
+ UINT8 MaxPacketLength;\r
+ UINTN PollingInterval;\r
+ EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction;\r
+ VOID *Context;\r
+ BOOLEAN IsPeriodic;\r
+ VOID *Buffer;\r
+ UINTN DataLength;\r
+ VOID *UCBuffer;\r
+ VOID *UCBufferMapping;\r
+ UINT8 *Toggle;\r
+ INTERRUPT_CONTEXT_ENTRY *NextEntry;\r
+};\r
+\r
+\r
+typedef struct {\r
+ UINT32 ErrorCode;\r
+ UINT8 NextToggle;\r
+} OHCI_ED_RESULT;\r
+\r
+/**\r
+\r
+ Add an item of interrupt context\r
+\r
+ @param Ohc UHC private data\r
+ @param NewEntry New entry to add\r
+\r
+ @retval EFI_SUCCESS Item successfully added\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAddInterruptContextEntry (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN INTERRUPT_CONTEXT_ENTRY *NewEntry\r
+ );\r
+\r
+/**\r
+\r
+ Free a interrupt context entry\r
+\r
+ @param Ohc UHC private data\r
+ @param Entry Pointer to an interrupt context entry\r
+\r
+ @retval EFI_SUCCESS Entry freed\r
+ @retval EFI_INVALID_PARAMETER Entry is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeInterruptContextEntry (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN INTERRUPT_CONTEXT_ENTRY *Entry\r
+ );\r
+\r
+/**\r
+\r
+ Free entries match the device address and endpoint address\r
+\r
+ @Param Ohc UHC private date\r
+ @Param DeviceAddress Item to free must match this device address\r
+ @Param EndPointAddress Item to free must match this end point address\r
+ @Param DataToggle DataToggle for output\r
+\r
+ @retval EFI_SUCCESS Items match the requirement removed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeInterruptContext(\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ OUT UINT8 *DataToggle\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Convert Error code from OHCI format to EFI format\r
+\r
+ @Param ErrorCode ErrorCode in OHCI format\r
+\r
+ @retval ErrorCode in EFI format\r
+\r
+**/\r
+UINT32\r
+ConvertErrorCode (\r
+ IN UINT32 ErrorCode\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Check TDs Results\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Td TD_DESCRIPTOR\r
+ @Param Result Result to return\r
+\r
+ @retval TRUE means OK\r
+ @retval FLASE means Error or Short packet\r
+\r
+**/\r
+BOOLEAN\r
+OhciCheckTDsResults (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN TD_DESCRIPTOR *Td,\r
+ OUT UINT32 *Result\r
+ );\r
+/**\r
+\r
+ Check the task status on an ED\r
+\r
+ @Param Ed Pointer to the ED task that TD hooked on\r
+ @Param HeadTd TD header for current transaction\r
+\r
+ @retval Task Status Code\r
+\r
+**/\r
+\r
+UINT32\r
+CheckEDStatus (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd,\r
+ OUT OHCI_ED_RESULT *EdResult\r
+ );\r
+/**\r
+\r
+ Check the task status\r
+\r
+ @Param Ohc UHC private data\r
+ @Param ListType Pipe type\r
+ @Param Ed Pointer to the ED task hooked on\r
+ @Param HeadTd Head of TD corresponding to the task\r
+ @Param ErrorCode return the ErrorCode\r
+\r
+ @retval EFI_SUCCESS Task done\r
+ @retval EFI_NOT_READY Task on processing\r
+ @retval EFI_DEVICE_ERROR Some error occured\r
+\r
+**/\r
+EFI_STATUS\r
+CheckIfDone (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN DESCRIPTOR_LIST_TYPE ListType,\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd,\r
+ OUT OHCI_ED_RESULT *EdResult\r
+ );\r
+\r
+/**\r
+\r
+ Convert TD condition code to Efi Status\r
+\r
+ @Param ConditionCode Condition code to convert\r
+\r
+ @retval EFI_SUCCESS No error occured\r
+ @retval EFI_NOT_READY TD still on processing\r
+ @retval EFI_DEVICE_ERROR Error occured in processing TD\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciTDConditionCodeToStatus (\r
+ IN UINT32 ConditionCode\r
+ );\r
+\r
+/**\r
+\r
+ Invoke callbacks hooked on done TDs\r
+\r
+ @Param Entry Interrupt transfer transaction information data structure\r
+ @Param Context Ohc private data\r
+\r
+**/\r
+\r
+VOID\r
+OhciInvokeInterruptCallBack(\r
+ IN INTERRUPT_CONTEXT_ENTRY *Entry,\r
+ IN UINT32 Result\r
+);\r
+\r
+\r
+/**\r
+\r
+ Timer to submit periodic interrupt transfer, and invoke callbacks hooked on done TDs\r
+\r
+ @param Event Event handle\r
+ @param Context Device private data\r
+\r
+**/\r
+\r
+VOID\r
+EFIAPI\r
+OhciHouseKeeper (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This file contains URB request, each request is warpped in a\r
+URB (Usb Request Block).\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#include "Ohci.h"\r
+\r
+\r
+/**\r
+\r
+ Create a TD\r
+\r
+ @Param Ohc UHC private data\r
+\r
+ @retval TD structure pointer\r
+\r
+**/\r
+TD_DESCRIPTOR *\r
+OhciCreateTD (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ TD_DESCRIPTOR *Td;\r
+\r
+ Td = UsbHcAllocateMem(Ohc->MemPool, sizeof(TD_DESCRIPTOR));\r
+ if (Td == NULL) {\r
+ DEBUG ((EFI_D_INFO, "STV allocate TD fail !\r\n"));\r
+ return NULL;\r
+ }\r
+ Td->CurrBufferPointer = 0;\r
+ Td->NextTD = 0;\r
+ Td->BufferEndPointer = 0;\r
+ Td->NextTDPointer = 0;\r
+\r
+ return Td;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Free a TD\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Td Pointer to a TD to free\r
+\r
+ @retval EFI_SUCCESS TD freed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeTD (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN TD_DESCRIPTOR *Td\r
+ )\r
+{\r
+ if (Td == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Create a ED\r
+\r
+ @Param Ohc Device private data\r
+\r
+ @retval ED descriptor pointer\r
+\r
+**/\r
+ED_DESCRIPTOR *\r
+OhciCreateED (\r
+ USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ ED_DESCRIPTOR *Ed;\r
+ Ed = UsbHcAllocateMem(Ohc->MemPool, sizeof (ED_DESCRIPTOR));\r
+ if (Ed == NULL) {\r
+ DEBUG ((EFI_D_INFO, "STV allocate ED fail !\r\n"));\r
+ return NULL;\r
+ }\r
+ Ed->Word0.Skip = 1;\r
+ Ed->TdTailPointer = 0;\r
+ Ed->Word2.TdHeadPointer = 0;\r
+ Ed->NextED = 0;\r
+\r
+ return Ed;\r
+}\r
+\r
+/**\r
+\r
+ Free a ED\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Ed Pointer to a ED to free\r
+\r
+ @retval EFI_SUCCESS ED freed\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciFreeED (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN ED_DESCRIPTOR *Ed\r
+ )\r
+{\r
+ if (Ed == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Free ED\r
+\r
+ @Param Ohc Device private data\r
+ @Param Ed Pointer to a ED to free\r
+\r
+ @retval EFI_SUCCESS ED freed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeAllTDFromED (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN ED_DESCRIPTOR *Ed\r
+ )\r
+{\r
+ TD_DESCRIPTOR *HeadTd;\r
+ TD_DESCRIPTOR *TailTd;\r
+ TD_DESCRIPTOR *Td;\r
+ TD_DESCRIPTOR *TempTd;\r
+\r
+ if (Ed == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ HeadTd = TD_PTR (Ed->Word2.TdHeadPointer);\r
+ TailTd = (TD_DESCRIPTOR *)(UINTN)(Ed->TdTailPointer);\r
+\r
+ Td = HeadTd;\r
+ while (Td != TailTd) {\r
+ TempTd = Td;\r
+ Td = (TD_DESCRIPTOR *)(UINTN)(Td->NextTDPointer);\r
+ OhciFreeTD (Ohc, TempTd);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Find a working ED match the requirement\r
+\r
+ @Param EdHead Head of the ED list\r
+ @Param DeviceAddress Device address to search\r
+ @Param EndPointNum End point num to search\r
+ @Param EdDir ED Direction to search\r
+\r
+ @retval ED descriptor searched\r
+\r
+**/\r
+\r
+ED_DESCRIPTOR *\r
+OhciFindWorkingEd (\r
+ IN ED_DESCRIPTOR *EdHead,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointNum,\r
+ IN UINT8 EdDir\r
+ )\r
+{\r
+ ED_DESCRIPTOR *Ed;\r
+\r
+ for (Ed = EdHead; Ed != NULL; Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED)) {\r
+ if (Ed->Word2.Halted == 0 && Ed->Word0.Skip == 0 &&\r
+ Ed->Word0.FunctionAddress == DeviceAddress && Ed->Word0.EndPointNum == EndPointNum &&\r
+ Ed->Word0.Direction == EdDir) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ return Ed;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Initialize interrupt list.\r
+\r
+ @Param Ohc Device private data\r
+\r
+ @retval EFI_SUCCESS Initialization done\r
+\r
+**/\r
+EFI_STATUS\r
+OhciInitializeInterruptList (\r
+ USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ static UINT32 Leaf[32] = {0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17,\r
+ 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31};\r
+ UINT32 *HccaInterruptTable;\r
+ UINTN Index;\r
+ UINTN Level;\r
+ UINTN Count;\r
+ ED_DESCRIPTOR *NewEd;\r
+\r
+ HccaInterruptTable = Ohc->HccaMemoryBlock->HccaInterruptTable;\r
+\r
+ for (Index = 0; Index < 32; Index++) {\r
+ NewEd = OhciCreateED (Ohc);\r
+ if (NewEd == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ HccaInterruptTable[Index] = (UINT32)(UINTN)NewEd;\r
+ }\r
+\r
+ for (Index = 0; Index < 32; Index++) {\r
+ Ohc->IntervalList[0][Index] = (ED_DESCRIPTOR *)(UINTN)HccaInterruptTable[Leaf[Index]];\r
+ }\r
+\r
+ Count = 32;\r
+ for (Level = 1; Level <= 5; Level++) {\r
+ Count = Count >> 1;\r
+\r
+ for (Index = 0; Index < Count; Index++) {\r
+ Ohc->IntervalList[Level][Index] = OhciCreateED (Ohc);\r
+ if (HccaInterruptTable[Index] == 0) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Ohc->IntervalList[Level - 1][Index * 2 ]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index];\r
+ Ohc->IntervalList[Level - 1][Index * 2 + 1]->NextED = (UINT32)(UINTN)Ohc->IntervalList[Level][Index];\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Attach an ED\r
+\r
+ @Param Ed Ed to be attached\r
+ @Param NewEd Ed to attach\r
+\r
+ @retval EFI_SUCCESS NewEd attached to Ed\r
+ @retval EFI_INVALID_PARAMETER Ed is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAttachED (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN ED_DESCRIPTOR *NewEd\r
+ )\r
+{\r
+ ED_DESCRIPTOR *Temp;\r
+\r
+ if (Ed == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Ed->NextED == 0){\r
+ Ed->NextED = (UINT32)(UINTN)NewEd;\r
+ } else {\r
+ Temp = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);\r
+ Ed->NextED = (UINT32)(UINTN)NewEd;\r
+ NewEd->NextED = (UINT32)(UINTN)Temp;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Count ED number on a ED chain\r
+\r
+ @Param Ed Head of the ED chain\r
+\r
+ @retval ED number on the chain\r
+\r
+**/\r
+\r
+UINTN\r
+CountEdNum (\r
+ IN ED_DESCRIPTOR *Ed\r
+ )\r
+{\r
+ UINTN Count;\r
+\r
+ Count = 0;\r
+\r
+ while (Ed) {\r
+ Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);\r
+ Count++;\r
+ }\r
+\r
+ return Count;\r
+}\r
+\r
+/**\r
+\r
+ Find the minimal burn ED list on a specific depth level\r
+\r
+ @Param Ohc Device private data\r
+ @Param Depth Depth level\r
+\r
+ @retval ED list found\r
+\r
+**/\r
+\r
+ED_DESCRIPTOR *\r
+OhciFindMinInterruptEDList (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Depth\r
+ )\r
+{\r
+ UINTN EdNum;\r
+ UINTN MinEdNum;\r
+ ED_DESCRIPTOR *TempEd;\r
+ ED_DESCRIPTOR *HeadEd;\r
+ UINTN Index;\r
+\r
+ if (Depth > 5) {\r
+ return NULL;\r
+ }\r
+\r
+ MinEdNum = 0xFFFFFFFF;\r
+ TempEd = NULL;\r
+ for (Index = 0; Index < (UINTN)(32 >> Depth); Index++) {\r
+ HeadEd = Ohc->IntervalList[Depth][Index];\r
+ EdNum = CountEdNum (HeadEd);\r
+ if (EdNum < MinEdNum) {\r
+ MinEdNum = EdNum;\r
+ TempEd = HeadEd;\r
+ }\r
+ }\r
+\r
+ ASSERT (TempEd != NULL);\r
+\r
+ return TempEd;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Attach an ED to an ED list\r
+\r
+ @Param OHC UHC private data\r
+ @Param ListType Type of the ED list\r
+ @Param Ed ED to attach\r
+ @Param EdList ED list to be attached\r
+\r
+ @retval EFI_SUCCESS ED attached to ED list\r
+\r
+**/\r
+ED_DESCRIPTOR *\r
+OhciAttachEDToList (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN DESCRIPTOR_LIST_TYPE ListType,\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN ED_DESCRIPTOR *EdList\r
+ )\r
+{\r
+ ED_DESCRIPTOR *HeadEd;\r
+\r
+ HeadEd = NULL;\r
+ switch(ListType) {\r
+ case CONTROL_LIST:\r
+ HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_CONTROL_HEAD);\r
+ if (HeadEd == NULL) {\r
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, Ed);\r
+ HeadEd = Ed;\r
+ } else {\r
+ OhciAttachED (HeadEd, Ed);\r
+ }\r
+ break;\r
+\r
+ case BULK_LIST:\r
+ HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_BULK_HEAD);\r
+ if (HeadEd == NULL) {\r
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, Ed);\r
+ HeadEd = Ed;\r
+ } else {\r
+ OhciAttachED (HeadEd, Ed);\r
+ }\r
+ break;\r
+\r
+ case INTERRUPT_LIST:\r
+ OhciAttachED (EdList, Ed);\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return HeadEd;\r
+}\r
+\r
+/**\r
+\r
+ Remove interrupt EDs that match requirement\r
+\r
+ @Param Ohc UHC private data\r
+ @Param IntEd The address of Interrupt endpoint\r
+\r
+ @retval EFI_SUCCESS EDs match requirement removed\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciFreeInterruptEdByEd (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN ED_DESCRIPTOR *IntEd\r
+ )\r
+{\r
+ ED_DESCRIPTOR *Ed;\r
+ ED_DESCRIPTOR *TempEd;\r
+ UINTN Index;\r
+\r
+ if (IntEd == NULL)\r
+ return EFI_SUCCESS;\r
+\r
+ for (Index = 0; Index < 32; Index++) {\r
+ Ed = (ED_DESCRIPTOR *)(UINTN)Ohc->HccaMemoryBlock->HccaInterruptTable[Index];\r
+ if (Ed == NULL) {\r
+ continue;\r
+ }\r
+ while (Ed->NextED != 0) {\r
+ if (Ed->NextED == (UINT32)(UINTN)IntEd ) {\r
+ TempEd = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);\r
+ Ed->NextED = TempEd->NextED;\r
+ OhciFreeED (Ohc, TempEd);\r
+ } else {\r
+ Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);\r
+ }\r
+ }\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Remove interrupt EDs that match requirement\r
+\r
+ @Param Ohc UHC private data\r
+ @Param FunctionAddress Requirement on function address\r
+ @Param EndPointNum Requirement on end point number\r
+\r
+ @retval EFI_SUCCESS EDs match requirement removed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeInterruptEdByAddr (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT8 FunctionAddress,\r
+ IN UINT8 EndPointNum\r
+ )\r
+{\r
+ ED_DESCRIPTOR *Ed;\r
+ ED_DESCRIPTOR *TempEd;\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < 32; Index++) {\r
+ Ed = (ED_DESCRIPTOR *)(UINTN)Ohc->HccaMemoryBlock->HccaInterruptTable[Index];\r
+ if (Ed == NULL) {\r
+ continue;\r
+ }\r
+\r
+ while (Ed->NextED != 0) {\r
+ TempEd = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);\r
+ if (TempEd->Word0.FunctionAddress == FunctionAddress &&\r
+ TempEd->Word0.EndPointNum == EndPointNum ) {\r
+ Ed->NextED = TempEd->NextED;\r
+ OhciFreeED (Ohc, TempEd);\r
+ } else {\r
+ Ed = (ED_DESCRIPTOR *)(UINTN)(Ed->NextED);\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Link Td2 to the end of Td1\r
+\r
+ @Param Td1 TD to be linked\r
+ @Param Td2 TD to link\r
+\r
+ @retval EFI_SUCCESS TD successfully linked\r
+ @retval EFI_INVALID_PARAMETER Td1 is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+OhciLinkTD (\r
+ IN TD_DESCRIPTOR *Td1,\r
+ IN TD_DESCRIPTOR *Td2\r
+ )\r
+{\r
+ TD_DESCRIPTOR *TempTd;\r
+\r
+ if (Td1 == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Td1 == Td2) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ TempTd = Td1;\r
+ while (TempTd->NextTD != 0) {\r
+ TempTd = (TD_DESCRIPTOR *)(UINTN)(TempTd->NextTD);\r
+ }\r
+\r
+ TempTd->NextTD = (UINT32)(UINTN)Td2;\r
+ TempTd->NextTDPointer = (UINT32)(UINTN)Td2;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Attach TD list to ED\r
+\r
+ @Param Ed ED which TD list attach on\r
+ @Param HeadTd Head of the TD list to attach\r
+\r
+ @retval EFI_SUCCESS TD list attached on the ED\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAttachTDListToED (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd\r
+ )\r
+{\r
+ TD_DESCRIPTOR *TempTd;\r
+\r
+ TempTd = TD_PTR (Ed->Word2.TdHeadPointer);\r
+\r
+ if (TempTd != NULL) {\r
+ while (TempTd->NextTD != 0) {\r
+ TempTd = (TD_DESCRIPTOR *)(UINTN)(TempTd->NextTD);\r
+ }\r
+ TempTd->NextTD = (UINT32)(UINTN)HeadTd;\r
+ TempTd->NextTDPointer = (UINT32)(UINTN)HeadTd;\r
+ } else {\r
+ Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32)(UINTN)HeadTd);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set value to ED specific field\r
+\r
+ @Param Ed ED to be set\r
+ @Param Field Field to be set\r
+ @Param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetEDField (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ if (Field & ED_FUNC_ADD) {\r
+ Ed->Word0.FunctionAddress = Value;\r
+ }\r
+ if (Field & ED_ENDPT_NUM) {\r
+ Ed->Word0.EndPointNum = Value;\r
+ }\r
+ if (Field & ED_DIR) {\r
+ Ed->Word0.Direction = Value;\r
+ }\r
+ if (Field & ED_SPEED) {\r
+ Ed->Word0.Speed = Value;\r
+ }\r
+ if (Field & ED_SKIP) {\r
+ Ed->Word0.Skip = Value;\r
+ }\r
+ if (Field & ED_FORMAT) {\r
+ Ed->Word0.Format = Value;\r
+ }\r
+ if (Field & ED_MAX_PACKET) {\r
+ Ed->Word0.MaxPacketSize = Value;\r
+ }\r
+ if (Field & ED_PDATA) {\r
+ Ed->Word0.FreeSpace = Value;\r
+ }\r
+ if (Field & ED_ZERO) {\r
+ Ed->Word2.Zero = Value;\r
+ }\r
+ if (Field & ED_TDTAIL_PTR) {\r
+ Ed->TdTailPointer = Value;\r
+ }\r
+\r
+ if (Field & ED_HALTED) {\r
+ Ed->Word2.Halted = Value;\r
+ }\r
+ if (Field & ED_DTTOGGLE) {\r
+ Ed->Word2.ToggleCarry = Value;\r
+ }\r
+ if (Field & ED_TDHEAD_PTR) {\r
+ Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 (Value);\r
+ }\r
+\r
+ if (Field & ED_NEXT_EDPTR) {\r
+ Ed->NextED = Value;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Get value from an ED's specific field\r
+\r
+ @Param Ed ED pointer\r
+ @Param Field Field to get value from\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+UINT32\r
+OhciGetEDField (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN UINT32 Field\r
+ )\r
+{\r
+ switch (Field) {\r
+ case ED_FUNC_ADD:\r
+ return Ed->Word0.FunctionAddress;\r
+ break;\r
+ case ED_ENDPT_NUM:\r
+ return Ed->Word0.EndPointNum;\r
+ break;\r
+ case ED_DIR:\r
+ return Ed->Word0.Direction;\r
+ break;\r
+ case ED_SPEED:\r
+ return Ed->Word0.Speed;\r
+ break;\r
+ case ED_SKIP:\r
+ return Ed->Word0.Skip;\r
+ break;\r
+ case ED_FORMAT:\r
+ return Ed->Word0.Format;\r
+ break;\r
+ case ED_MAX_PACKET:\r
+ return Ed->Word0.MaxPacketSize;\r
+ break;\r
+\r
+ case ED_TDTAIL_PTR:\r
+ return Ed->TdTailPointer;\r
+ break;\r
+\r
+ case ED_HALTED:\r
+ return Ed->Word2.Halted;\r
+ break;\r
+\r
+ case ED_DTTOGGLE:\r
+ return Ed->Word2.ToggleCarry;\r
+ break;\r
+\r
+ case ED_TDHEAD_PTR:\r
+ return Ed->Word2.TdHeadPointer << 4;\r
+ break;\r
+\r
+ case ED_NEXT_EDPTR:\r
+ return Ed->NextED;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set value to TD specific field\r
+\r
+ @Param Td TD to be set\r
+ @Param Field Field to be set\r
+ @Param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetTDField (\r
+ IN TD_DESCRIPTOR *Td,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ if (Field & TD_PDATA) {\r
+ Td->Word0.Reserved = Value;\r
+ }\r
+ if (Field & TD_BUFFER_ROUND) {\r
+ Td->Word0.BufferRounding = Value;\r
+ }\r
+ if (Field & TD_DIR_PID) {\r
+ Td->Word0.DirPID = Value;\r
+ }\r
+ if (Field & TD_DELAY_INT) {\r
+ Td->Word0.DelayInterrupt = Value;\r
+ }\r
+ if (Field & TD_DT_TOGGLE) {\r
+ Td->Word0.DataToggle = Value | 0x2;\r
+ }\r
+ if (Field & TD_ERROR_CNT) {\r
+ Td->Word0.ErrorCount = Value;\r
+ }\r
+ if (Field & TD_COND_CODE) {\r
+ Td->Word0.ConditionCode = Value;\r
+ }\r
+\r
+ if (Field & TD_CURR_BUFFER_PTR) {\r
+ Td->CurrBufferPointer = Value;\r
+ }\r
+\r
+\r
+ if (Field & TD_NEXT_PTR) {\r
+ Td->NextTD = Value;\r
+ }\r
+\r
+ if (Field & TD_BUFFER_END_PTR) {\r
+ Td->BufferEndPointer = Value;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get value from ED specific field\r
+\r
+ @Param Td TD pointer\r
+ @Param Field Field to get value from\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetTDField (\r
+ IN TD_DESCRIPTOR *Td,\r
+ IN UINT32 Field\r
+ )\r
+{\r
+ switch (Field){\r
+ case TD_BUFFER_ROUND:\r
+ return Td->Word0.BufferRounding;\r
+ break;\r
+ case TD_DIR_PID:\r
+ return Td->Word0.DirPID;\r
+ break;\r
+ case TD_DELAY_INT:\r
+ return Td->Word0.DelayInterrupt;\r
+ break;\r
+ case TD_DT_TOGGLE:\r
+ return Td->Word0.DataToggle;\r
+ break;\r
+ case TD_ERROR_CNT:\r
+ return Td->Word0.ErrorCount;\r
+ break;\r
+ case TD_COND_CODE:\r
+ return Td->Word0.ConditionCode;\r
+ break;\r
+ case TD_CURR_BUFFER_PTR:\r
+ return Td->CurrBufferPointer;\r
+ break;\r
+\r
+ case TD_NEXT_PTR:\r
+ return Td->NextTD;\r
+ break;\r
+\r
+ case TD_BUFFER_END_PTR:\r
+ return Td->BufferEndPointer;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Free the Ed,Td,buffer that were created during transferring\r
+\r
+ @Param Ohc Device private data\r
+**/\r
+\r
+VOID\r
+OhciFreeDynamicIntMemory(\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ INTERRUPT_CONTEXT_ENTRY *Entry;\r
+ if (Ohc != NULL) {\r
+ while (Ohc->InterruptContextList != NULL) {\r
+ Entry = Ohc->InterruptContextList;\r
+ Ohc->InterruptContextList = Ohc->InterruptContextList->NextEntry;\r
+ OhciFreeInterruptEdByEd (Ohc, Entry->Ed);\r
+ OhciFreeInterruptContextEntry (Ohc, Entry);\r
+ }\r
+ }\r
+}\r
+/**\r
+\r
+ Free the Ed that were initilized during driver was starting,\r
+ those memory were used as interrupt ED head\r
+\r
+ @Param Ohc Device private data\r
+\r
+\r
+**/\r
+VOID\r
+OhciFreeFixedIntMemory (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ static UINT32 Leaf[] = {32,16,8,4,2,1};\r
+ UINTN Index;\r
+ UINTN Level;\r
+\r
+ for (Level = 0; Level < 6; Level++) {\r
+ for (Index = 0; Index < Leaf[Level]; Index++) {\r
+ if (Ohc->IntervalList[Level][Index] != NULL) {\r
+ UsbHcFreeMem(Ohc->MemPool, Ohc->IntervalList[Level][Index], sizeof(ED_DESCRIPTOR));\r
+ }\r
+ }\r
+ }\r
+}\r
+/**\r
+\r
+ Release all OHCI used memory when OHCI going to quit\r
+\r
+ @Param Ohc Device private data\r
+\r
+ @retval EFI_SUCCESS Memory released\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciFreeIntTransferMemory (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ //\r
+ // Free the Ed,Td,buffer that were created during transferring\r
+ //\r
+ OhciFreeDynamicIntMemory (Ohc);\r
+ //\r
+ // Free the Ed that were initilized during driver was starting\r
+ //\r
+ OhciFreeFixedIntMemory (Ohc);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
--- /dev/null
+/** @file\r
+Provides some data struct used by OHCI controller driver.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef _OHCI_URB_H\r
+#define _OHCI_URB_H\r
+\r
+#include "Descriptor.h"\r
+\r
+\r
+//\r
+// Func List\r
+//\r
+\r
+\r
+/**\r
+\r
+ Create a TD\r
+\r
+ @Param Ohc UHC private data\r
+\r
+ @retval TD structure pointer\r
+\r
+**/\r
+TD_DESCRIPTOR *\r
+OhciCreateTD (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ );\r
+\r
+/**\r
+\r
+ Free a TD\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Td Pointer to a TD to free\r
+\r
+ @retval EFI_SUCCESS TD freed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeTD (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN TD_DESCRIPTOR *Td\r
+ );\r
+\r
+/**\r
+\r
+ Create a ED\r
+\r
+ @Param Ohc Device private data\r
+\r
+ @retval ED descriptor pointer\r
+\r
+**/\r
+ED_DESCRIPTOR *\r
+OhciCreateED (\r
+ USB_OHCI_HC_DEV *Ohc\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Free a ED\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Ed Pointer to a ED to free\r
+\r
+ @retval EFI_SUCCESS ED freed\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciFreeED (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN ED_DESCRIPTOR *Ed\r
+ );\r
+\r
+/**\r
+\r
+ Free ED\r
+\r
+ @Param Ohc Device private data\r
+ @Param Ed Pointer to a ED to free\r
+\r
+ @retval EFI_SUCCESS ED freed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeAllTDFromED (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN ED_DESCRIPTOR *Ed\r
+ );\r
+\r
+/**\r
+\r
+ Find a working ED match the requirement\r
+\r
+ @Param EdHead Head of the ED list\r
+ @Param DeviceAddress Device address to search\r
+ @Param EndPointNum End point num to search\r
+ @Param EdDir ED Direction to search\r
+\r
+ @retval ED descriptor searched\r
+\r
+**/\r
+\r
+ED_DESCRIPTOR *\r
+OhciFindWorkingEd (\r
+ IN ED_DESCRIPTOR *EdHead,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointNum,\r
+ IN UINT8 EdDir\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Initialize interrupt list.\r
+\r
+ @Param Ohc Device private data\r
+\r
+ @retval EFI_SUCCESS Initialization done\r
+\r
+**/\r
+EFI_STATUS\r
+OhciInitializeInterruptList (\r
+ USB_OHCI_HC_DEV *Ohc\r
+ );\r
+\r
+/**\r
+\r
+ Attach an ED\r
+\r
+ @Param Ed Ed to be attached\r
+ @Param NewEd Ed to attach\r
+\r
+ @retval EFI_SUCCESS NewEd attached to Ed\r
+ @retval EFI_INVALID_PARAMETER Ed is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAttachED (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN ED_DESCRIPTOR *NewEd\r
+ );\r
+\r
+/**\r
+\r
+ Count ED number on a ED chain\r
+\r
+ @Param Ed Head of the ED chain\r
+\r
+ @retval ED number on the chain\r
+\r
+**/\r
+\r
+UINTN\r
+CountEdNum (\r
+ IN ED_DESCRIPTOR *Ed\r
+ );\r
+\r
+/**\r
+\r
+ Find the minimal burn ED list on a specific depth level\r
+\r
+ @Param Ohc Device private data\r
+ @Param Depth Depth level\r
+\r
+ @retval ED list found\r
+\r
+**/\r
+\r
+ED_DESCRIPTOR *\r
+OhciFindMinInterruptEDList (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Depth\r
+ );\r
+\r
+/**\r
+\r
+ Attach an ED to an ED list\r
+\r
+ @Param OHC UHC private data\r
+ @Param ListType Type of the ED list\r
+ @Param Ed ED to attach\r
+ @Param EdList ED list to be attached\r
+\r
+ @retval EFI_SUCCESS ED attached to ED list\r
+\r
+**/\r
+ED_DESCRIPTOR *\r
+OhciAttachEDToList (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN DESCRIPTOR_LIST_TYPE ListType,\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN ED_DESCRIPTOR *EdList\r
+ );\r
+\r
+/**\r
+\r
+ Remove interrupt EDs that match requirement\r
+\r
+ @Param Ohc UHC private data\r
+ @Param IntEd The address of Interrupt endpoint\r
+\r
+ @retval EFI_SUCCESS EDs match requirement removed\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciFreeInterruptEdByEd (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN ED_DESCRIPTOR *IntEd\r
+ );\r
+\r
+/**\r
+\r
+ Remove interrupt EDs that match requirement\r
+\r
+ @Param Ohc UHC private data\r
+ @Param FunctionAddress Requirement on function address\r
+ @Param EndPointNum Requirement on end point number\r
+\r
+ @retval EFI_SUCCESS EDs match requirement removed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeInterruptEdByAddr (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT8 FunctionAddress,\r
+ IN UINT8 EndPointNum\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Link Td2 to the end of Td1\r
+\r
+ @Param Td1 TD to be linked\r
+ @Param Td2 TD to link\r
+\r
+ @retval EFI_SUCCESS TD successfully linked\r
+ @retval EFI_INVALID_PARAMETER Td1 is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+OhciLinkTD (\r
+ IN TD_DESCRIPTOR *Td1,\r
+ IN TD_DESCRIPTOR *Td2\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Attach TD list to ED\r
+\r
+ @Param Ed ED which TD list attach on\r
+ @Param HeadTd Head of the TD list to attach\r
+\r
+ @retval EFI_SUCCESS TD list attached on the ED\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAttachTDListToED (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Set value to ED specific field\r
+\r
+ @Param Ed ED to be set\r
+ @Param Field Field to be set\r
+ @Param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetEDField (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Get value from an ED's specific field\r
+\r
+ @Param Ed ED pointer\r
+ @Param Field Field to get value from\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+UINT32\r
+OhciGetEDField (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN UINT32 Field\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Set value to TD specific field\r
+\r
+ @Param Td TD to be set\r
+ @Param Field Field to be set\r
+ @Param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetTDField (\r
+ IN TD_DESCRIPTOR *Td,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Get value from ED specific field\r
+\r
+ @Param Td TD pointer\r
+ @Param Field Field to get value from\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetTDField (\r
+ IN TD_DESCRIPTOR *Td,\r
+ IN UINT32 Field\r
+ );\r
+/**\r
+\r
+ Free the Ed,Td,buffer that were created during transferring\r
+\r
+ @Param Ohc Device private data\r
+**/\r
+\r
+VOID\r
+OhciFreeDynamicIntMemory(\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ );\r
+\r
+/**\r
+\r
+ Free the Ed that were initilized during driver was starting,\r
+ those memory were used as interrupt ED head\r
+\r
+ @Param Ohc Device private data\r
+\r
+\r
+**/\r
+VOID\r
+OhciFreeFixedIntMemory (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ );\r
+/**\r
+\r
+ Release all OHCI used memory when OHCI going to quit\r
+\r
+ @Param Ohc Device private data\r
+\r
+ @retval EFI_SUCCESS Memory released\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciFreeIntTransferMemory (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Routine procedures for memory allocate/free.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "Ohci.h"\r
+\r
+\r
+/**\r
+ Allocate a block of memory to be used by the buffer pool.\r
+\r
+ @param Pool The buffer pool to allocate memory for.\r
+ @param Pages How many pages to allocate.\r
+\r
+ @return The allocated memory block or NULL if failed.\r
+\r
+**/\r
+USBHC_MEM_BLOCK *\r
+UsbHcAllocMemBlock (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ VOID *BufHost;\r
+ VOID *Mapping;\r
+ EFI_PHYSICAL_ADDRESS MappedAddr;\r
+ UINTN Bytes;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Pool->PciIo;\r
+\r
+ Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));\r
+ if (Block == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // each bit in the bit array represents USBHC_MEM_UNIT\r
+ // bytes of memory in the memory block.\r
+ //\r
+ ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
+\r
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
+ Block->Bits = AllocateZeroPool (Block->BitsLen);\r
+\r
+ if (Block->Bits == NULL) {\r
+ gBS->FreePool (Block);\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Allocate the number of Pages of memory, then map it for\r
+ // bus master read and write.\r
+ //\r
+ Status = PciIo->AllocateBuffer (\r
+ PciIo,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ Pages,\r
+ &BufHost,\r
+ 0\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto FREE_BITARRAY;\r
+ }\r
+\r
+ Bytes = EFI_PAGES_TO_SIZE (Pages);\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ BufHost,\r
+ &Bytes,\r
+ &MappedAddr,\r
+ &Mapping\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {\r
+ goto FREE_BUFFER;\r
+ }\r
+\r
+ //\r
+ // Check whether the data structure used by the host controller\r
+ // should be restricted into the same 4G\r
+ //\r
+ if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {\r
+ PciIo->Unmap (PciIo, Mapping);\r
+ goto FREE_BUFFER;\r
+ }\r
+\r
+ Block->BufHost = BufHost;\r
+ Block->Buf = (UINT8 *) ((UINTN) MappedAddr);\r
+ Block->Mapping = Mapping;\r
+\r
+ return Block;\r
+\r
+FREE_BUFFER:\r
+ PciIo->FreeBuffer (PciIo, Pages, BufHost);\r
+\r
+FREE_BITARRAY:\r
+ gBS->FreePool (Block->Bits);\r
+ gBS->FreePool (Block);\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Free the memory block from the memory pool.\r
+\r
+ @param Pool The memory pool to free the block from.\r
+ @param Block The memory block to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMemBlock (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ ASSERT ((Pool != NULL) && (Block != NULL));\r
+\r
+ PciIo = Pool->PciIo;\r
+\r
+ //\r
+ // Unmap the common buffer then free the structures\r
+ //\r
+ PciIo->Unmap (PciIo, Block->Mapping);\r
+ PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);\r
+\r
+ gBS->FreePool (Block->Bits);\r
+ gBS->FreePool (Block);\r
+}\r
+\r
+\r
+/**\r
+ Alloc some memory from the block.\r
+\r
+ @param Block The memory block to allocate memory from.\r
+ @param Units Number of memory units to allocate.\r
+\r
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
+ the return value is NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocMemFromBlock (\r
+ IN USBHC_MEM_BLOCK *Block,\r
+ IN UINTN Units\r
+ )\r
+{\r
+ UINTN Byte;\r
+ UINT8 Bit;\r
+ UINTN StartByte;\r
+ UINT8 StartBit;\r
+ UINTN Available;\r
+ UINTN Count;\r
+\r
+ ASSERT ((Block != 0) && (Units != 0));\r
+\r
+ StartByte = 0;\r
+ StartBit = 0;\r
+ Available = 0;\r
+\r
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
+ //\r
+ // If current bit is zero, the corresponding memory unit is\r
+ // available, otherwise we need to restart our searching.\r
+ // Available counts the consective number of zero bit.\r
+ //\r
+ if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
+ Available++;\r
+\r
+ if (Available >= Units) {\r
+ break;\r
+ }\r
+\r
+ NEXT_BIT (Byte, Bit);\r
+\r
+ } else {\r
+ NEXT_BIT (Byte, Bit);\r
+\r
+ Available = 0;\r
+ StartByte = Byte;\r
+ StartBit = Bit;\r
+ }\r
+ }\r
+\r
+ if (Available < Units) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Mark the memory as allocated\r
+ //\r
+ Byte = StartByte;\r
+ Bit = StartBit;\r
+\r
+ for (Count = 0; Count < Units; Count++) {\r
+ ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | USB_HC_BIT (Bit));\r
+ NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
+}\r
+\r
+/**\r
+ Calculate the corresponding pci bus address according to the Mem parameter.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The pointer to host memory.\r
+ @param Size The size of the memory region.\r
+\r
+ @return the pci memory address\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+UsbHcGetPciAddressForHostMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Head;\r
+ USBHC_MEM_BLOCK *Block;\r
+ UINTN AllocSize;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+ UINTN Offset;\r
+\r
+ Head = Pool->Head;\r
+ AllocSize = USBHC_MEM_ROUND (Size);\r
+\r
+ if (Mem == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ //\r
+ // scan the memory block list for the memory block that\r
+ // completely contains the allocated memory.\r
+ //\r
+ if ((Block->BufHost <= (UINT8 *) Mem) && (((UINT8 *) Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ ASSERT ((Block != NULL));\r
+ //\r
+ // calculate the pci memory address for host memory address.\r
+ //\r
+ Offset = (UINT8 *)Mem - Block->BufHost;\r
+ PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN) (Block->Buf + Offset);\r
+ return PhyAddr;\r
+}\r
+\r
+\r
+/**\r
+ Insert the memory block to the pool's list of the blocks.\r
+\r
+ @param Head The head of the memory pool's block list.\r
+ @param Block The memory block to insert.\r
+\r
+**/\r
+VOID\r
+UsbHcInsertMemBlockToPool (\r
+ IN USBHC_MEM_BLOCK *Head,\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+ ASSERT ((Head != NULL) && (Block != NULL));\r
+ Block->Next = Head->Next;\r
+ Head->Next = Block;\r
+}\r
+\r
+\r
+/**\r
+ Is the memory block empty?\r
+\r
+ @param Block The memory block to check.\r
+\r
+ @retval TRUE The memory block is empty.\r
+ @retval FALSE The memory block isn't empty.\r
+\r
+**/\r
+BOOLEAN\r
+UsbHcIsMemBlockEmpty (\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < Block->BitsLen; Index++) {\r
+ if (Block->Bits[Index] != 0) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Unlink the memory block from the pool's list.\r
+\r
+ @param Head The block list head of the memory's pool.\r
+ @param BlockToUnlink The memory block to unlink.\r
+\r
+**/\r
+VOID\r
+UsbHcUnlinkMemBlock (\r
+ IN USBHC_MEM_BLOCK *Head,\r
+ IN USBHC_MEM_BLOCK *BlockToUnlink\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+\r
+ ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ if (Block->Next == BlockToUnlink) {\r
+ Block->Next = BlockToUnlink->Next;\r
+ BlockToUnlink->Next = NULL;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller.\r
+\r
+ @param PciIo The PciIo that can be used to access the host controller.\r
+ @param Check4G Whether the host controller requires allocated memory\r
+ from one 4G address space.\r
+ @param Which4G The 4G memory area each memory allocated should be from.\r
+\r
+ @retval EFI_SUCCESS The memory pool is initialized.\r
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN BOOLEAN Check4G,\r
+ IN UINT32 Which4G\r
+ )\r
+{\r
+ USBHC_MEM_POOL *Pool;\r
+\r
+ Pool = AllocatePool (sizeof (USBHC_MEM_POOL));\r
+\r
+ if (Pool == NULL) {\r
+ return Pool;\r
+ }\r
+\r
+ Pool->PciIo = PciIo;\r
+ Pool->Check4G = Check4G;\r
+ Pool->Which4G = Which4G;\r
+ Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
+\r
+ if (Pool->Head == NULL) {\r
+ gBS->FreePool (Pool);\r
+ Pool = NULL;\r
+ }\r
+\r
+ return Pool;\r
+}\r
+\r
+\r
+/**\r
+ Release the memory management pool.\r
+\r
+ @param Pool The USB memory pool to free.\r
+\r
+ @retval EFI_SUCCESS The memory pool is freed.\r
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+ IN USBHC_MEM_POOL *Pool\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+\r
+ ASSERT (Pool->Head != NULL);\r
+\r
+ //\r
+ // Unlink all the memory blocks from the pool, then free them.\r
+ // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
+ // first block.\r
+ //\r
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
+ UsbHcUnlinkMemBlock (Pool->Head, Block);\r
+ UsbHcFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ UsbHcFreeMemBlock (Pool, Pool->Head);\r
+ gBS->FreePool (Pool);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+\r
+ @param Pool The host controller's memory pool.\r
+ @param Size Size of the memory to allocate.\r
+\r
+ @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Head;\r
+ USBHC_MEM_BLOCK *Block;\r
+ USBHC_MEM_BLOCK *NewBlock;\r
+ VOID *Mem;\r
+ UINTN AllocSize;\r
+ UINTN Pages;\r
+\r
+ Mem = NULL;\r
+ AllocSize = USBHC_MEM_ROUND (Size);\r
+ Head = Pool->Head;\r
+ ASSERT (Head != NULL);\r
+\r
+ //\r
+ // First check whether current memory blocks can satisfy the allocation.\r
+ //\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Mem != NULL) {\r
+ return Mem;\r
+ }\r
+\r
+ //\r
+ // Create a new memory block if there is not enough memory\r
+ // in the pool. If the allocation size is larger than the\r
+ // default page number, just allocate a large enough memory\r
+ // block. Otherwise allocate default pages.\r
+ //\r
+ if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
+ } else {\r
+ Pages = USBHC_MEM_DEFAULT_PAGES;\r
+ }\r
+\r
+ NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
+\r
+ if (NewBlock == NULL) {\r
+ DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Add the new memory block to the pool, then allocate memory from it\r
+ //\r
+ UsbHcInsertMemBlockToPool (Head, NewBlock);\r
+ Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ }\r
+\r
+ return Mem;\r
+}\r
+\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The memory to free.\r
+ @param Size The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Head;\r
+ USBHC_MEM_BLOCK *Block;\r
+ UINT8 *ToFree;\r
+ UINTN AllocSize;\r
+ UINTN Byte;\r
+ UINTN Bit;\r
+ UINTN Count;\r
+\r
+ Head = Pool->Head;\r
+ AllocSize = USBHC_MEM_ROUND (Size);\r
+ ToFree = (UINT8 *) Mem;\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ //\r
+ // scan the memory block list for the memory block that\r
+ // completely contains the memory to free.\r
+ //\r
+ if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
+ //\r
+ // compute the start byte and bit in the bit array\r
+ //\r
+ Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;\r
+ Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;\r
+\r
+ //\r
+ // reset associated bits in bit arry\r
+ //\r
+ for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
+ ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
+ NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If Block == NULL, it means that the current memory isn't\r
+ // in the host controller's pool. This is critical because\r
+ // the caller has passed in a wrong memory point\r
+ //\r
+ ASSERT (Block != NULL);\r
+\r
+ //\r
+ // Release the current memory block if it is empty and not the head\r
+ //\r
+ if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
+ UsbHcUnlinkMemBlock (Head, Block);\r
+ UsbHcFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ return ;\r
+}\r
--- /dev/null
+/** @file\r
+This file contains the definination for host controller memory\r
+management routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _USB_HC_MEM_H_\r
+#define _USB_HC_MEM_H_\r
+\r
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))\r
+\r
+#define USB_HC_BIT_IS_SET(Data, Bit) \\r
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))\r
+\r
+#define USB_HC_HIGH_32BIT(Addr64) \\r
+ ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))\r
+\r
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;\r
+struct _USBHC_MEM_BLOCK {\r
+ UINT8 *Bits; // Bit array to record which unit is allocated\r
+ UINTN BitsLen;\r
+ UINT8 *Buf;\r
+ UINT8 *BufHost;\r
+ UINTN BufLen; // Memory size in bytes\r
+ VOID *Mapping;\r
+ USBHC_MEM_BLOCK *Next;\r
+};\r
+\r
+//\r
+// USBHC_MEM_POOL is used to manage the memory used by USB\r
+// host controller. EHCI requires the control memory and transfer\r
+// data to be on the same 4G memory.\r
+//\r
+typedef struct _USBHC_MEM_POOL {\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ BOOLEAN Check4G;\r
+ UINT32 Which4G;\r
+ USBHC_MEM_BLOCK *Head;\r
+} USBHC_MEM_POOL;\r
+\r
+//\r
+// Memory allocation unit, must be 2^n, n>4\r
+//\r
+#define USBHC_MEM_UNIT 64\r
+\r
+#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)\r
+#define USBHC_MEM_DEFAULT_PAGES 16\r
+\r
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define NEXT_BIT(Byte, Bit) \\r
+ do { \\r
+ (Bit)++; \\r
+ if ((Bit) > 7) { \\r
+ (Byte)++; \\r
+ (Bit) = 0; \\r
+ } \\r
+ } while (0)\r
+\r
+\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller.\r
+\r
+ @param PciIo The PciIo that can be used to access the host controller.\r
+ @param Check4G Whether the host controller requires allocated memory\r
+ from one 4G address space.\r
+ @param Which4G The 4G memory area each memory allocated should be from.\r
+\r
+ @retval EFI_SUCCESS The memory pool is initialized.\r
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN BOOLEAN Check4G,\r
+ IN UINT32 Which4G\r
+ );\r
+\r
+\r
+/**\r
+ Release the memory management pool.\r
+\r
+ @param Pool The USB memory pool to free.\r
+\r
+ @retval EFI_SUCCESS The memory pool is freed.\r
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+ IN USBHC_MEM_POOL *Pool\r
+ );\r
+\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+\r
+ @param Pool The host controller's memory pool.\r
+ @param Size Size of the memory to allocate.\r
+\r
+ @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ );\r
+\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The memory to free.\r
+ @param Size The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ );\r
+\r
+/**\r
+ Calculate the corresponding pci bus address according to the Mem parameter.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The pointer to host memory.\r
+ @param Size The size of the memory region.\r
+\r
+ @return the pci memory address\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+UsbHcGetPciAddressForHostMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This file contains the descriptor definination of OHCI spec\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#ifndef _DESCRIPTOR_H\r
+#define _DESCRIPTOR_H\r
+\r
+#define ED_FUNC_ADD 0x0001\r
+#define ED_ENDPT_NUM 0x0002\r
+#define ED_DIR 0x0004\r
+#define ED_SPEED 0x0008\r
+#define ED_SKIP 0x0010\r
+#define ED_FORMAT 0x0020\r
+#define ED_MAX_PACKET 0x0040\r
+#define ED_TDTAIL_PTR 0x0080\r
+#define ED_HALTED 0x0100\r
+#define ED_DTTOGGLE 0x0200\r
+#define ED_TDHEAD_PTR 0x0400\r
+#define ED_NEXT_EDPTR 0x0800\r
+#define ED_PDATA 0x1000\r
+#define ED_ZERO 0x2000\r
+\r
+#define TD_BUFFER_ROUND 0x0001\r
+#define TD_DIR_PID 0x0002\r
+#define TD_DELAY_INT 0x0004\r
+#define TD_DT_TOGGLE 0x0008\r
+#define TD_ERROR_CNT 0x0010\r
+#define TD_COND_CODE 0x0020\r
+#define TD_CURR_BUFFER_PTR 0x0040\r
+#define TD_NEXT_PTR 0x0080\r
+#define TD_BUFFER_END_PTR 0x0100\r
+#define TD_PDATA 0x0200\r
+\r
+#define ED_FROM_TD_DIR 0x0\r
+#define ED_OUT_DIR 0x1\r
+#define ED_IN_DIR 0x2\r
+#define ED_FROM_TD_ALSO_DIR 0x3\r
+\r
+#define TD_SETUP_PID 0x00\r
+#define TD_OUT_PID 0x01\r
+#define TD_IN_PID 0x02\r
+#define TD_NODATA_PID 0x03\r
+\r
+#define HI_SPEED 0\r
+#define LO_SPEED 1\r
+\r
+#define TD_NO_ERROR 0x00\r
+#define TD_CRC_ERROR 0x01\r
+#define TD_BITSTUFFING_ERROR 0x02\r
+#define TD_TOGGLE_ERROR 0x03\r
+#define TD_DEVICE_STALL 0x04\r
+#define TD_NO_RESPONSE 0x05\r
+#define TD_PIDCHK_FAIL 0x06\r
+#define TD_PID_UNEXPECTED 0x07\r
+#define TD_DATA_OVERRUN 0x08\r
+#define TD_DATA_UNDERRUN 0x09\r
+#define TD_BUFFER_OVERRUN 0x0C\r
+#define TD_BUFFER_UNDERRUN 0x0D\r
+#define TD_TOBE_PROCESSED 0x0E\r
+#define TD_TOBE_PROCESSED_2 0x0F\r
+\r
+#define TD_NO_DELAY 0x7\r
+\r
+#define TD_INT 0x1\r
+#define TD_CTL 0x2\r
+#define TD_BLK 0x3\r
+\r
+typedef struct {\r
+ UINT32 Reserved:18;\r
+ UINT32 BufferRounding:1;\r
+ UINT32 DirPID:2;\r
+ UINT32 DelayInterrupt:3;\r
+ UINT32 DataToggle:2;\r
+ UINT32 ErrorCount:2;\r
+ UINT32 ConditionCode:4;\r
+} TD_DESCRIPTOR_WORD0;\r
+\r
+typedef struct _TD_DESCRIPTOR {\r
+ TD_DESCRIPTOR_WORD0 Word0;\r
+ VOID *CurrBufferPointer;\r
+ struct _TD_DESCRIPTOR *NextTD;\r
+ VOID *BufferEndPointer;\r
+ struct _TD_DESCRIPTOR *NextTDPointer;\r
+ UINT8 *DataBuffer;\r
+ UINT32 ActualSendLength;\r
+} TD_DESCRIPTOR;\r
+\r
+typedef struct {\r
+ UINT32 FunctionAddress:7;\r
+ UINT32 EndPointNum:4;\r
+ UINT32 Direction:2;\r
+ UINT32 Speed:1;\r
+ UINT32 Skip:1;\r
+ UINT32 Format:1;\r
+ UINT32 MaxPacketSize:11;\r
+ UINT32 FreeSpace:5;\r
+} ED_DESCRIPTOR_WORD0;\r
+\r
+typedef struct {\r
+ UINT32 Halted:1;\r
+ UINT32 ToggleCarry:1;\r
+ UINT32 Zero:2;\r
+ UINT32 TdHeadPointer:28;\r
+} ED_DESCRIPTOR_WORD2;\r
+\r
+typedef struct _ED_DESCRIPTOR {\r
+ ED_DESCRIPTOR_WORD0 Word0;\r
+ TD_DESCRIPTOR *TdTailPointer;\r
+ ED_DESCRIPTOR_WORD2 Word2;\r
+ struct _ED_DESCRIPTOR *NextED;\r
+} ED_DESCRIPTOR;\r
+\r
+#define TD_PTR(p) ((TD_DESCRIPTOR *)((p) << 4))\r
+#define ED_PTR(p) ((ED_DESCRIPTOR *)((p) << 4))\r
+#define RIGHT_SHIFT_4(p) ((UINT32)(p) >> 4)\r
+\r
+typedef enum {\r
+ CONTROL_LIST,\r
+ BULK_LIST,\r
+ INTERRUPT_LIST,\r
+ ISOCHRONOUS_LIST\r
+} DESCRIPTOR_LIST_TYPE;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This file contains the implementation of Usb Hc Protocol.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "OhcPeim.h"\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress The target device address.\r
+ @param DeviceSpeed Target device speed.\r
+ @param MaximumPacketLength Maximum packet size the default control transfer\r
+ endpoint is capable of sending or receiving.\r
+ @param Request USB device request to send.\r
+ @param TransferDirection Specifies the data direction for the data stage.\r
+ @param Data Data buffer to be transmitted or received from USB device.\r
+ @param DataLength The size (in bytes) of the data buffer.\r
+ @param TimeOut Indicates the maximum timeout, in millisecond.\r
+ @param TransferResult Return the result of this control transfer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciControlTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINT8 MaxPacketLength,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ ED_DESCRIPTOR *Ed;\r
+ TD_DESCRIPTOR *HeadTd;\r
+ TD_DESCRIPTOR *SetupTd;\r
+ TD_DESCRIPTOR *DataTd;\r
+ TD_DESCRIPTOR *StatusTd;\r
+ TD_DESCRIPTOR *EmptyTd;\r
+ EFI_STATUS Status;\r
+ UINT32 DataPidDir;\r
+ UINT32 StatusPidDir;\r
+ UINTN TimeCount;\r
+ UINT32 ErrorCode;\r
+\r
+ UINTN ActualSendLength;\r
+ UINTN LeftLength;\r
+ UINT8 DataToggle;\r
+\r
+ UINTN ReqMapLength = 0;\r
+ EFI_PHYSICAL_ADDRESS ReqMapPhyAddr = 0;\r
+\r
+ UINTN DataMapLength = 0;\r
+ EFI_PHYSICAL_ADDRESS DataMapPhyAddr = 0;\r
+\r
+ HeadTd = NULL;\r
+ DataTd = NULL;\r
+\r
+ if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn &&\r
+ TransferDirection != EfiUsbNoData) ||\r
+ Request == NULL || DataLength == NULL || TransferResult == NULL ||\r
+ (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) ||\r
+ (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) ||\r
+ (DeviceSpeed != EFI_USB_SPEED_LOW && DeviceSpeed != EFI_USB_SPEED_FULL) ||\r
+ (MaxPacketLength != 8 && MaxPacketLength != 16 &&\r
+ MaxPacketLength != 32 && MaxPacketLength != 64)) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: EFI_INVALID_PARAMETER\n"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (*DataLength > MAX_BYTES_PER_TD) {\r
+ DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\n"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS(This);\r
+\r
+ if (TransferDirection == EfiUsbDataIn) {\r
+ DataPidDir = TD_IN_PID;\r
+ StatusPidDir = TD_OUT_PID;\r
+ } else {\r
+ DataPidDir = TD_OUT_PID;\r
+ StatusPidDir = TD_IN_PID;\r
+ }\r
+\r
+ OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);\r
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to disable CONTROL transfer\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
+ Ed = OhciCreateED (Ohc);\r
+ if (Ed == NULL) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ OhciSetEDField (Ed, ED_SKIP, 1);\r
+ OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
+ OhciSetEDField (Ed, ED_ENDPT_NUM, 0);\r
+ OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
+ OhciSetEDField (Ed, ED_SPEED, DeviceSpeed);\r
+ OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);\r
+ OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
+ OhciSetEDField (Ed, ED_PDATA, 0);\r
+ OhciSetEDField (Ed, ED_ZERO, 0);\r
+ OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL);\r
+ OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL);\r
+ OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL);\r
+ OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL);\r
+ //\r
+ // Setup Stage\r
+ //\r
+ if(Request != NULL) {\r
+ ReqMapLength = sizeof(EFI_USB_DEVICE_REQUEST);\r
+ ReqMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Request;\r
+ }\r
+ SetupTd = OhciCreateTD (Ohc);\r
+ if (SetupTd == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\n"));\r
+ goto FREE_ED_BUFF;\r
+ }\r
+ HeadTd = SetupTd;\r
+ OhciSetTDField (SetupTd, TD_PDATA, 0);\r
+ OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1);\r
+ OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID);\r
+ OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY);\r
+ OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2);\r
+ OhciSetTDField (SetupTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+ OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINTN)ReqMapPhyAddr);\r
+ OhciSetTDField (SetupTd, TD_NEXT_PTR, (UINT32) NULL);\r
+ OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINTN)ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1);\r
+ SetupTd->ActualSendLength = 0;\r
+ SetupTd->DataBuffer = NULL;\r
+ SetupTd->NextTDPointer = NULL;\r
+\r
+ DataMapLength = *DataLength;\r
+ if ((Data != NULL) && (DataMapLength != 0)) {\r
+ DataMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data;\r
+ }\r
+ //\r
+ //Data Stage\r
+ //\r
+ LeftLength = DataMapLength;\r
+ ActualSendLength = DataMapLength;\r
+ DataToggle = 1;\r
+ while (LeftLength > 0) {\r
+ ActualSendLength = LeftLength;\r
+ if (LeftLength > MaxPacketLength) {\r
+ ActualSendLength = MaxPacketLength;\r
+ }\r
+ DataTd = OhciCreateTD (Ohc);\r
+ if (DataTd == NULL) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Data TD buffer\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FREE_TD_BUFF;\r
+ }\r
+ OhciSetTDField (DataTd, TD_PDATA, 0);\r
+ OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
+ OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
+ OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle);\r
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+ OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr);\r
+ OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) DataMapPhyAddr + ActualSendLength - 1);\r
+ OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL);\r
+ DataTd->ActualSendLength = ActualSendLength;\r
+ DataTd->DataBuffer = (UINT8 *)(UINTN)DataMapPhyAddr;\r
+ DataTd->NextTDPointer = 0;\r
+ OhciLinkTD (HeadTd, DataTd);\r
+ DataToggle ^= 1;\r
+ DataMapPhyAddr += ActualSendLength;\r
+ LeftLength -= ActualSendLength;\r
+ }\r
+ //\r
+ // Status Stage\r
+ //\r
+ StatusTd = OhciCreateTD (Ohc);\r
+ if (StatusTd == NULL) {\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Status TD buffer\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FREE_TD_BUFF;\r
+ }\r
+ OhciSetTDField (StatusTd, TD_PDATA, 0);\r
+ OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1);\r
+ OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir);\r
+ OhciSetTDField (StatusTd, TD_DELAY_INT, 7);\r
+ OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3);\r
+ OhciSetTDField (StatusTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+ OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, (UINT32) NULL);\r
+ OhciSetTDField (StatusTd, TD_NEXT_PTR, (UINT32) NULL);\r
+ OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, (UINT32) NULL);\r
+ StatusTd->ActualSendLength = 0;\r
+ StatusTd->DataBuffer = NULL;\r
+ StatusTd->NextTDPointer = NULL;\r
+ OhciLinkTD (HeadTd, StatusTd);\r
+ //\r
+ // Empty Stage\r
+ //\r
+ EmptyTd = OhciCreateTD (Ohc);\r
+ if (EmptyTd == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Empty TD buffer\n"));\r
+ goto FREE_TD_BUFF;\r
+ }\r
+ OhciSetTDField (EmptyTd, TD_PDATA, 0);\r
+ OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);\r
+ OhciSetTDField (EmptyTd, TD_DIR_PID, 0);\r
+ OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);\r
+ //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);\r
+ EmptyTd->Word0.DataToggle = 0;\r
+ OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (EmptyTd, TD_COND_CODE, 0);\r
+ OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);\r
+ OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);\r
+ OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);\r
+ EmptyTd->ActualSendLength = 0;\r
+ EmptyTd->DataBuffer = NULL;\r
+ EmptyTd->NextTDPointer = NULL;\r
+ OhciLinkTD (HeadTd, EmptyTd);\r
+ Ed->TdTailPointer = EmptyTd;\r
+ OhciAttachTDListToED (Ed, HeadTd);\r
+ //\r
+ OhciSetEDField (Ed, ED_SKIP, 0);\r
+ MicroSecondDelay (20 * HC_1_MILLISECOND);\r
+ OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1);\r
+ OhciSetHcControl (Ohc, CONTROL_ENABLE, 1);\r
+ MicroSecondDelay (20 * HC_1_MILLISECOND);\r
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) {\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ Status = EFI_DEVICE_ERROR;\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable CONTROL transfer\n"));\r
+ goto FREE_TD_BUFF;\r
+ }\r
+ }\r
+\r
+ TimeCount = 0;\r
+ Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode);\r
+\r
+ while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ TimeCount++;\r
+ Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode);\r
+ }\r
+ //\r
+ *TransferResult = ConvertErrorCode (ErrorCode);\r
+\r
+ if (ErrorCode != TD_NO_ERROR) {\r
+ if (ErrorCode == TD_TOBE_PROCESSED) {\r
+ DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Control pipe broken\r\n"));\r
+ }\r
+\r
+ *DataLength = 0;\r
+ }\r
+\r
+ OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);\r
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ DEBUG ((EFI_D_INFO, "OhciControlTransfer: Cannot disable CONTROL_ENABLE transfer\n"));\r
+ goto FREE_TD_BUFF;\r
+ }\r
+ }\r
+\r
+FREE_TD_BUFF:\r
+ while (HeadTd) {\r
+ DataTd = HeadTd;\r
+ HeadTd = HeadTd->NextTDPointer;\r
+ UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
+ }\r
+\r
+FREE_ED_BUFF:\r
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress Target device address.\r
+ @param EndPointAddress Endpoint number and its direction in bit 7.\r
+ @param MaxiPacketLength Maximum packet size the endpoint is capable of\r
+ sending or receiving.\r
+ @param Data A pointers to the buffers of data to transmit\r
+ from or receive into.\r
+ @param DataLength The lenght of the data buffer.\r
+ @param DataToggle On input, the initial data toggle for the transfer;\r
+ On output, it is updated to to next data toggle to use of\r
+ the subsequent bulk transfer.\r
+ @param TimeOut Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+ @param TransferResult A pointer to the detailed result information of the\r
+ bulk transfer.\r
+\r
+ @retval EFI_SUCCESS The transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+ @retval EFI_TIMEOUT The transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciBulkTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaxPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ ED_DESCRIPTOR *Ed;\r
+ UINT8 EdDir;\r
+ UINT32 DataPidDir;\r
+ TD_DESCRIPTOR *HeadTd;\r
+ TD_DESCRIPTOR *DataTd;\r
+ TD_DESCRIPTOR *EmptyTd;\r
+ EFI_STATUS Status;\r
+ EFI_USB_DATA_DIRECTION TransferDirection;\r
+ UINT8 EndPointNum;\r
+ UINTN TimeCount;\r
+ UINT32 ErrorCode;\r
+\r
+ UINT8 CurrentToggle;\r
+ VOID *Mapping;\r
+ UINTN MapLength;\r
+ EFI_PHYSICAL_ADDRESS MapPyhAddr;\r
+ UINTN LeftLength;\r
+ UINTN ActualSendLength;\r
+ BOOLEAN FirstTD;\r
+\r
+ Mapping = NULL;\r
+ MapLength = 0;\r
+ MapPyhAddr = 0;\r
+ LeftLength = 0;\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL ||\r
+ *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) ||\r
+ (MaxPacketLength != 8 && MaxPacketLength != 16 &&\r
+ MaxPacketLength != 32 && MaxPacketLength != 64)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);\r
+\r
+ if ((EndPointAddress & 0x80) != 0) {\r
+ TransferDirection = EfiUsbDataIn;\r
+ EdDir = ED_IN_DIR;\r
+ DataPidDir = TD_IN_PID;\r
+ } else {\r
+ TransferDirection = EfiUsbDataOut;\r
+ EdDir = ED_OUT_DIR;\r
+ DataPidDir = TD_OUT_PID;\r
+ }\r
+\r
+ EndPointNum = (EndPointAddress & 0xF);\r
+\r
+ OhciSetHcControl (Ohc, BULK_ENABLE, 0);\r
+ if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) {\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
+\r
+ Ed = OhciCreateED (Ohc);\r
+ if (Ed == NULL) {\r
+ DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate ED buffer\r\n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ OhciSetEDField (Ed, ED_SKIP, 1);\r
+ OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
+ OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);\r
+ OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
+ OhciSetEDField (Ed, ED_SPEED, HI_SPEED);\r
+ OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);\r
+ OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
+ OhciSetEDField (Ed, ED_PDATA, 0);\r
+ OhciSetEDField (Ed, ED_ZERO, 0);\r
+ OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL);\r
+ OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL);\r
+ OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL);\r
+ OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL);\r
+\r
+ if(Data != NULL) {\r
+ MapLength = *DataLength;\r
+ MapPyhAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data;\r
+ }\r
+ //\r
+ //Data Stage\r
+ //\r
+ LeftLength = MapLength;\r
+ ActualSendLength = MapLength;\r
+ CurrentToggle = *DataToggle;\r
+ HeadTd = NULL;\r
+ FirstTD = TRUE;\r
+ while (LeftLength > 0) {\r
+ ActualSendLength = LeftLength;\r
+ if (LeftLength > MaxPacketLength) {\r
+ ActualSendLength = MaxPacketLength;\r
+ }\r
+ DataTd = OhciCreateTD (Ohc);\r
+ if (DataTd == NULL) {\r
+ DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Data TD buffer\r\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto FREE_TD_BUFF;\r
+ }\r
+ OhciSetTDField (DataTd, TD_PDATA, 0);\r
+ OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
+ OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
+ OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
+ OhciSetTDField (DataTd, TD_DT_TOGGLE, CurrentToggle);\r
+ OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
+ OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);\r
+ OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) MapPyhAddr + ActualSendLength - 1);\r
+ OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL);\r
+ DataTd->ActualSendLength = ActualSendLength;\r
+ DataTd->DataBuffer = (UINT8 *)(UINTN)MapPyhAddr;\r
+ DataTd->NextTDPointer = 0;\r
+ if (FirstTD) {\r
+ HeadTd = DataTd;\r
+ FirstTD = FALSE;\r
+ } else {\r
+ OhciLinkTD (HeadTd, DataTd);\r
+ }\r
+ CurrentToggle ^= 1;\r
+ MapPyhAddr += ActualSendLength;\r
+ LeftLength -= ActualSendLength;\r
+ }\r
+ //\r
+ // Empty Stage\r
+ //\r
+ EmptyTd = OhciCreateTD (Ohc);\r
+ if (EmptyTd == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Empty TD buffer\r\n"));\r
+ goto FREE_TD_BUFF;\r
+ }\r
+ OhciSetTDField (EmptyTd, TD_PDATA, 0);\r
+ OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);\r
+ OhciSetTDField (EmptyTd, TD_DIR_PID, 0);\r
+ OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);\r
+ //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);\r
+ EmptyTd->Word0.DataToggle = 0;\r
+ OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);\r
+ OhciSetTDField (EmptyTd, TD_COND_CODE, 0);\r
+ OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);\r
+ OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);\r
+ OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);\r
+ EmptyTd->ActualSendLength = 0;\r
+ EmptyTd->DataBuffer = NULL;\r
+ EmptyTd->NextTDPointer = NULL;\r
+ OhciLinkTD (HeadTd, EmptyTd);\r
+ Ed->TdTailPointer = EmptyTd;\r
+ OhciAttachTDListToED (Ed, HeadTd);\r
+\r
+ OhciSetEDField (Ed, ED_SKIP, 0);\r
+ OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1);\r
+ OhciSetHcControl (Ohc, BULK_ENABLE, 1);\r
+ if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) {\r
+ *TransferResult = EFI_USB_ERR_SYSTEM;\r
+ goto FREE_TD_BUFF;\r
+ }\r
+ }\r
+\r
+ TimeCount = 0;\r
+ Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode);\r
+\r
+ while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ TimeCount++;\r
+ Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode);\r
+ }\r
+\r
+ *TransferResult = ConvertErrorCode (ErrorCode);\r
+\r
+ if (ErrorCode != TD_NO_ERROR) {\r
+ if (ErrorCode == TD_TOBE_PROCESSED) {\r
+ DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n"));\r
+ }\r
+ *DataLength = 0;\r
+ }\r
+ *DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);\r
+\r
+FREE_TD_BUFF:\r
+ while (HeadTd) {\r
+ DataTd = HeadTd;\r
+ HeadTd = HeadTd->NextTDPointer;\r
+ UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
+ }\r
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
+\r
+ return Status;\r
+}\r
+/**\r
+ Retrieves the number of root hub ports.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the\r
+ PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param[out] NumOfPorts The pointer to the number of the root hub ports.\r
+\r
+ @retval EFI_SUCCESS The port number was retrieved successfully.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetRootHubNumOfPorts (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ OUT UINT8 *NumOfPorts\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ if (NumOfPorts == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);\r
+ *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Retrieves the current status of a USB root hub port.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param PortNumber The root hub port to retrieve the state from.\r
+ @param PortStatus Variable to receive the port state.\r
+\r
+ @retval EFI_SUCCESS The status of the USB root hub port specified.\r
+ by PortNumber was returned in PortStatus.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetRootHubPortStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ UINT8 NumOfPorts;\r
+\r
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);\r
+\r
+ OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);\r
+ if (PortNumber >= NumOfPorts) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ PortStatus->PortStatus = 0;\r
+ PortStatus->PortChangeStatus = 0;\r
+\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_POWER;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) {\r
+ PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;\r
+ }\r
+ if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) {\r
+ PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+ Sets a feature for the specified root hub port.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI\r
+ @param PortNumber Root hub port to set.\r
+ @param PortFeature Feature to set.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was set.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+ @retval EFI_TIMEOUT The time out occurred.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciSetRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ EFI_STATUS Status;\r
+ UINT8 NumOfPorts;\r
+ UINTN RetryTimes;\r
+\r
+ OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);\r
+ if (PortNumber >= NumOfPorts) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortPower:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ RetryTimes++;\r
+ } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 ||\r
+ OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
+ break;\r
+\r
+ case EfiUsbPortEnable:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);;\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+\r
+ case EfiUsbPortSuspend:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);;\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Clears a feature for the specified root hub port.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param PortNumber Specifies the root hub port whose feature\r
+ is requested to be cleared.\r
+ @param PortFeature Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared\r
+ for the USB root hub port specified by PortNumber.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciClearRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ )\r
+{\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ EFI_STATUS Status;\r
+ UINT8 NumOfPorts;\r
+ UINTN RetryTimes;\r
+\r
+\r
+ OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);\r
+ if (PortNumber >= NumOfPorts) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ switch (PortFeature) {\r
+ case EfiUsbPortEnable:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortSuspend:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortReset:\r
+ break;\r
+\r
+ case EfiUsbPortPower:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortConnectChange:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortResetChange:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+\r
+ case EfiUsbPortEnableChange:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortSuspendChange:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ case EfiUsbPortOverCurrentChange:\r
+ Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE);\r
+\r
+ //\r
+ // Verify the state\r
+ //\r
+ RetryTimes = 0;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ RetryTimes++;\r
+ } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 &&\r
+ RetryTimes < MAX_RETRY_TIMES);\r
+\r
+ if (RetryTimes >= MAX_RETRY_TIMES) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return Status;\r
+}\r
+/**\r
+ Provides software reset for the USB host controller.\r
+\r
+ @param This This EFI_USB_HC_PROTOCOL instance.\r
+ @param Attributes A bit mask of the reset operation to perform.\r
+\r
+ @retval EFI_SUCCESS The reset operation succeeded.\r
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.\r
+ @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is\r
+ not currently supported by the host controller.\r
+ @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUsbHC (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT16 Attributes\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Index;\r
+ UINT8 NumOfPorts;\r
+ UINT32 PowerOnGoodTime;\r
+ UINT32 Data32;\r
+ BOOLEAN Flag = FALSE;\r
+\r
+ if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Status = EFI_SUCCESS;\r
+\r
+ if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) {\r
+ MicroSecondDelay (50 * HC_1_MILLISECOND);\r
+ Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ MicroSecondDelay (50 * HC_1_MILLISECOND);\r
+ //\r
+ // Wait for host controller reset.\r
+ //\r
+ PowerOnGoodTime = 50;\r
+ do {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ Data32 = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS );\r
+ if ((Data32 & HC_RESET) == 0) {\r
+ Flag = TRUE;\r
+ break;\r
+ }\r
+ }while(PowerOnGoodTime--);\r
+ if (!Flag){\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);\r
+ if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) {\r
+ Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ MicroSecondDelay (50 * HC_1_MILLISECOND);\r
+ }\r
+ //\r
+ // Initialize host controller operational registers\r
+ //\r
+ OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778);\r
+ OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);\r
+ OhciSetPeriodicStart (Ohc, 0x2a2f);\r
+ OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x0);\r
+ OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0);\r
+ OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0);\r
+ OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1);\r
+ //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0);\r
+ //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1);\r
+\r
+ OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0);\r
+ OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff);\r
+ OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE);\r
+ OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER);\r
+ OhciGetRootHubNumOfPorts (PeiServices, &Ohc->UsbHostControllerPpi, &NumOfPorts);\r
+ for (Index = 0; Index < NumOfPorts; Index++) {\r
+ if (!EFI_ERROR (OhciSetRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortReset))) {\r
+ MicroSecondDelay (200 * HC_1_MILLISECOND);\r
+ OhciClearRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortReset);\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ OhciSetRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortEnable);\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ }\r
+ }\r
+\r
+ Ohc->MemPool = UsbHcInitMemPool(TRUE, 0);\r
+ if(Ohc->MemPool == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
+ OhciSetHcControl (Ohc, CONTROL_ENABLE | BULK_ENABLE, 1);\r
+ OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);\r
+ MicroSecondDelay (50 * HC_1_MILLISECOND);\r
+ //\r
+ // Wait till first SOF occurs, and then clear it\r
+ //\r
+ while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0);\r
+ OhciClearInterruptStatus (Ohc, START_OF_FRAME);\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+\r
+ Calls underlying OhciControlTransfer to do work. This wrapper routine required\r
+ on Quark so that USB DMA transfers do not cause an IMR violation.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress The target device address.\r
+ @param DeviceSpeed Target device speed.\r
+ @param MaximumPacketLength Maximum packet size the default control transfer\r
+ endpoint is capable of sending or receiving.\r
+ @param Request USB device request to send.\r
+ @param TransferDirection Specifies the data direction for the data stage.\r
+ @param Data Data buffer to be transmitted or received from USB device.\r
+ @param DataLength The size (in bytes) of the data buffer.\r
+ @param TimeOut Indicates the maximum timeout, in millisecond.\r
+ @param TransferResult Return the result of this control transfer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedirectOhciControlTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINT8 MaxPacketLength,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_USB_DEVICE_REQUEST *NewRequest;\r
+ VOID *NewData;\r
+ UINT8 *Alloc;\r
+\r
+ //\r
+ // Allocate memory external to IMR protected region for transfer data.\r
+ //\r
+ Status = PeiServicesAllocatePool (\r
+ sizeof(EFI_USB_DEVICE_REQUEST) + *DataLength,\r
+ (VOID **) &Alloc\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Setup pointers to transfer buffers.\r
+ //\r
+ NewRequest = (EFI_USB_DEVICE_REQUEST *) Alloc;\r
+ Alloc += sizeof(EFI_USB_DEVICE_REQUEST);\r
+ NewData = (VOID *) Alloc;\r
+\r
+ //\r
+ // Copy callers request packet into transfer request packet.\r
+ //\r
+ if (Request != NULL) {\r
+ CopyMem (NewRequest,Request,sizeof(EFI_USB_DEVICE_REQUEST));\r
+ } else {\r
+ NewRequest = NULL;\r
+ }\r
+ //\r
+ // Copy callers data into transfer data buffer.\r
+ //\r
+ if (Data != NULL) {\r
+ if (DataLength > 0) {\r
+ CopyMem (NewData,Data,*DataLength);\r
+ }\r
+ } else {\r
+ NewData = NULL;\r
+ }\r
+\r
+ //\r
+ // Call underlying OhciControlTransfer to do work.\r
+ //\r
+ Status = OhciControlTransfer (\r
+ PeiServices,\r
+ This,\r
+ DeviceAddress,\r
+ DeviceSpeed,\r
+ MaxPacketLength,\r
+ NewRequest,\r
+ TransferDirection,\r
+ NewData,\r
+ DataLength,\r
+ TimeOut,\r
+ TransferResult\r
+ );\r
+\r
+ //\r
+ // Copy transfer buffer back into callers buffer.\r
+ //\r
+ if (Data != NULL && *DataLength > 0) {\r
+ CopyMem (Data, NewData, *DataLength);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+ Calls underlying OhciBulkTransfer to do work. This wrapper routine required\r
+ on Quark so that USB DMA transfers do not cause an IMR violation.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress Target device address.\r
+ @param EndPointAddress Endpoint number and its direction in bit 7.\r
+ @param MaxiPacketLength Maximum packet size the endpoint is capable of\r
+ sending or receiving.\r
+ @param Data A pointers to the buffers of data to transmit\r
+ from or receive into.\r
+ @param DataLength The lenght of the data buffer.\r
+ @param DataToggle On input, the initial data toggle for the transfer;\r
+ On output, it is updated to to next data toggle to use of\r
+ the subsequent bulk transfer.\r
+ @param TimeOut Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+ @param TransferResult A pointer to the detailed result information of the\r
+ bulk transfer.\r
+\r
+ @retval EFI_SUCCESS The transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+ @retval EFI_TIMEOUT The transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RedirectOhciBulkTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaxPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *NewData;\r
+\r
+ //\r
+ // Allocate memory external to IMR protected region for transfer data.\r
+ //\r
+ Status = PeiServicesAllocatePool (\r
+ *DataLength,\r
+ (VOID **) &NewData\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Copy callers data into transfer buffer.\r
+ //\r
+ if (Data != NULL) {\r
+ if (DataLength > 0) {\r
+ CopyMem (NewData,Data,*DataLength);\r
+ }\r
+ } else {\r
+ NewData = NULL;\r
+ }\r
+\r
+ //\r
+ // Call underlying OhciBulkTransfer to do work.\r
+ //\r
+ Status = OhciBulkTransfer (\r
+ PeiServices,\r
+ This,\r
+ DeviceAddress,\r
+ EndPointAddress,\r
+ MaxPacketLength,\r
+ NewData,\r
+ DataLength,\r
+ DataToggle,\r
+ TimeOut,\r
+ TransferResult\r
+ );\r
+\r
+ //\r
+ // Copy transfer buffer back into callers buffer.\r
+ //\r
+ if (Data != NULL && *DataLength > 0) {\r
+ CopyMem (Data, NewData, *DataLength);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCCESS PPI successfully installed.\r
+\r
+**/\r
+EFI_STATUS\r
+OhcPeimEntry (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+\r
+ PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi;\r
+ EFI_STATUS Status;\r
+ UINT8 Index;\r
+ UINTN ControllerType;\r
+ UINTN BaseAddress;\r
+ UINTN MemPages;\r
+ USB_OHCI_HC_DEV *Ohc;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+\r
+\r
+ //\r
+ // Shadow this PEIM to run from memory\r
+ //\r
+ if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ Status = PeiServicesLocatePpi (\r
+ &gPeiUsbControllerPpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **) &ChipSetUsbControllerPpi\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Index = 0;\r
+ while (TRUE) {\r
+ Status = ChipSetUsbControllerPpi->GetUsbController (\r
+ (EFI_PEI_SERVICES **) PeiServices,\r
+ ChipSetUsbControllerPpi,\r
+ Index,\r
+ &ControllerType,\r
+ &BaseAddress\r
+ );\r
+ //\r
+ // When status is error, meant no controller is found\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ //\r
+ // This PEIM is for OHC type controller.\r
+ //\r
+ if (ControllerType != PEI_OHCI_CONTROLLER) {\r
+ Index++;\r
+ continue;\r
+ }\r
+\r
+ MemPages = sizeof (USB_OHCI_HC_DEV) / PAGESIZE + 1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ MemPages,\r
+ &TempPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "OhcPeimEntry: Fail to allocate buffer for the %dth OHCI ControllerPpi\n", Index));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE);\r
+ Ohc = (USB_OHCI_HC_DEV *) ((UINTN) TempPtr);\r
+\r
+ Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE;\r
+\r
+ Ohc->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
+\r
+ //\r
+ // Initialize Uhc's hardware\r
+ //\r
+ Status = InitializeUsbHC (\r
+ (EFI_PEI_SERVICES **)PeiServices,\r
+ Ohc,\r
+ EFI_USB_HC_RESET_GLOBAL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "OhcPeimEntry: Fail to init %dth OHCI ControllerPpi\n", Index));\r
+ return Status;\r
+ }\r
+ //\r
+ // Control & Bulk transfer services are accessed via their Redirect\r
+ // routine versions on Quark so that USB DMA transfers do not cause an\r
+ // IMR violation.\r
+ //\r
+ Ohc->UsbHostControllerPpi.ControlTransfer = RedirectOhciControlTransfer;\r
+ Ohc->UsbHostControllerPpi.BulkTransfer = RedirectOhciBulkTransfer;\r
+ Ohc->UsbHostControllerPpi.GetRootHubPortNumber = OhciGetRootHubNumOfPorts;\r
+ Ohc->UsbHostControllerPpi.GetRootHubPortStatus = OhciGetRootHubPortStatus;\r
+ Ohc->UsbHostControllerPpi.SetRootHubPortFeature = OhciSetRootHubPortFeature;\r
+ Ohc->UsbHostControllerPpi.ClearRootHubPortFeature = OhciClearRootHubPortFeature;\r
+\r
+ Ohc->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ Ohc->PpiDescriptor.Guid = &gPeiUsbHostControllerPpiGuid;\r
+ Ohc->PpiDescriptor.Ppi = &Ohc->UsbHostControllerPpi;\r
+\r
+ Status = PeiServicesInstallPpi (&Ohc->PpiDescriptor);\r
+ if (EFI_ERROR (Status)) {\r
+ Index++;\r
+ continue;\r
+ }\r
+ Index++;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+Provides the definition of Usb Hc Protocol and OHCI controller\r
+private data structure.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#ifndef _OHCI_PEIM_H\r
+#define _OHCI_PEIM_H\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/UsbController.h>\r
+#include <Ppi/UsbHostController.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/IoLib.h>\r
+\r
+typedef struct _USB_OHCI_HC_DEV USB_OHCI_HC_DEV;\r
+\r
+#include "UsbHcMem.h"\r
+#include "OhciReg.h"\r
+#include "OhciSched.h"\r
+#include "OhciUrb.h"\r
+#include "Descriptor.h"\r
+\r
+#define EFI_USB_SPEED_FULL 0x0000\r
+#define EFI_USB_SPEED_LOW 0x0001\r
+#define EFI_USB_SPEED_HIGH 0x0002\r
+\r
+#define PAGESIZE 4096\r
+\r
+#define HC_1_MICROSECOND 1\r
+#define HC_1_MILLISECOND (1000 * HC_1_MICROSECOND)\r
+#define HC_1_SECOND (1000 * HC_1_MILLISECOND)\r
+\r
+\r
+#define USB_OHCI_HC_DEV_SIGNATURE SIGNATURE_32('o','h','c','i')\r
+\r
+struct _USB_OHCI_HC_DEV {\r
+ UINTN Signature;\r
+ PEI_USB_HOST_CONTROLLER_PPI UsbHostControllerPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;\r
+ UINT32 UsbHostControllerBaseAddress;\r
+ VOID *MemPool;\r
+};\r
+\r
+#define PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS(a) CR (a, USB_OHCI_HC_DEV, UsbHostControllerPpi, USB_OHCI_HC_DEV_SIGNATURE)\r
+\r
+//\r
+// Func List\r
+//\r
+\r
+/**\r
+ Provides software reset for the USB host controller.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param Attributes A bit mask of the reset operation to perform.\r
+\r
+ @retval EFI_SUCCESS The reset operation succeeded.\r
+ @retval EFI_INVALID_PARAMETER Attributes is not valid.\r
+ @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is\r
+ not currently supported by the host controller.\r
+ @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUsbHC (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT16 Attributes\r
+ );\r
+\r
+/**\r
+ Submits control transfer to a target USB device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress The target device address.\r
+ @param DeviceSpeed Target device speed.\r
+ @param MaximumPacketLength Maximum packet size the default control transfer\r
+ endpoint is capable of sending or receiving.\r
+ @param Request USB device request to send.\r
+ @param TransferDirection Specifies the data direction for the data stage.\r
+ @param Data Data buffer to be transmitted or received from USB device.\r
+ @param DataLength The size (in bytes) of the data buffer.\r
+ @param TimeOut Indicates the maximum timeout, in millisecond.\r
+ @param TransferResult Return the result of this control transfer.\r
+\r
+ @retval EFI_SUCCESS Transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
+ @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
+ @retval EFI_TIMEOUT Transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciControlTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 DeviceSpeed,\r
+ IN UINT8 MaxPacketLength,\r
+ IN EFI_USB_DEVICE_REQUEST *Request,\r
+ IN EFI_USB_DATA_DIRECTION TransferDirection,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+/**\r
+ Submits bulk transfer to a bulk endpoint of a USB device.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param DeviceAddress Target device address.\r
+ @param EndPointAddress Endpoint number and its direction in bit 7.\r
+ @param MaxiPacketLength Maximum packet size the endpoint is capable of\r
+ sending or receiving.\r
+ @param Data A pointers to the buffers of data to transmit\r
+ from or receive into.\r
+ @param DataLength The lenght of the data buffer.\r
+ @param DataToggle On input, the initial data toggle for the transfer;\r
+ On output, it is updated to to next data toggle to use of\r
+ the subsequent bulk transfer.\r
+ @param TimeOut Indicates the maximum time, in millisecond, which the\r
+ transfer is allowed to complete.\r
+ @param TransferResult A pointer to the detailed result information of the\r
+ bulk transfer.\r
+\r
+ @retval EFI_SUCCESS The transfer was completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
+ @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
+ @retval EFI_TIMEOUT The transfer failed due to timeout.\r
+ @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciBulkTransfer (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 DeviceAddress,\r
+ IN UINT8 EndPointAddress,\r
+ IN UINT8 MaxPacketLength,\r
+ IN OUT VOID *Data,\r
+ IN OUT UINTN *DataLength,\r
+ IN OUT UINT8 *DataToggle,\r
+ IN UINTN TimeOut,\r
+ OUT UINT32 *TransferResult\r
+ );\r
+/**\r
+ Retrieves the number of root hub ports.\r
+\r
+ @param[in] PeiServices The pointer to the PEI Services Table.\r
+ @param[in] This The pointer to this instance of the\r
+ PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param[out] NumOfPorts The pointer to the number of the root hub ports.\r
+\r
+ @retval EFI_SUCCESS The port number was retrieved successfully.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetRootHubNumOfPorts (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ OUT UINT8 *NumOfPorts\r
+ );\r
+/**\r
+ Retrieves the current status of a USB root hub port.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param PortNumber The root hub port to retrieve the state from.\r
+ @param PortStatus Variable to receive the port state.\r
+\r
+ @retval EFI_SUCCESS The status of the USB root hub port specified.\r
+ by PortNumber was returned in PortStatus.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciGetRootHubPortStatus (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ OUT EFI_USB_PORT_STATUS *PortStatus\r
+ );\r
+/**\r
+\r
+ Sets a feature for the specified root hub port.\r
+\r
+ @param This A pointer to the EFI_USB_HC_PROTOCOL.\r
+ @param PortNumber Specifies the root hub port whose feature\r
+ is requested to be set.\r
+ @param PortFeature Indicates the feature selector associated\r
+ with the feature set request.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was set for the\r
+ USB root hub port specified by PortNumber.\r
+ @retval EFI_DEVICE_ERROR Set feature failed because of hardware issue\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+OhciSetRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ );\r
+/**\r
+ Clears a feature for the specified root hub port.\r
+\r
+ @param PeiServices The pointer of EFI_PEI_SERVICES.\r
+ @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
+ @param PortNumber Specifies the root hub port whose feature\r
+ is requested to be cleared.\r
+ @param PortFeature Indicates the feature selector associated with the\r
+ feature clear request.\r
+\r
+ @retval EFI_SUCCESS The feature specified by PortFeature was cleared\r
+ for the USB root hub port specified by PortNumber.\r
+ @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+OhciClearRootHubPortFeature (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
+ IN UINT8 PortNumber,\r
+ IN EFI_USB_PORT_FEATURE PortFeature\r
+ );\r
+#endif\r
--- /dev/null
+## @file\r
+# OHCI USB Host Controller PEIM\r
+#\r
+# Copyright (c) 2013-2015 Intel Corporation.\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = OhciPei\r
+ FILE_GUID = 332A0926-429B-4624-9211-A36B23DF0389\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = OhcPeimEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ Descriptor.h\r
+ OhcPeim.c\r
+ OhcPeim.h\r
+ OhciSched.c\r
+ OhciSched.h\r
+ OhciReg.c\r
+ OhciReg.h\r
+ OhciUrb.c\r
+ OhciUrb.h\r
+ UsbHcMem.c\r
+ UsbHcMem.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+ QuarkSocPkg/QuarkSocPkg.dec\r
+\r
+[LibraryClasses]\r
+ IoLib\r
+ TimerLib\r
+ BaseMemoryLib\r
+ PeimEntryPoint\r
+ PeiServicesLib\r
+\r
+[Ppis]\r
+ gPeiUsbHostControllerPpiGuid # PPI ALWAYS_PRODUCED\r
+ gPeiUsbControllerPpiGuid # PPI ALWAYS_CONSUMED\r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
--- /dev/null
+/** @file\r
+The OHCI register operation routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "OhcPeim.h"\r
+\r
+/**\r
+\r
+ Get OHCI operational reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Offset Offset of the operational reg\r
+\r
+ @retval Value of the register\r
+\r
+**/\r
+UINT32\r
+OhciGetOperationalReg (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Offset\r
+ )\r
+{\r
+\r
+ return MmioRead32 (Ohc->UsbHostControllerBaseAddress + Offset);\r
+\r
+}\r
+/**\r
+\r
+ Set OHCI operational reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Offset Offset of the operational reg\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set to the reg\r
+\r
+**/\r
+\r
+\r
+EFI_STATUS\r
+OhciSetOperationalReg (\r
+ USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 *Value\r
+ )\r
+{\r
+ MmioWrite32(Ohc->UsbHostControllerBaseAddress + Offset, *Value);\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+\r
+ Get HcRevision reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @retval Value of the register\r
+\r
+**/\r
+\r
+\r
+UINT32\r
+OhciGetHcRevision (\r
+ USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ return OhciGetOperationalReg (Ohc, HC_REVISION);\r
+}\r
+/**\r
+\r
+ Set HcReset reg value\r
+\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcReset (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcRESET Reset;\r
+\r
+ Status = EFI_SUCCESS;\r
+ *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR);\r
+\r
+ if (Field & RESET_SYSTEM_BUS) {\r
+ Reset.FSBIR = Value;\r
+ }\r
+\r
+ if (Field & RESET_HOST_CONTROLLER) {\r
+ Reset.FHR = Value;\r
+ }\r
+\r
+ if (Field & RESET_CLOCK_GENERATION) {\r
+ Reset.CGR = Value;\r
+ }\r
+\r
+ if (Field & RESET_SSE_GLOBAL) {\r
+ Reset.SSE = Value;\r
+ }\r
+\r
+ if (Field & RESET_PSPL) {\r
+ Reset.PSPL = Value;\r
+ }\r
+\r
+ if (Field & RESET_PCPL) {\r
+ Reset.PCPL = Value;\r
+ }\r
+\r
+ if (Field & RESET_SSEP1) {\r
+ Reset.SSEP1 = Value;\r
+ }\r
+\r
+ if (Field & RESET_SSEP2) {\r
+ Reset.SSEP2 = Value;\r
+ }\r
+\r
+ if (Field & RESET_SSEP3) {\r
+ Reset.SSEP3 = Value;\r
+ }\r
+\r
+ OhciSetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR, (UINT32*)&Reset);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Get specific field of HcReset reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcReset (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Field\r
+ )\r
+{\r
+ HcRESET Reset;\r
+ UINT32 Value;\r
+\r
+\r
+ *(UINT32 *) &Reset = OhciGetOperationalReg (Ohc, USBHOST_OFFSET_UHCHR);\r
+ Value = 0;\r
+\r
+ switch (Field) {\r
+ case RESET_SYSTEM_BUS:\r
+ Value = Reset.FSBIR;\r
+ break;\r
+\r
+ case RESET_HOST_CONTROLLER:\r
+ Value = Reset.FHR;\r
+ break;\r
+\r
+ case RESET_CLOCK_GENERATION:\r
+ Value = Reset.CGR;\r
+ break;\r
+\r
+ case RESET_SSE_GLOBAL:\r
+ Value = Reset.SSE;\r
+ break;\r
+\r
+ case RESET_PSPL:\r
+ Value = Reset.PSPL;\r
+ break;\r
+\r
+ case RESET_PCPL:\r
+ Value = Reset.PCPL;\r
+ break;\r
+\r
+ case RESET_SSEP1:\r
+ Value = Reset.SSEP1;\r
+ break;\r
+\r
+ case RESET_SSEP2:\r
+ Value = Reset.SSEP2;\r
+ break;\r
+\r
+ case RESET_SSEP3:\r
+ Value = Reset.SSEP3;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+\r
+ return Value;\r
+}\r
+\r
+/**\r
+\r
+ Set HcControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcCONTROL Control;\r
+\r
+\r
+\r
+ *(UINT32 *) &Control = OhciGetOperationalReg (Ohc, HC_CONTROL);\r
+\r
+ if (Field & CONTROL_BULK_RATIO) {\r
+ Control.ControlBulkRatio = Value;\r
+ }\r
+\r
+ if (Field & HC_FUNCTIONAL_STATE) {\r
+ Control.FunctionalState = Value;\r
+ }\r
+\r
+ if (Field & PERIODIC_ENABLE) {\r
+ Control.PeriodicEnable = Value;\r
+ }\r
+\r
+ if (Field & CONTROL_ENABLE) {\r
+ Control.ControlEnable = Value;\r
+ }\r
+\r
+ if (Field & ISOCHRONOUS_ENABLE) {\r
+ Control.IsochronousEnable = Value;\r
+ }\r
+\r
+ if (Field & BULK_ENABLE) {\r
+ Control.BulkEnable = Value;\r
+ }\r
+\r
+ if (Field & INTERRUPT_ROUTING) {\r
+ Control.InterruptRouting = Value;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc, HC_CONTROL, (UINT32*)&Control);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get specific field of HcControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+\r
+UINT32\r
+OhciGetHcControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcCONTROL Control;\r
+\r
+ *(UINT32 *) &Control = OhciGetOperationalReg (Ohc, HC_CONTROL);\r
+\r
+ switch (Field) {\r
+ case CONTROL_BULK_RATIO:\r
+ return Control.ControlBulkRatio;\r
+ break;\r
+ case PERIODIC_ENABLE:\r
+ return Control.PeriodicEnable;\r
+ break;\r
+ case CONTROL_ENABLE:\r
+ return Control.ControlEnable;\r
+ break;\r
+ case BULK_ENABLE:\r
+ return Control.BulkEnable;\r
+ break;\r
+ case ISOCHRONOUS_ENABLE:\r
+ return Control.IsochronousEnable;\r
+ break;\r
+ case HC_FUNCTIONAL_STATE:\r
+ return Control.FunctionalState;\r
+ break;\r
+ case INTERRUPT_ROUTING:\r
+ return Control.InterruptRouting;\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Set HcCommand reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcCommandStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcCOMMAND_STATUS CommandStatus;\r
+\r
+ ZeroMem (&CommandStatus, sizeof (HcCOMMAND_STATUS));\r
+\r
+ if(Field & HC_RESET){\r
+ CommandStatus.HcReset = Value;\r
+ }\r
+\r
+ if(Field & CONTROL_LIST_FILLED){\r
+ CommandStatus.ControlListFilled = Value;\r
+ }\r
+\r
+ if(Field & BULK_LIST_FILLED){\r
+ CommandStatus.BulkListFilled = Value;\r
+ }\r
+\r
+ if(Field & CHANGE_OWNER_REQUEST){\r
+ CommandStatus.ChangeOwnerRequest = Value;\r
+ }\r
+\r
+ if(Field & SCHEDULE_OVERRUN_COUNT){\r
+ CommandStatus.ScheduleOverrunCount = Value;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc, HC_COMMAND_STATUS, (UINT32*)&CommandStatus);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Get specific field of HcCommand reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcCommandStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcCOMMAND_STATUS CommandStatus;\r
+\r
+ *(UINT32 *) &CommandStatus = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS);\r
+\r
+ switch (Field){\r
+ case HC_RESET:\r
+ return CommandStatus.HcReset;\r
+ break;\r
+ case CONTROL_LIST_FILLED:\r
+ return CommandStatus.ControlListFilled;\r
+ break;\r
+ case BULK_LIST_FILLED:\r
+ return CommandStatus.BulkListFilled;\r
+ break;\r
+ case CHANGE_OWNER_REQUEST:\r
+ return CommandStatus.ChangeOwnerRequest;\r
+ break;\r
+ case SCHEDULE_OVERRUN_COUNT:\r
+ return CommandStatus.ScheduleOverrunCount;\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Clear specific fields of Interrupt Status\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to clear\r
+\r
+ @retval EFI_SUCCESS Fields cleared\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciClearInterruptStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcINTERRUPT_STATUS InterruptStatus;\r
+\r
+ ZeroMem (&InterruptStatus, sizeof (HcINTERRUPT_STATUS));\r
+\r
+ if(Field & SCHEDULE_OVERRUN){\r
+ InterruptStatus.SchedulingOverrun = 1;\r
+ }\r
+\r
+ if(Field & WRITEBACK_DONE_HEAD){\r
+ InterruptStatus.WriteBackDone = 1;\r
+ }\r
+ if(Field & START_OF_FRAME){\r
+ InterruptStatus.Sof = 1;\r
+ }\r
+\r
+ if(Field & RESUME_DETECT){\r
+ InterruptStatus.ResumeDetected = 1;\r
+ }\r
+\r
+ if(Field & UNRECOVERABLE_ERROR){\r
+ InterruptStatus.UnrecoverableError = 1;\r
+ }\r
+\r
+ if(Field & FRAME_NUMBER_OVERFLOW){\r
+ InterruptStatus.FrameNumOverflow = 1;\r
+ }\r
+\r
+ if(Field & ROOTHUB_STATUS_CHANGE){\r
+ InterruptStatus.RHStatusChange = 1;\r
+ }\r
+\r
+ if(Field & OWNERSHIP_CHANGE){\r
+ InterruptStatus.OwnerChange = 1;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_STATUS, (UINT32*)&InterruptStatus);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Get fields of HcInterrupt reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcInterruptStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcINTERRUPT_STATUS InterruptStatus;\r
+\r
+ *(UINT32 *) &InterruptStatus = OhciGetOperationalReg (Ohc, HC_INTERRUPT_STATUS);\r
+\r
+ switch (Field){\r
+ case SCHEDULE_OVERRUN:\r
+ return InterruptStatus.SchedulingOverrun;\r
+ break;\r
+\r
+ case WRITEBACK_DONE_HEAD:\r
+ return InterruptStatus.WriteBackDone;\r
+ break;\r
+\r
+ case START_OF_FRAME:\r
+ return InterruptStatus.Sof;\r
+ break;\r
+\r
+ case RESUME_DETECT:\r
+ return InterruptStatus.ResumeDetected;\r
+ break;\r
+\r
+ case UNRECOVERABLE_ERROR:\r
+ return InterruptStatus.UnrecoverableError;\r
+ break;\r
+\r
+ case FRAME_NUMBER_OVERFLOW:\r
+ return InterruptStatus.FrameNumOverflow;\r
+ break;\r
+\r
+ case ROOTHUB_STATUS_CHANGE:\r
+ return InterruptStatus.RHStatusChange;\r
+ break;\r
+\r
+ case OWNERSHIP_CHANGE:\r
+ return InterruptStatus.OwnerChange;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Set Interrupt Control reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param StatEnable Enable or Disable\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetInterruptControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN BOOLEAN StatEnable,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcINTERRUPT_CONTROL InterruptState;\r
+\r
+\r
+ ZeroMem (&InterruptState, sizeof (HcINTERRUPT_CONTROL));\r
+\r
+ if(Field & SCHEDULE_OVERRUN) {\r
+ InterruptState.SchedulingOverrunInt = Value;\r
+ }\r
+\r
+ if(Field & WRITEBACK_DONE_HEAD) {\r
+ InterruptState.WriteBackDoneInt = Value;\r
+ }\r
+ if(Field & START_OF_FRAME) {\r
+ InterruptState.SofInt = Value;\r
+ }\r
+\r
+ if(Field & RESUME_DETECT) {\r
+ InterruptState.ResumeDetectedInt = Value;\r
+ }\r
+\r
+ if(Field & UNRECOVERABLE_ERROR) {\r
+ InterruptState.UnrecoverableErrorInt = Value;\r
+ }\r
+\r
+ if(Field & FRAME_NUMBER_OVERFLOW) {\r
+ InterruptState.FrameNumOverflowInt = Value;\r
+ }\r
+\r
+ if(Field & ROOTHUB_STATUS_CHANGE) {\r
+ InterruptState.RHStatusChangeInt = Value;\r
+ }\r
+\r
+ if(Field & OWNERSHIP_CHANGE) {\r
+ InterruptState.OwnerChangedInt = Value;\r
+ }\r
+\r
+ if(Field & MASTER_INTERRUPT) {\r
+ InterruptState.MasterInterruptEnable = Value;\r
+ }\r
+\r
+ if (StatEnable) {\r
+ Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_ENABLE, (UINT32*)&InterruptState);\r
+ } else {\r
+ Status = OhciSetOperationalReg (Ohc, HC_INTERRUPT_DISABLE, (UINT32*)&InterruptState);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Get field of HcInterruptControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcInterruptControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcINTERRUPT_CONTROL InterruptState;\r
+\r
+ *(UINT32 *) &InterruptState = OhciGetOperationalReg (Ohc, HC_INTERRUPT_ENABLE);\r
+\r
+ switch (Field){\r
+ case SCHEDULE_OVERRUN:\r
+ return InterruptState.SchedulingOverrunInt;\r
+ break;\r
+\r
+ case WRITEBACK_DONE_HEAD:\r
+ return InterruptState.WriteBackDoneInt;\r
+ break;\r
+\r
+ case START_OF_FRAME:\r
+ return InterruptState.SofInt;\r
+ break;\r
+\r
+ case RESUME_DETECT:\r
+ return InterruptState.ResumeDetectedInt;\r
+ break;\r
+\r
+ case UNRECOVERABLE_ERROR:\r
+ return InterruptState.UnrecoverableErrorInt;\r
+ break;\r
+\r
+ case FRAME_NUMBER_OVERFLOW:\r
+ return InterruptState.FrameNumOverflowInt;\r
+ break;\r
+\r
+ case ROOTHUB_STATUS_CHANGE:\r
+ return InterruptState.RHStatusChangeInt;\r
+ break;\r
+\r
+ case OWNERSHIP_CHANGE:\r
+ return InterruptState.OwnerChangedInt;\r
+ break;\r
+\r
+ case MASTER_INTERRUPT:\r
+ return InterruptState.MasterInterruptEnable;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Set memory pointer of specific type\r
+\r
+ @param Ohc UHC private data\r
+ @param PointerType Type of the pointer to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Memory pointer set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetMemoryPointer(\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN PointerType,\r
+ IN VOID *Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Verify;\r
+\r
+ Status = OhciSetOperationalReg (Ohc, PointerType, (UINT32*)&Value);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Verify = OhciGetOperationalReg (Ohc, PointerType);\r
+\r
+ while (Verify != (UINT32) Value) {\r
+ MicroSecondDelay (HC_1_MILLISECOND);\r
+ Verify = OhciGetOperationalReg (Ohc, PointerType);\r
+ };\r
+\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Get memory pointer of specific type\r
+\r
+ @param Ohc UHC private data\r
+ @param PointerType Type of pointer\r
+\r
+ @retval Memory pointer of the specific type\r
+\r
+**/\r
+\r
+VOID *\r
+OhciGetMemoryPointer (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN PointerType\r
+ )\r
+{\r
+\r
+ return (VOID *) OhciGetOperationalReg (Ohc, PointerType);\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set Frame Interval value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameInterval (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcFRM_INTERVAL FrameInterval;\r
+\r
+\r
+ *(UINT32 *) &FrameInterval = OhciGetOperationalReg(Ohc, HC_FRM_INTERVAL);\r
+\r
+ if (Field & FRAME_INTERVAL) {\r
+ FrameInterval.FrmIntervalToggle = !FrameInterval.FrmIntervalToggle;\r
+ FrameInterval.FrameInterval = Value;\r
+ }\r
+\r
+ if (Field & FS_LARGEST_DATA_PACKET) {\r
+ FrameInterval.FSMaxDataPacket = Value;\r
+ }\r
+\r
+ if (Field & FRMINT_TOGGLE) {\r
+ FrameInterval.FrmIntervalToggle = Value;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (\r
+ Ohc,\r
+ HC_FRM_INTERVAL,\r
+ (UINT32*)&FrameInterval\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get field of frame interval reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetFrameInterval (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcFRM_INTERVAL FrameInterval;\r
+\r
+ *(UINT32 *) &FrameInterval = OhciGetOperationalReg (Ohc, HC_FRM_INTERVAL);\r
+\r
+ switch (Field){\r
+ case FRAME_INTERVAL:\r
+ return FrameInterval.FrameInterval;\r
+ break;\r
+\r
+ case FS_LARGEST_DATA_PACKET:\r
+ return FrameInterval.FSMaxDataPacket;\r
+ break;\r
+\r
+ case FRMINT_TOGGLE:\r
+ return FrameInterval.FrmIntervalToggle;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Set Frame Remaining reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameRemaining (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcFRAME_REMAINING FrameRemaining;\r
+\r
+\r
+ *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc, HC_FRM_REMAINING);\r
+\r
+ FrameRemaining.FrameRemaining = Value;\r
+ FrameRemaining.FrameRemainingToggle = !FrameRemaining.FrameRemainingToggle;\r
+\r
+ Status = OhciSetOperationalReg (Ohc, HC_FRM_REMAINING, (UINT32*)&FrameRemaining);\r
+\r
+ return Status;\r
+}\r
+/**\r
+\r
+ Get value of frame remaining reg\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of frame remaining reg\r
+\r
+**/\r
+UINT32\r
+OhciGetFrameRemaining (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+\r
+{\r
+ HcFRAME_REMAINING FrameRemaining;\r
+\r
+\r
+ *(UINT32 *) &FrameRemaining = OhciGetOperationalReg (Ohc, HC_FRM_REMAINING);\r
+\r
+ switch (Field){\r
+ case FRAME_REMAINING:\r
+ return FrameRemaining.FrameRemaining;\r
+ break;\r
+\r
+ case FRAME_REMAIN_TOGGLE:\r
+ return FrameRemaining.FrameRemainingToggle;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/**\r
+\r
+ Set frame number reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameNumber(\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = OhciSetOperationalReg (Ohc, HC_FRM_NUMBER, &Value);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+\r
+ Get frame number reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @retval Value of frame number reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetFrameNumber (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ return OhciGetOperationalReg(Ohc, HC_FRM_NUMBER);\r
+}\r
+\r
+/**\r
+\r
+ Set period start reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetPeriodicStart (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+\r
+ Status = OhciSetOperationalReg (Ohc, HC_PERIODIC_START, &Value);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get periodic start reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @param Value of periodic start reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetPeriodicStart (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ return OhciGetOperationalReg(Ohc, HC_PERIODIC_START);\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set Ls Threshold reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetLsThreshold (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+\r
+ Status = OhciSetOperationalReg (Ohc, HC_LS_THREASHOLD, &Value);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get Ls Threshold reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @retval Value of Ls Threshold reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetLsThreshold (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ return OhciGetOperationalReg(Ohc, HC_LS_THREASHOLD);\r
+}\r
+\r
+/**\r
+\r
+ Set Root Hub Descriptor reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetRootHubDescriptor (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcRH_DESC_A DescriptorA;\r
+ HcRH_DESC_B DescriptorB;\r
+\r
+\r
+ if (Field & (RH_DEV_REMOVABLE || RH_PORT_PWR_CTRL_MASK)) {\r
+ *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc, HC_RH_DESC_B);\r
+\r
+ if(Field & RH_DEV_REMOVABLE) {\r
+ DescriptorB.DeviceRemovable = Value;\r
+ }\r
+ if(Field & RH_PORT_PWR_CTRL_MASK) {\r
+ DescriptorB.PortPowerControlMask = Value;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc, HC_RH_DESC_B, (UINT32*)&DescriptorB);\r
+\r
+ return Status;\r
+ }\r
+\r
+ *(UINT32 *)&DescriptorA = OhciGetOperationalReg (Ohc, HC_RH_DESC_A);\r
+\r
+ if(Field & RH_NUM_DS_PORTS) {\r
+ DescriptorA.NumDownStrmPorts = Value;\r
+ }\r
+ if(Field & RH_NO_PSWITCH) {\r
+ DescriptorA.NoPowerSwitch = Value;\r
+ }\r
+ if(Field & RH_PSWITCH_MODE) {\r
+ DescriptorA.PowerSwitchMode = Value;\r
+ }\r
+ if(Field & RH_DEVICE_TYPE) {\r
+ DescriptorA.DeviceType = Value;\r
+ }\r
+ if(Field & RH_OC_PROT_MODE) {\r
+ DescriptorA.OverCurrentProtMode = Value;\r
+ }\r
+ if(Field & RH_NOC_PROT) {\r
+ DescriptorA.NoOverCurrentProtMode = Value;\r
+ }\r
+ if(Field & RH_NO_POTPGT) {\r
+ DescriptorA.PowerOnToPowerGoodTime = Value;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc, HC_RH_DESC_A, (UINT32*)&DescriptorA);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get Root Hub Descriptor reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetRootHubDescriptor (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcRH_DESC_A DescriptorA;\r
+ HcRH_DESC_B DescriptorB;\r
+\r
+\r
+ *(UINT32 *) &DescriptorA = OhciGetOperationalReg (Ohc, HC_RH_DESC_A);\r
+ *(UINT32 *) &DescriptorB = OhciGetOperationalReg (Ohc, HC_RH_DESC_B);\r
+\r
+ switch (Field){\r
+ case RH_DEV_REMOVABLE:\r
+ return DescriptorB.DeviceRemovable;\r
+ break;\r
+\r
+ case RH_PORT_PWR_CTRL_MASK:\r
+ return DescriptorB.PortPowerControlMask;\r
+ break;\r
+\r
+ case RH_NUM_DS_PORTS:\r
+ return DescriptorA.NumDownStrmPorts;\r
+ break;\r
+\r
+ case RH_NO_PSWITCH:\r
+ return DescriptorA.NoPowerSwitch;\r
+ break;\r
+\r
+ case RH_PSWITCH_MODE:\r
+ return DescriptorA.PowerSwitchMode;\r
+ break;\r
+\r
+ case RH_DEVICE_TYPE:\r
+ return DescriptorA.DeviceType;\r
+ break;\r
+\r
+ case RH_OC_PROT_MODE:\r
+ return DescriptorA.OverCurrentProtMode;\r
+ break;\r
+\r
+ case RH_NOC_PROT:\r
+ return DescriptorA.NoOverCurrentProtMode;\r
+ break;\r
+\r
+ case RH_NO_POTPGT:\r
+ return DescriptorA.PowerOnToPowerGoodTime;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set Root Hub Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetRootHubStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcRH_STATUS RootHubStatus;\r
+\r
+\r
+ ZeroMem (&RootHubStatus, sizeof(HcRH_STATUS));\r
+\r
+ if(Field & RH_LOCAL_PSTAT){\r
+ RootHubStatus.LocalPowerStat = 1;\r
+ }\r
+ if(Field & RH_OC_ID){\r
+ RootHubStatus.OverCurrentIndicator = 1;\r
+ }\r
+ if(Field & RH_REMOTE_WK_ENABLE){\r
+ RootHubStatus.DevRemoteWakeupEnable = 1;\r
+ }\r
+ if(Field & RH_LOCAL_PSTAT_CHANGE){\r
+ RootHubStatus.LocalPowerStatChange = 1;\r
+ }\r
+ if(Field & RH_OC_ID_CHANGE){\r
+ RootHubStatus.OverCurrentIndicatorChange = 1;\r
+ }\r
+ if(Field & RH_CLR_RMT_WK_ENABLE){\r
+ RootHubStatus.ClearRemoteWakeupEnable = 1;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc, HC_RH_STATUS, (UINT32*)&RootHubStatus);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get Root Hub Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetRootHubStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcRH_STATUS RootHubStatus;\r
+\r
+\r
+ *(UINT32 *) &RootHubStatus = OhciGetOperationalReg (Ohc, HC_RH_STATUS);\r
+\r
+ switch (Field) {\r
+ case RH_LOCAL_PSTAT:\r
+ return RootHubStatus.LocalPowerStat;\r
+ break;\r
+ case RH_OC_ID:\r
+ return RootHubStatus.OverCurrentIndicator;\r
+ break;\r
+ case RH_REMOTE_WK_ENABLE:\r
+ return RootHubStatus.DevRemoteWakeupEnable;\r
+ break;\r
+ case RH_LOCAL_PSTAT_CHANGE:\r
+ return RootHubStatus.LocalPowerStatChange;\r
+ break;\r
+ case RH_OC_ID_CHANGE:\r
+ return RootHubStatus.OverCurrentIndicatorChange;\r
+ break;\r
+ case RH_CLR_RMT_WK_ENABLE:\r
+ return RootHubStatus.ClearRemoteWakeupEnable;\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set Root Hub Port Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Index Index of the port\r
+ @param Field Field to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetRootHubPortStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Index,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ HcRHPORT_STATUS PortStatus;\r
+\r
+\r
+ ZeroMem (&PortStatus, sizeof(HcRHPORT_STATUS));\r
+\r
+ if (Field & RH_CLEAR_PORT_ENABLE) {\r
+ PortStatus.CurrentConnectStat = 1;\r
+ }\r
+ if (Field & RH_SET_PORT_ENABLE) {\r
+ PortStatus.EnableStat = 1;\r
+ }\r
+ if (Field & RH_SET_PORT_SUSPEND) {\r
+ PortStatus.SuspendStat = 1;\r
+ }\r
+ if (Field & RH_CLEAR_SUSPEND_STATUS) {\r
+ PortStatus.OCIndicator = 1;\r
+ }\r
+ if (Field & RH_SET_PORT_RESET) {\r
+ PortStatus.ResetStat = 1;\r
+ }\r
+ if (Field & RH_SET_PORT_POWER) {\r
+ PortStatus.PowerStat = 1;\r
+ }\r
+ if (Field & RH_CLEAR_PORT_POWER) {\r
+ PortStatus.LsDeviceAttached = 1;\r
+ }\r
+ if (Field & RH_CONNECT_STATUS_CHANGE) {\r
+ PortStatus.ConnectStatChange = 1;\r
+ }\r
+ if (Field & RH_PORT_ENABLE_STAT_CHANGE) {\r
+ PortStatus.EnableStatChange = 1;\r
+ }\r
+ if (Field & RH_PORT_SUSPEND_STAT_CHANGE) {\r
+ PortStatus.SuspendStatChange = 1;\r
+ }\r
+ if (Field & RH_OC_INDICATOR_CHANGE) {\r
+ PortStatus.OCIndicatorChange = 1;\r
+ }\r
+ if (Field & RH_PORT_RESET_STAT_CHANGE ) {\r
+ PortStatus.ResetStatChange = 1;\r
+ }\r
+\r
+ Status = OhciSetOperationalReg (Ohc, HC_RH_PORT_STATUS + (Index * 4), (UINT32*)&PortStatus);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get Root Hub Port Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Index Index of the port\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field and index\r
+\r
+**/\r
+\r
+UINT32\r
+OhciReadRootHubPortStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Index,\r
+ IN UINTN Field\r
+ )\r
+{\r
+ HcRHPORT_STATUS PortStatus;\r
+\r
+ *(UINT32 *) &PortStatus = OhciGetOperationalReg (\r
+ Ohc,\r
+ HC_RH_PORT_STATUS + (Index * 4)\r
+ );\r
+\r
+ switch (Field){\r
+ case RH_CURR_CONNECT_STAT:\r
+ return PortStatus.CurrentConnectStat;\r
+ break;\r
+ case RH_PORT_ENABLE_STAT:\r
+ return PortStatus.EnableStat;\r
+ break;\r
+ case RH_PORT_SUSPEND_STAT:\r
+ return PortStatus.SuspendStat;\r
+ break;\r
+ case RH_PORT_OC_INDICATOR:\r
+ return PortStatus.OCIndicator;\r
+ break;\r
+ case RH_PORT_RESET_STAT:\r
+ return PortStatus.ResetStat;\r
+ break;\r
+ case RH_PORT_POWER_STAT:\r
+ return PortStatus.PowerStat;\r
+ break;\r
+ case RH_LSDEVICE_ATTACHED:\r
+ return PortStatus.LsDeviceAttached;\r
+ break;\r
+ case RH_CONNECT_STATUS_CHANGE:\r
+ return PortStatus.ConnectStatChange;\r
+ break;\r
+ case RH_PORT_ENABLE_STAT_CHANGE:\r
+ return PortStatus.EnableStatChange;\r
+ break;\r
+ case RH_PORT_SUSPEND_STAT_CHANGE:\r
+ return PortStatus.SuspendStatChange;\r
+ break;\r
+ case RH_OC_INDICATOR_CHANGE:\r
+ return PortStatus.OCIndicatorChange;\r
+ break;\r
+ case RH_PORT_RESET_STAT_CHANGE:\r
+ return PortStatus.ResetStatChange;\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
--- /dev/null
+/** @file\r
+This file contains the definination for host controller\r
+register operation routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#ifndef _OHCI_REGS_H\r
+#define _OHCI_REGS_H\r
+\r
+#define HC_STATE_RESET 0x0\r
+#define HC_STATE_RESUME 0x1\r
+#define HC_STATE_OPERATIONAL 0x2\r
+#define HC_STATE_SUSPEND 0x3\r
+\r
+#define PERIODIC_ENABLE 0x01\r
+#define ISOCHRONOUS_ENABLE 0x02\r
+#define CONTROL_ENABLE 0x04\r
+#define BULK_ENABLE 0x08\r
+#define CONTROL_BULK_RATIO 0x10\r
+\r
+#define HC_FUNCTIONAL_STATE 0x20\r
+#define INTERRUPT_ROUTING 0x40\r
+\r
+#define HC_RESET 0x01\r
+#define CONTROL_LIST_FILLED 0x02\r
+#define BULK_LIST_FILLED 0x04\r
+#define CHANGE_OWNER_REQUEST 0x08\r
+\r
+#define SCHEDULE_OVERRUN_COUNT 0x10\r
+\r
+#define SCHEDULE_OVERRUN 0x00001\r
+#define WRITEBACK_DONE_HEAD 0x00002\r
+#define START_OF_FRAME 0x00004\r
+#define RESUME_DETECT 0x00008\r
+#define UNRECOVERABLE_ERROR 0x00010\r
+#define FRAME_NUMBER_OVERFLOW 0x00020\r
+#define ROOTHUB_STATUS_CHANGE 0x00040\r
+#define OWNERSHIP_CHANGE 0x00080\r
+\r
+#define MASTER_INTERRUPT 0x00400\r
+\r
+#define CONTROL_HEAD 0x001\r
+#define BULK_HEAD 0x002\r
+#define DONE_HEAD 0x004\r
+\r
+#define Hc_HCCA 0x001\r
+#define Hc_PERIODIC_CURRENT 0x002\r
+#define Hc_CONTOL_HEAD 0x004\r
+#define Hc_CONTROL_CURRENT_PTR 0x008\r
+#define Hc_BULK_HEAD 0x010\r
+#define Hc_BULK_CURRENT_PTR 0x020\r
+#define Hc_DONE_HEAD 0x040\r
+\r
+#define FRAME_INTERVAL 0x008\r
+#define FS_LARGEST_DATA_PACKET 0x010\r
+#define FRMINT_TOGGLE 0x020\r
+#define FRAME_REMAINING 0x040\r
+#define FRAME_REMAIN_TOGGLE 0x080\r
+\r
+#define RH_DESC_A 0x00001\r
+#define RH_DESC_B 0x00002\r
+#define RH_NUM_DS_PORTS 0x00004\r
+#define RH_NO_PSWITCH 0x00008\r
+#define RH_PSWITCH_MODE 0x00010\r
+#define RH_DEVICE_TYPE 0x00020\r
+#define RH_OC_PROT_MODE 0x00040\r
+#define RH_NOC_PROT 0x00080\r
+#define RH_POTPGT 0x00100\r
+#define RH_NO_POTPGT 0x00200\r
+#define RH_DEV_REMOVABLE 0x00400\r
+#define RH_PORT_PWR_CTRL_MASK 0x00800\r
+\r
+#define RH_LOCAL_PSTAT 0x00001\r
+#define RH_OC_ID 0x00002\r
+#define RH_REMOTE_WK_ENABLE 0x00004\r
+#define RH_LOCAL_PSTAT_CHANGE 0x00008\r
+#define RH_OC_ID_CHANGE 0x00010\r
+#define RH_CLR_RMT_WK_ENABLE 0x00020\r
+\r
+#define RH_CLEAR_PORT_ENABLE 0x0001\r
+#define RH_SET_PORT_ENABLE 0x0002\r
+#define RH_SET_PORT_SUSPEND 0x0004\r
+#define RH_CLEAR_SUSPEND_STATUS 0x0008\r
+#define RH_SET_PORT_RESET 0x0010\r
+#define RH_SET_PORT_POWER 0x0020\r
+#define RH_CLEAR_PORT_POWER 0x0040\r
+#define RH_CONNECT_STATUS_CHANGE 0x10000\r
+#define RH_PORT_ENABLE_STAT_CHANGE 0x20000\r
+#define RH_PORT_SUSPEND_STAT_CHANGE 0x40000\r
+#define RH_OC_INDICATOR_CHANGE 0x80000\r
+#define RH_PORT_RESET_STAT_CHANGE 0x100000\r
+\r
+#define RH_CURR_CONNECT_STAT 0x0001\r
+#define RH_PORT_ENABLE_STAT 0x0002\r
+#define RH_PORT_SUSPEND_STAT 0x0004\r
+#define RH_PORT_OC_INDICATOR 0x0008\r
+#define RH_PORT_RESET_STAT 0x0010\r
+#define RH_PORT_POWER_STAT 0x0020\r
+#define RH_LSDEVICE_ATTACHED 0x0040\r
+\r
+#define RESET_SYSTEM_BUS (1 << 0)\r
+#define RESET_HOST_CONTROLLER (1 << 1)\r
+#define RESET_CLOCK_GENERATION (1 << 2)\r
+#define RESET_SSE_GLOBAL (1 << 5)\r
+#define RESET_PSPL (1 << 6)\r
+#define RESET_PCPL (1 << 7)\r
+#define RESET_SSEP1 (1 << 9)\r
+#define RESET_SSEP2 (1 << 10)\r
+#define RESET_SSEP3 (1 << 11)\r
+\r
+#define ONE_SECOND 1000000\r
+#define ONE_MILLI_SEC 1000\r
+#define MAX_BYTES_PER_TD 0x1000\r
+#define MAX_RETRY_TIMES 100\r
+#define PORT_NUMBER_ON_MAINSTONE2 1\r
+\r
+\r
+//\r
+// Operational Register Offsets\r
+//\r
+\r
+//\r
+// Command & Status Registers Offsets\r
+//\r
+#define HC_REVISION 0x00\r
+#define HC_CONTROL 0x04\r
+#define HC_COMMAND_STATUS 0x08\r
+#define HC_INTERRUPT_STATUS 0x0C\r
+#define HC_INTERRUPT_ENABLE 0x10\r
+#define HC_INTERRUPT_DISABLE 0x14\r
+\r
+//\r
+// Memory Pointer Offsets\r
+//\r
+#define HC_HCCA 0x18\r
+#define HC_PERIODIC_CURRENT 0x1C\r
+#define HC_CONTROL_HEAD 0x20\r
+#define HC_CONTROL_CURRENT_PTR 0x24\r
+#define HC_BULK_HEAD 0x28\r
+#define HC_BULK_CURRENT_PTR 0x2C\r
+#define HC_DONE_HEAD 0x30\r
+\r
+//\r
+// Frame Register Offsets\r
+//\r
+#define HC_FRM_INTERVAL 0x34\r
+#define HC_FRM_REMAINING 0x38\r
+#define HC_FRM_NUMBER 0x3C\r
+#define HC_PERIODIC_START 0x40\r
+#define HC_LS_THREASHOLD 0x44\r
+\r
+//\r
+// Root Hub Register Offsets\r
+//\r
+#define HC_RH_DESC_A 0x48\r
+#define HC_RH_DESC_B 0x4C\r
+#define HC_RH_STATUS 0x50\r
+#define HC_RH_PORT_STATUS 0x54\r
+\r
+#define USBHOST_OFFSET_UHCHR 0x64 // Usb Host reset register\r
+\r
+#define OHC_BAR_INDEX 0\r
+\r
+//\r
+// Usb Host controller register offset\r
+//\r
+#define USBHOST_OFFSET_UHCREV 0x0 // Usb Host revision register\r
+#define USBHOST_OFFSET_UHCHCON 0x4 // Usb Host control register\r
+#define USBHOST_OFFSET_UHCCOMS 0x8 // Usb Host Command Status register\r
+#define USBHOST_OFFSET_UHCINTS 0xC // Usb Host Interrupt Status register\r
+#define USBHOST_OFFSET_UHCINTE 0x10 // Usb Host Interrupt Enable register\r
+#define USBHOST_OFFSET_UHCINTD 0x14 // Usb Host Interrupt Disable register\r
+#define USBHOST_OFFSET_UHCHCCA 0x18 // Usb Host Controller Communication Area\r
+#define USBHOST_OFFSET_UHCPCED 0x1C // Usb Host Period Current Endpoint Descriptor\r
+#define USBHOST_OFFSET_UHCCHED 0x20 // Usb Host Control Head Endpoint Descriptor\r
+#define USBHOST_OFFSET_UHCCCED 0x24 // Usb Host Control Current Endpoint Descriptor\r
+#define USBHOST_OFFSET_UHCBHED 0x28 // Usb Host Bulk Head Endpoint Descriptor\r
+#define USBHOST_OFFSET_UHCBCED 0x2C // Usb Host Bulk Current Endpoint Descriptor\r
+#define USBHOST_OFFSET_UHCDHEAD 0x30 // Usb Host Done Head register\r
+#define USBHOST_OFFSET_UHCFMI 0x34 // Usb Host Frame Interval register\r
+#define USBHOST_OFFSET_UHCFMR 0x38 // Usb Host Frame Remaining register\r
+#define USBHOST_OFFSET_UHCFMN 0x3C // Usb Host Frame Number register\r
+#define USBHOST_OFFSET_UHCPERS 0x40 // Usb Host Periodic Start register\r
+#define USBHOST_OFFSET_UHCLST 0x44 // Usb Host Low-Speed Threshold register\r
+#define USBHOST_OFFSET_UHCRHDA 0x48 // Usb Host Root Hub Descriptor A register\r
+#define USBHOST_OFFSET_UHCRHDB 0x4C // Usb Host Root Hub Descriptor B register\r
+#define USBHOST_OFFSET_UHCRHS 0x50 // Usb Host Root Hub Status register\r
+#define USBHOST_OFFSET_UHCRHPS1 0x54 // Usb Host Root Hub Port Status 1 register\r
+\r
+//\r
+// Usb Host controller register bit fields\r
+//\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+ UINT8 ProgInterface;\r
+ UINT8 SubClassCode;\r
+ UINT8 BaseCode;\r
+} USB_CLASSC;\r
+\r
+typedef struct {\r
+ UINT32 Revision:8;\r
+ UINT32 Rsvd:24;\r
+} HcREVISION;\r
+\r
+typedef struct {\r
+ UINT32 ControlBulkRatio:2;\r
+ UINT32 PeriodicEnable:1;\r
+ UINT32 IsochronousEnable:1;\r
+ UINT32 ControlEnable:1;\r
+ UINT32 BulkEnable:1;\r
+ UINT32 FunctionalState:2;\r
+ UINT32 InterruptRouting:1;\r
+ UINT32 RemoteWakeup:1;\r
+ UINT32 RemoteWakeupEnable:1;\r
+ UINT32 Reserved:21;\r
+} HcCONTROL;\r
+\r
+typedef struct {\r
+ UINT32 HcReset:1;\r
+ UINT32 ControlListFilled:1;\r
+ UINT32 BulkListFilled:1;\r
+ UINT32 ChangeOwnerRequest:1;\r
+ UINT32 Reserved1:12;\r
+ UINT32 ScheduleOverrunCount:2;\r
+ UINT32 Reserved:14;\r
+} HcCOMMAND_STATUS;\r
+\r
+typedef struct {\r
+ UINT32 SchedulingOverrun:1;\r
+ UINT32 WriteBackDone:1;\r
+ UINT32 Sof:1;\r
+ UINT32 ResumeDetected:1;\r
+ UINT32 UnrecoverableError:1;\r
+ UINT32 FrameNumOverflow:1;\r
+ UINT32 RHStatusChange:1;\r
+ UINT32 Reserved1:23;\r
+ UINT32 OwnerChange:1;\r
+ UINT32 Reserved2:1;\r
+} HcINTERRUPT_STATUS;\r
+\r
+typedef struct {\r
+ UINT32 SchedulingOverrunInt:1;\r
+ UINT32 WriteBackDoneInt:1;\r
+ UINT32 SofInt:1;\r
+ UINT32 ResumeDetectedInt:1;\r
+ UINT32 UnrecoverableErrorInt:1;\r
+ UINT32 FrameNumOverflowInt:1;\r
+ UINT32 RHStatusChangeInt:1;\r
+ UINT32 Reserved:23;\r
+ UINT32 OwnerChangedInt:1;\r
+ UINT32 MasterInterruptEnable:1;\r
+} HcINTERRUPT_CONTROL;\r
+\r
+typedef struct {\r
+ UINT32 Rerserved:8;\r
+ UINT32 Hcca:24;\r
+} HcHCCA;\r
+\r
+typedef struct {\r
+ UINT32 Reserved:4;\r
+ UINT32 MemoryPtr:28;\r
+} HcMEMORY_PTR;\r
+\r
+typedef struct {\r
+ UINT32 FrameInterval:14;\r
+ UINT32 Reserved:2;\r
+ UINT32 FSMaxDataPacket:15;\r
+ UINT32 FrmIntervalToggle:1;\r
+} HcFRM_INTERVAL;\r
+\r
+typedef struct {\r
+ UINT32 FrameRemaining:14;\r
+ UINT32 Reserved:17;\r
+ UINT32 FrameRemainingToggle:1;\r
+} HcFRAME_REMAINING;\r
+\r
+typedef struct {\r
+ UINT32 FrameNumber:16;\r
+ UINT32 Reserved:16;\r
+} HcFRAME_NUMBER;\r
+\r
+typedef struct {\r
+ UINT32 PeriodicStart:14;\r
+ UINT32 Reserved:18;\r
+} HcPERIODIC_START;\r
+\r
+typedef struct {\r
+ UINT32 LsThreshold:12;\r
+ UINT32 Reserved:20;\r
+} HcLS_THRESHOLD;\r
+\r
+typedef struct {\r
+ UINT32 NumDownStrmPorts:8;\r
+ UINT32 PowerSwitchMode:1;\r
+ UINT32 NoPowerSwitch:1;\r
+ UINT32 DeviceType:1;\r
+ UINT32 OverCurrentProtMode:1;\r
+ UINT32 NoOverCurrentProtMode:1;\r
+ UINT32 Reserved:11;\r
+ UINT32 PowerOnToPowerGoodTime:8;\r
+} HcRH_DESC_A;\r
+\r
+typedef struct {\r
+ UINT32 DeviceRemovable:16;\r
+ UINT32 PortPowerControlMask:16;\r
+} HcRH_DESC_B;\r
+\r
+typedef struct {\r
+ UINT32 LocalPowerStat:1;\r
+ UINT32 OverCurrentIndicator:1;\r
+ UINT32 Reserved1:13;\r
+ UINT32 DevRemoteWakeupEnable:1;\r
+ UINT32 LocalPowerStatChange:1;\r
+ UINT32 OverCurrentIndicatorChange:1;\r
+ UINT32 Reserved2:13;\r
+ UINT32 ClearRemoteWakeupEnable:1;\r
+} HcRH_STATUS;\r
+\r
+typedef struct {\r
+ UINT32 CurrentConnectStat:1;\r
+ UINT32 EnableStat:1;\r
+ UINT32 SuspendStat:1;\r
+ UINT32 OCIndicator:1;\r
+ UINT32 ResetStat:1;\r
+ UINT32 Reserved1:3;\r
+ UINT32 PowerStat:1;\r
+ UINT32 LsDeviceAttached:1;\r
+ UINT32 Reserved2:6;\r
+ UINT32 ConnectStatChange:1;\r
+ UINT32 EnableStatChange:1;\r
+ UINT32 SuspendStatChange:1;\r
+ UINT32 OCIndicatorChange:1;\r
+ UINT32 ResetStatChange:1;\r
+ UINT32 Reserved3:11;\r
+} HcRHPORT_STATUS;\r
+\r
+typedef struct {\r
+ UINT32 FSBIR:1;\r
+ UINT32 FHR:1;\r
+ UINT32 CGR:1;\r
+ UINT32 SSDC:1;\r
+ UINT32 UIT:1;\r
+ UINT32 SSE:1;\r
+ UINT32 PSPL:1;\r
+ UINT32 PCPL:1;\r
+ UINT32 Reserved0:1;\r
+ UINT32 SSEP1:1;\r
+ UINT32 SSEP2:1;\r
+ UINT32 SSEP3:1;\r
+ UINT32 Reserved1:20;\r
+} HcRESET;\r
+\r
+#pragma pack()\r
+\r
+//\r
+// Func List\r
+//\r
+/**\r
+\r
+ Get OHCI operational reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Offset Offset of the operational reg\r
+\r
+ @retval Value of the register\r
+\r
+**/\r
+UINT32\r
+OhciGetOperationalReg (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Offset\r
+ );\r
+/**\r
+\r
+ Set OHCI operational reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Offset Offset of the operational reg\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set to the reg\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetOperationalReg (\r
+ USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Offset,\r
+ IN UINT32 *Value\r
+ );\r
+/**\r
+\r
+ Get HcRevision reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @retval Value of the register\r
+\r
+**/\r
+\r
+\r
+UINT32\r
+OhciGetHcRevision (\r
+ USB_OHCI_HC_DEV *Ohc\r
+ );\r
+\r
+/**\r
+\r
+ Set HcReset reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcReset (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ );\r
+/**\r
+\r
+ Get specific field of HcReset reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcReset (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Field\r
+ );\r
+/**\r
+\r
+ Set HcControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ );\r
+/**\r
+\r
+ Get specific field of HcControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+\r
+UINT32\r
+OhciGetHcControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+/**\r
+\r
+ Set HcCommand reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetHcCommandStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ );\r
+/**\r
+\r
+ Get specific field of HcCommand reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcCommandStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+/**\r
+\r
+ Clear specific fields of Interrupt Status\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to clear\r
+\r
+ @retval EFI_SUCCESS Fields cleared\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciClearInterruptStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+/**\r
+\r
+ Get fields of HcInterrupt reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcInterruptStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+/**\r
+\r
+ Set Interrupt Control reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param StatEnable Enable or Disable\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetInterruptControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN BOOLEAN StatEnable,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ );\r
+/**\r
+\r
+ Get field of HcInterruptControl reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetHcInterruptControl (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+/**\r
+\r
+ Set memory pointer of specific type\r
+\r
+ @param Ohc UHC private data\r
+ @param PointerType Type of the pointer to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Memory pointer set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetMemoryPointer(\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN PointerType,\r
+ IN VOID *Value\r
+ );\r
+/**\r
+\r
+ Get memory pointer of specific type\r
+\r
+ @param Ohc UHC private data\r
+ @param PointerType Type of pointer\r
+\r
+ @retval Memory pointer of the specific type\r
+\r
+**/\r
+\r
+VOID *\r
+OhciGetMemoryPointer (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN PointerType\r
+ );\r
+/**\r
+\r
+ Set Frame Interval value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameInterval (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ );\r
+/**\r
+\r
+ Get field of frame interval reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetFrameInterval (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+/**\r
+\r
+ Set Frame Remaining reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameRemaining (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ );\r
+/**\r
+\r
+ Get value of frame remaining reg\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of frame remaining reg\r
+\r
+**/\r
+UINT32\r
+OhciGetFrameRemaining (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+/**\r
+\r
+ Set frame number reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetFrameNumber(\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ );\r
+/**\r
+\r
+ Get frame number reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @retval Value of frame number reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetFrameNumber (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ );\r
+/**\r
+\r
+ Set period start reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetPeriodicStart (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ );\r
+/**\r
+\r
+ Get periodic start reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @param Value of periodic start reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetPeriodicStart (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ );\r
+/**\r
+\r
+ Set Ls Threshold reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetLsThreshold (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Value\r
+ );\r
+/**\r
+\r
+ Get Ls Threshold reg value\r
+\r
+ @param Ohc UHC private data\r
+\r
+ @retval Value of Ls Threshold reg\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetLsThreshold (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ );\r
+/**\r
+\r
+ Set Root Hub Descriptor reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+ @param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetRootHubDescriptor (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field,\r
+ IN UINT32 Value\r
+ );\r
+/**\r
+\r
+ Get Root Hub Descriptor reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetRootHubDescriptor (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+/**\r
+\r
+ Set Root Hub Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetRootHubStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+/**\r
+\r
+ Get Root Hub Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetRootHubStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINTN Field\r
+ );\r
+/**\r
+\r
+ Set Root Hub Port Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Index Index of the port\r
+ @param Field Field to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciSetRootHubPortStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Index,\r
+ IN UINTN Field\r
+ );\r
+/**\r
+\r
+ Get Root Hub Port Status reg value\r
+\r
+ @param Ohc UHC private data\r
+ @param Index Index of the port\r
+ @param Field Field to get\r
+\r
+ @retval Value of the field and index\r
+\r
+**/\r
+\r
+UINT32\r
+OhciReadRootHubPortStatus (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN UINT32 Index,\r
+ IN UINTN Field\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+OHCI transfer scheduling routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "OhcPeim.h"\r
+\r
+/**\r
+\r
+ Convert Error code from OHCI format to EFI format\r
+\r
+ @Param ErrorCode ErrorCode in OHCI format\r
+\r
+ @retval ErrorCode in EFI format\r
+\r
+**/\r
+UINT32\r
+ConvertErrorCode (\r
+ IN UINT32 ErrorCode\r
+ )\r
+{\r
+ UINT32 TransferResult;\r
+\r
+ switch (ErrorCode) {\r
+ case TD_NO_ERROR:\r
+ TransferResult = EFI_USB_NOERROR;\r
+ break;\r
+\r
+ case TD_TOBE_PROCESSED:\r
+ case TD_TOBE_PROCESSED_2:\r
+ TransferResult = EFI_USB_ERR_NOTEXECUTE;\r
+ break;\r
+\r
+ case TD_DEVICE_STALL:\r
+ TransferResult = EFI_USB_ERR_STALL;\r
+ break;\r
+\r
+ case TD_BUFFER_OVERRUN:\r
+ case TD_BUFFER_UNDERRUN:\r
+ TransferResult = EFI_USB_ERR_BUFFER;\r
+ break;\r
+\r
+ case TD_CRC_ERROR:\r
+ TransferResult = EFI_USB_ERR_CRC;\r
+ break;\r
+\r
+ case TD_NO_RESPONSE:\r
+ TransferResult = EFI_USB_ERR_TIMEOUT;\r
+ break;\r
+\r
+ case TD_BITSTUFFING_ERROR:\r
+ TransferResult = EFI_USB_ERR_BITSTUFF;\r
+ break;\r
+\r
+ default:\r
+ TransferResult = EFI_USB_ERR_SYSTEM;\r
+ }\r
+\r
+ return TransferResult;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Check TDs Results\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Td TD_DESCRIPTOR\r
+ @Param Result Result to return\r
+\r
+ @retval TRUE means OK\r
+ @retval FLASE means Error or Short packet\r
+\r
+**/\r
+BOOLEAN\r
+OhciCheckTDsResults (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN TD_DESCRIPTOR *Td,\r
+ OUT UINT32 *Result\r
+ )\r
+{\r
+ UINT32 TdCompletionCode;\r
+\r
+ *Result = EFI_USB_NOERROR;\r
+\r
+ while (Td) {\r
+ TdCompletionCode = Td->Word0.ConditionCode;\r
+\r
+ *Result |= ConvertErrorCode(TdCompletionCode);\r
+ //\r
+ // if any error encountered, stop processing the left TDs.\r
+ //\r
+ if (*Result) {\r
+ return FALSE;\r
+ }\r
+\r
+ Td = Td->NextTDPointer;\r
+ }\r
+ return TRUE;\r
+\r
+}\r
+\r
+\r
+/**\r
+\r
+ Check the task status on an ED\r
+\r
+ @Param Ed Pointer to the ED task that TD hooked on\r
+ @Param HeadTd TD header for current transaction\r
+\r
+ @retval Task Status Code\r
+\r
+**/\r
+\r
+UINT32\r
+CheckEDStatus (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd\r
+ )\r
+{\r
+ while(HeadTd != NULL) {\r
+ if (HeadTd->Word0.ConditionCode != 0) {\r
+ return HeadTd->Word0.ConditionCode;\r
+ }\r
+ HeadTd = HeadTd->NextTDPointer;\r
+ }\r
+\r
+ if (OhciGetEDField (Ed, ED_TDHEAD_PTR) != OhciGetEDField (Ed, ED_TDTAIL_PTR)) {\r
+ return TD_TOBE_PROCESSED;\r
+ }\r
+\r
+ return TD_NO_ERROR;\r
+}\r
+\r
+/**\r
+\r
+ Check the task status\r
+\r
+ @Param Ohc UHC private data\r
+ @Param ListType Pipe type\r
+ @Param Ed Pointer to the ED task hooked on\r
+ @Param HeadTd Head of TD corresponding to the task\r
+ @Param ErrorCode return the ErrorCode\r
+\r
+ @retval EFI_SUCCESS Task done\r
+ @retval EFI_NOT_READY Task on processing\r
+ @retval EFI_DEVICE_ERROR Some error occured\r
+\r
+**/\r
+EFI_STATUS\r
+CheckIfDone (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN DESCRIPTOR_LIST_TYPE ListType,\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd,\r
+ OUT UINT32 *ErrorCode\r
+ )\r
+{\r
+ *ErrorCode = TD_TOBE_PROCESSED;\r
+\r
+ switch (ListType) {\r
+ case CONTROL_LIST:\r
+ if (OhciGetHcCommandStatus (Ohc, CONTROL_LIST_FILLED) != 0) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ break;\r
+\r
+ case BULK_LIST:\r
+ if (OhciGetHcCommandStatus (Ohc, BULK_LIST_FILLED) != 0) {\r
+ return EFI_NOT_READY;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ *ErrorCode = CheckEDStatus (Ed, HeadTd);\r
+\r
+\r
+ if (*ErrorCode == TD_NO_ERROR) {\r
+ return EFI_SUCCESS;\r
+ } else if (*ErrorCode == TD_TOBE_PROCESSED) {\r
+ return EFI_NOT_READY;\r
+ } else {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+\r
+ Convert TD condition code to Efi Status\r
+\r
+ @Param ConditionCode Condition code to convert\r
+\r
+ @retval EFI_SUCCESS No error occured\r
+ @retval EFI_NOT_READY TD still on processing\r
+ @retval EFI_DEVICE_ERROR Error occured in processing TD\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciTDConditionCodeToStatus (\r
+ IN UINT32 ConditionCode\r
+ )\r
+{\r
+ if (ConditionCode == TD_NO_ERROR) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (ConditionCode == TD_TOBE_PROCESSED) {\r
+ return EFI_NOT_READY;\r
+ }\r
+\r
+ return EFI_DEVICE_ERROR;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+This file contains the definination for host controller schedule routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#ifndef _OHCI_SCHED_H\r
+#define _OHCI_SCHED_H\r
+\r
+#include "Descriptor.h"\r
+\r
+#define HCCA_MEM_SIZE 256\r
+#define GRID_SIZE 16\r
+#define GRID_SHIFT 4\r
+\r
+/**\r
+\r
+ Convert Error code from OHCI format to EFI format\r
+\r
+ @Param ErrorCode ErrorCode in OHCI format\r
+\r
+ @retval ErrorCode in EFI format\r
+\r
+**/\r
+UINT32\r
+ConvertErrorCode (\r
+ IN UINT32 ErrorCode\r
+ );\r
+/**\r
+\r
+ Check TDs Results\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Td TD_DESCRIPTOR\r
+ @Param Result Result to return\r
+\r
+ @retval TRUE means OK\r
+ @retval FLASE means Error or Short packet\r
+\r
+**/\r
+BOOLEAN\r
+OhciCheckTDsResults (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN TD_DESCRIPTOR *Td,\r
+ OUT UINT32 *Result\r
+ );\r
+/**\r
+\r
+ Check the task status on an ED\r
+\r
+ @Param Ed Pointer to the ED task that TD hooked on\r
+ @Param HeadTd TD header for current transaction\r
+\r
+ @retval Task Status Code\r
+\r
+**/\r
+\r
+UINT32\r
+CheckEDStatus (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd\r
+ );\r
+/**\r
+\r
+ Check the task status\r
+\r
+ @Param Ohc UHC private data\r
+ @Param ListType Pipe type\r
+ @Param Ed Pointer to the ED task hooked on\r
+ @Param HeadTd Head of TD corresponding to the task\r
+ @Param ErrorCode return the ErrorCode\r
+\r
+ @retval EFI_SUCCESS Task done\r
+ @retval EFI_NOT_READY Task on processing\r
+ @retval EFI_DEVICE_ERROR Some error occured\r
+\r
+**/\r
+EFI_STATUS\r
+CheckIfDone (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN DESCRIPTOR_LIST_TYPE ListType,\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd,\r
+ OUT UINT32 *ErrorCode\r
+ );\r
+/**\r
+\r
+ Convert TD condition code to Efi Status\r
+\r
+ @Param ConditionCode Condition code to convert\r
+\r
+ @retval EFI_SUCCESS No error occured\r
+ @retval EFI_NOT_READY TD still on processing\r
+ @retval EFI_DEVICE_ERROR Error occured in processing TD\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciTDConditionCodeToStatus (\r
+ IN UINT32 ConditionCode\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+This file contains URB request, each request is warpped in a\r
+URB (Usb Request Block).\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#include "OhcPeim.h"\r
+\r
+\r
+/**\r
+\r
+ Create a TD\r
+\r
+ @Param Ohc UHC private data\r
+\r
+ @retval TD structure pointer\r
+\r
+**/\r
+TD_DESCRIPTOR *\r
+OhciCreateTD (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ TD_DESCRIPTOR *Td;\r
+\r
+ Td = UsbHcAllocateMem(Ohc->MemPool, sizeof(TD_DESCRIPTOR));\r
+ if (Td == NULL) {\r
+ return NULL;\r
+ }\r
+ Td->CurrBufferPointer = NULL;\r
+ Td->NextTD = NULL;\r
+ Td->BufferEndPointer = NULL;\r
+ Td->NextTDPointer = NULL;\r
+\r
+ return Td;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Free a TD\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Td Pointer to a TD to free\r
+\r
+ @retval EFI_SUCCESS TD freed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeTD (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN TD_DESCRIPTOR *Td\r
+ )\r
+{\r
+ if (Td == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Create a ED\r
+\r
+ @Param Ohc Device private data\r
+\r
+ @retval ED descriptor pointer\r
+\r
+**/\r
+ED_DESCRIPTOR *\r
+OhciCreateED (\r
+ USB_OHCI_HC_DEV *Ohc\r
+ )\r
+{\r
+ ED_DESCRIPTOR *Ed;\r
+ Ed = UsbHcAllocateMem(Ohc->MemPool, sizeof (ED_DESCRIPTOR));\r
+ if (Ed == NULL) {\r
+ return NULL;\r
+ }\r
+ Ed->Word0.Skip = 1;\r
+ Ed->TdTailPointer = NULL;\r
+ Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32) NULL);\r
+ Ed->NextED = NULL;\r
+\r
+ return Ed;\r
+}\r
+\r
+/**\r
+\r
+ Free a ED\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Ed Pointer to a ED to free\r
+\r
+ @retval EFI_SUCCESS ED freed\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciFreeED (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN ED_DESCRIPTOR *Ed\r
+ )\r
+{\r
+ if (Ed == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Free ED\r
+\r
+ @Param Ohc Device private data\r
+ @Param Ed Pointer to a ED to free\r
+\r
+ @retval EFI_SUCCESS ED freed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeAllTDFromED (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN ED_DESCRIPTOR *Ed\r
+ )\r
+{\r
+ TD_DESCRIPTOR *HeadTd;\r
+ TD_DESCRIPTOR *TailTd;\r
+ TD_DESCRIPTOR *Td;\r
+ TD_DESCRIPTOR *TempTd;\r
+\r
+ if (Ed == NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ HeadTd = TD_PTR (Ed->Word2.TdHeadPointer);\r
+ TailTd = Ed->TdTailPointer;\r
+\r
+ Td = HeadTd;\r
+ while (Td != TailTd) {\r
+ TempTd = Td;\r
+ Td = Td->NextTDPointer;\r
+ OhciFreeTD (Ohc, TempTd);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Attach an ED\r
+\r
+ @Param Ed Ed to be attached\r
+ @Param NewEd Ed to attach\r
+\r
+ @retval EFI_SUCCESS NewEd attached to Ed\r
+ @retval EFI_INVALID_PARAMETER Ed is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAttachED (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN ED_DESCRIPTOR *NewEd\r
+ )\r
+{\r
+ ED_DESCRIPTOR *Temp;\r
+\r
+ if (Ed == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Ed->NextED == NULL){\r
+ Ed->NextED = NewEd;\r
+ } else {\r
+ Temp = Ed->NextED;\r
+ Ed->NextED = NewEd;\r
+ NewEd->NextED = Temp;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+\r
+ Attach an ED to an ED list\r
+\r
+ @Param OHC UHC private data\r
+ @Param ListType Type of the ED list\r
+ @Param Ed ED to attach\r
+ @Param EdList ED list to be attached\r
+\r
+ @retval EFI_SUCCESS ED attached to ED list\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAttachEDToList (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN DESCRIPTOR_LIST_TYPE ListType,\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN ED_DESCRIPTOR *EdList\r
+ )\r
+{\r
+ ED_DESCRIPTOR *HeadEd;\r
+\r
+ switch(ListType) {\r
+ case CONTROL_LIST:\r
+ HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_CONTROL_HEAD);\r
+ if (HeadEd == NULL) {\r
+ OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, Ed);\r
+ } else {\r
+ OhciAttachED (HeadEd, Ed);\r
+ }\r
+ break;\r
+\r
+ case BULK_LIST:\r
+ HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_BULK_HEAD);\r
+ if (HeadEd == NULL) {\r
+ OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, Ed);\r
+ } else {\r
+ OhciAttachED (HeadEd, Ed);\r
+ }\r
+ break;\r
+\r
+ case INTERRUPT_LIST:\r
+ OhciAttachED (EdList, Ed);\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+/**\r
+\r
+ Link Td2 to the end of Td1\r
+\r
+ @Param Td1 TD to be linked\r
+ @Param Td2 TD to link\r
+\r
+ @retval EFI_SUCCESS TD successfully linked\r
+ @retval EFI_INVALID_PARAMETER Td1 is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+OhciLinkTD (\r
+ IN TD_DESCRIPTOR *Td1,\r
+ IN TD_DESCRIPTOR *Td2\r
+ )\r
+{\r
+ TD_DESCRIPTOR *TempTd;\r
+\r
+ if (Td1 == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Td1 == Td2) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ TempTd = Td1;\r
+ while (TempTd->NextTD != NULL) {\r
+ TempTd = TempTd->NextTD;\r
+ }\r
+\r
+ TempTd->NextTD = Td2;\r
+ TempTd->NextTDPointer = Td2;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Attach TD list to ED\r
+\r
+ @Param Ed ED which TD list attach on\r
+ @Param HeadTd Head of the TD list to attach\r
+\r
+ @retval EFI_SUCCESS TD list attached on the ED\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAttachTDListToED (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd\r
+ )\r
+{\r
+ TD_DESCRIPTOR *TempTd;\r
+\r
+ TempTd = TD_PTR (Ed->Word2.TdHeadPointer);\r
+\r
+ if (TempTd != NULL) {\r
+ while (TempTd->NextTD != NULL) {\r
+ TempTd = TempTd->NextTD;\r
+ }\r
+ TempTd->NextTD = HeadTd;\r
+ TempTd->NextTDPointer = HeadTd;\r
+ } else {\r
+ Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32) HeadTd);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set value to ED specific field\r
+\r
+ @Param Ed ED to be set\r
+ @Param Field Field to be set\r
+ @Param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetEDField (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ if (Field & ED_FUNC_ADD) {\r
+ Ed->Word0.FunctionAddress = Value;\r
+ }\r
+ if (Field & ED_ENDPT_NUM) {\r
+ Ed->Word0.EndPointNum = Value;\r
+ }\r
+ if (Field & ED_DIR) {\r
+ Ed->Word0.Direction = Value;\r
+ }\r
+ if (Field & ED_SPEED) {\r
+ Ed->Word0.Speed = Value;\r
+ }\r
+ if (Field & ED_SKIP) {\r
+ Ed->Word0.Skip = Value;\r
+ }\r
+ if (Field & ED_FORMAT) {\r
+ Ed->Word0.Format = Value;\r
+ }\r
+ if (Field & ED_MAX_PACKET) {\r
+ Ed->Word0.MaxPacketSize = Value;\r
+ }\r
+ if (Field & ED_PDATA) {\r
+ Ed->Word0.FreeSpace = Value;\r
+ }\r
+ if (Field & ED_ZERO) {\r
+ Ed->Word2.Zero = Value;\r
+ }\r
+ if (Field & ED_TDTAIL_PTR) {\r
+ Ed->TdTailPointer = (VOID *) Value;\r
+ }\r
+\r
+ if (Field & ED_HALTED) {\r
+ Ed->Word2.Halted = Value;\r
+ }\r
+ if (Field & ED_DTTOGGLE) {\r
+ Ed->Word2.ToggleCarry = Value;\r
+ }\r
+ if (Field & ED_TDHEAD_PTR) {\r
+ Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 (Value);\r
+ }\r
+\r
+ if (Field & ED_NEXT_EDPTR) {\r
+ Ed->NextED = (VOID *) Value;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+ Get value from an ED's specific field\r
+\r
+ @Param Ed ED pointer\r
+ @Param Field Field to get value from\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+UINT32\r
+OhciGetEDField (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN UINT32 Field\r
+ )\r
+{\r
+ switch (Field) {\r
+ case ED_FUNC_ADD:\r
+ return Ed->Word0.FunctionAddress;\r
+ break;\r
+ case ED_ENDPT_NUM:\r
+ return Ed->Word0.EndPointNum;\r
+ break;\r
+ case ED_DIR:\r
+ return Ed->Word0.Direction;\r
+ break;\r
+ case ED_SPEED:\r
+ return Ed->Word0.Speed;\r
+ break;\r
+ case ED_SKIP:\r
+ return Ed->Word0.Skip;\r
+ break;\r
+ case ED_FORMAT:\r
+ return Ed->Word0.Format;\r
+ break;\r
+ case ED_MAX_PACKET:\r
+ return Ed->Word0.MaxPacketSize;\r
+ break;\r
+\r
+ case ED_TDTAIL_PTR:\r
+ return (UINT32) Ed->TdTailPointer;\r
+ break;\r
+\r
+ case ED_HALTED:\r
+ return Ed->Word2.Halted;\r
+ break;\r
+\r
+ case ED_DTTOGGLE:\r
+ return Ed->Word2.ToggleCarry;\r
+ break;\r
+\r
+ case ED_TDHEAD_PTR:\r
+ return Ed->Word2.TdHeadPointer << 4;\r
+ break;\r
+\r
+ case ED_NEXT_EDPTR:\r
+ return (UINT32) Ed->NextED;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Set value to TD specific field\r
+\r
+ @Param Td TD to be set\r
+ @Param Field Field to be set\r
+ @Param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetTDField (\r
+ IN TD_DESCRIPTOR *Td,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ if (Field & TD_PDATA) {\r
+ Td->Word0.Reserved = Value;\r
+ }\r
+ if (Field & TD_BUFFER_ROUND) {\r
+ Td->Word0.BufferRounding = Value;\r
+ }\r
+ if (Field & TD_DIR_PID) {\r
+ Td->Word0.DirPID = Value;\r
+ }\r
+ if (Field & TD_DELAY_INT) {\r
+ Td->Word0.DelayInterrupt = Value;\r
+ }\r
+ if (Field & TD_DT_TOGGLE) {\r
+ Td->Word0.DataToggle = Value | 0x2;\r
+ }\r
+ if (Field & TD_ERROR_CNT) {\r
+ Td->Word0.ErrorCount = Value;\r
+ }\r
+ if (Field & TD_COND_CODE) {\r
+ Td->Word0.ConditionCode = Value;\r
+ }\r
+\r
+ if (Field & TD_CURR_BUFFER_PTR) {\r
+ Td->CurrBufferPointer = (VOID *) Value;\r
+ }\r
+\r
+\r
+ if (Field & TD_NEXT_PTR) {\r
+ Td->NextTD = (VOID *) Value;\r
+ }\r
+\r
+ if (Field & TD_BUFFER_END_PTR) {\r
+ Td->BufferEndPointer = (VOID *) Value;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+ Get value from ED specific field\r
+\r
+ @Param Td TD pointer\r
+ @Param Field Field to get value from\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetTDField (\r
+ IN TD_DESCRIPTOR *Td,\r
+ IN UINT32 Field\r
+ )\r
+{\r
+ switch (Field){\r
+ case TD_BUFFER_ROUND:\r
+ return Td->Word0.BufferRounding;\r
+ break;\r
+ case TD_DIR_PID:\r
+ return Td->Word0.DirPID;\r
+ break;\r
+ case TD_DELAY_INT:\r
+ return Td->Word0.DelayInterrupt;\r
+ break;\r
+ case TD_DT_TOGGLE:\r
+ return Td->Word0.DataToggle;\r
+ break;\r
+ case TD_ERROR_CNT:\r
+ return Td->Word0.ErrorCount;\r
+ break;\r
+ case TD_COND_CODE:\r
+ return Td->Word0.ConditionCode;\r
+ break;\r
+ case TD_CURR_BUFFER_PTR:\r
+ return (UINT32) Td->CurrBufferPointer;\r
+ break;\r
+\r
+ case TD_NEXT_PTR:\r
+ return (UINT32) Td->NextTD;\r
+ break;\r
+\r
+ case TD_BUFFER_END_PTR:\r
+ return (UINT32) Td->BufferEndPointer;\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+\r
+ return 0;\r
+}\r
--- /dev/null
+/** @file\r
+Provides some data struct used by OHCI controller driver.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#ifndef _OHCI_URB_H\r
+#define _OHCI_URB_H\r
+\r
+#include "Descriptor.h"\r
+\r
+\r
+//\r
+// Func List\r
+//\r
+\r
+\r
+/**\r
+\r
+ Create a TD\r
+\r
+ @Param Ohc UHC private data\r
+\r
+ @retval TD structure pointer\r
+\r
+**/\r
+TD_DESCRIPTOR *\r
+OhciCreateTD (\r
+ IN USB_OHCI_HC_DEV *Ohc\r
+ );\r
+\r
+/**\r
+\r
+ Free a TD\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Td Pointer to a TD to free\r
+\r
+ @retval EFI_SUCCESS TD freed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeTD (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN TD_DESCRIPTOR *Td\r
+ );\r
+\r
+/**\r
+\r
+ Create a ED\r
+\r
+ @Param Ohc Device private data\r
+\r
+ @retval ED descriptor pointer\r
+\r
+**/\r
+ED_DESCRIPTOR *\r
+OhciCreateED (\r
+ USB_OHCI_HC_DEV *Ohc\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Free a ED\r
+\r
+ @Param Ohc UHC private data\r
+ @Param Ed Pointer to a ED to free\r
+\r
+ @retval EFI_SUCCESS ED freed\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+OhciFreeED (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN ED_DESCRIPTOR *Ed\r
+ );\r
+\r
+/**\r
+\r
+ Free ED\r
+\r
+ @Param Ohc Device private data\r
+ @Param Ed Pointer to a ED to free\r
+\r
+ @retval EFI_SUCCESS ED freed\r
+\r
+**/\r
+EFI_STATUS\r
+OhciFreeAllTDFromED (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN ED_DESCRIPTOR *Ed\r
+ );\r
+\r
+/**\r
+\r
+ Attach an ED\r
+\r
+ @Param Ed Ed to be attached\r
+ @Param NewEd Ed to attach\r
+\r
+ @retval EFI_SUCCESS NewEd attached to Ed\r
+ @retval EFI_INVALID_PARAMETER Ed is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAttachED (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN ED_DESCRIPTOR *NewEd\r
+ );\r
+/**\r
+\r
+ Attach an ED to an ED list\r
+\r
+ @Param OHC UHC private data\r
+ @Param ListType Type of the ED list\r
+ @Param Ed ED to attach\r
+ @Param EdList ED list to be attached\r
+\r
+ @retval EFI_SUCCESS ED attached to ED list\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAttachEDToList (\r
+ IN USB_OHCI_HC_DEV *Ohc,\r
+ IN DESCRIPTOR_LIST_TYPE ListType,\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN ED_DESCRIPTOR *EdList\r
+ );\r
+EFI_STATUS\r
+OhciLinkTD (\r
+ IN TD_DESCRIPTOR *Td1,\r
+ IN TD_DESCRIPTOR *Td2\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Attach TD list to ED\r
+\r
+ @Param Ed ED which TD list attach on\r
+ @Param HeadTd Head of the TD list to attach\r
+\r
+ @retval EFI_SUCCESS TD list attached on the ED\r
+\r
+**/\r
+EFI_STATUS\r
+OhciAttachTDListToED (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN TD_DESCRIPTOR *HeadTd\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Set value to ED specific field\r
+\r
+ @Param Ed ED to be set\r
+ @Param Field Field to be set\r
+ @Param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetEDField (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Get value from an ED's specific field\r
+\r
+ @Param Ed ED pointer\r
+ @Param Field Field to get value from\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+UINT32\r
+OhciGetEDField (\r
+ IN ED_DESCRIPTOR *Ed,\r
+ IN UINT32 Field\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Set value to TD specific field\r
+\r
+ @Param Td TD to be set\r
+ @Param Field Field to be set\r
+ @Param Value Value to set\r
+\r
+ @retval EFI_SUCCESS Value set\r
+\r
+**/\r
+EFI_STATUS\r
+OhciSetTDField (\r
+ IN TD_DESCRIPTOR *Td,\r
+ IN UINT32 Field,\r
+ IN UINT32 Value\r
+ );\r
+\r
+\r
+/**\r
+\r
+ Get value from ED specific field\r
+\r
+ @Param Td TD pointer\r
+ @Param Field Field to get value from\r
+\r
+ @retval Value of the field\r
+\r
+**/\r
+\r
+UINT32\r
+OhciGetTDField (\r
+ IN TD_DESCRIPTOR *Td,\r
+ IN UINT32 Field\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+Routine procedures for memory allocate/free.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "OhcPeim.h"\r
+\r
+\r
+/**\r
+ Allocate a block of memory to be used by the buffer pool.\r
+\r
+ Use Redirect memory services to allocate memmory so that USB DMA transfers do\r
+ not cause IMR violations on Quark.\r
+\r
+ @param Pool The buffer pool to allocate memory for.\r
+ @param Pages How many pages to allocate.\r
+\r
+ @return The allocated memory block or NULL if failed.\r
+\r
+**/\r
+USBHC_MEM_BLOCK *\r
+UsbHcAllocMemBlock (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Pages\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+ VOID *BufHost;\r
+ VOID *Mapping;\r
+ EFI_PHYSICAL_ADDRESS MappedAddr;\r
+ EFI_STATUS Status;\r
+ UINTN PageNumber;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+\r
+ Mapping = NULL;\r
+ PageNumber = sizeof(USBHC_MEM_BLOCK)/PAGESIZE +1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ PageNumber,\r
+ &TempPtr\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);\r
+\r
+ //\r
+ // each bit in the bit array represents USBHC_MEM_UNIT\r
+ // bytes of memory in the memory block.\r
+ //\r
+ ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
+\r
+ Block = (USBHC_MEM_BLOCK*)(UINTN)TempPtr;\r
+ Block->BufLen = EFI_PAGES_TO_SIZE (Pages);\r
+ Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);\r
+\r
+ PageNumber = (Block->BitsLen)/PAGESIZE +1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ PageNumber,\r
+ &TempPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);\r
+\r
+ Block->Bits = (UINT8 *)(UINTN)TempPtr;\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ Pages,\r
+ &TempPtr\r
+ );\r
+ ZeroMem ((VOID *)(UINTN)TempPtr, Pages*EFI_PAGE_SIZE);\r
+\r
+ BufHost = (VOID *)(UINTN)TempPtr;\r
+ MappedAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) BufHost;\r
+ //\r
+ // Check whether the data structure used by the host controller\r
+ // should be restricted into the same 4G\r
+ //\r
+ if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {\r
+ return NULL;\r
+ }\r
+\r
+ Block->BufHost = BufHost;\r
+ Block->Buf = (UINT8 *) ((UINTN) MappedAddr);\r
+ Block->Mapping = Mapping;\r
+ Block->Next = NULL;\r
+\r
+ return Block;\r
+\r
+}\r
+\r
+\r
+/**\r
+ Free the memory block from the memory pool.\r
+\r
+ @param Pool The memory pool to free the block from.\r
+ @param Block The memory block to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMemBlock (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+\r
+ ASSERT ((Pool != NULL) && (Block != NULL));\r
+}\r
+\r
+\r
+/**\r
+ Alloc some memory from the block.\r
+\r
+ @param Block The memory block to allocate memory from.\r
+ @param Units Number of memory units to allocate.\r
+\r
+ @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
+ the return value is NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocMemFromBlock (\r
+ IN USBHC_MEM_BLOCK *Block,\r
+ IN UINTN Units\r
+ )\r
+{\r
+ UINTN Byte;\r
+ UINT8 Bit;\r
+ UINTN StartByte;\r
+ UINT8 StartBit;\r
+ UINTN Available;\r
+ UINTN Count;\r
+\r
+ ASSERT ((Block != 0) && (Units != 0));\r
+\r
+ StartByte = 0;\r
+ StartBit = 0;\r
+ Available = 0;\r
+\r
+ for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
+ //\r
+ // If current bit is zero, the corresponding memory unit is\r
+ // available, otherwise we need to restart our searching.\r
+ // Available counts the consective number of zero bit.\r
+ //\r
+ if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
+ Available++;\r
+\r
+ if (Available >= Units) {\r
+ break;\r
+ }\r
+\r
+ NEXT_BIT (Byte, Bit);\r
+\r
+ } else {\r
+ NEXT_BIT (Byte, Bit);\r
+\r
+ Available = 0;\r
+ StartByte = Byte;\r
+ StartBit = Bit;\r
+ }\r
+ }\r
+\r
+ if (Available < Units) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Mark the memory as allocated\r
+ //\r
+ Byte = StartByte;\r
+ Bit = StartBit;\r
+\r
+ for (Count = 0; Count < Units; Count++) {\r
+ ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));\r
+ NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;\r
+}\r
+\r
+/**\r
+ Insert the memory block to the pool's list of the blocks.\r
+\r
+ @param Head The head of the memory pool's block list.\r
+ @param Block The memory block to insert.\r
+\r
+**/\r
+VOID\r
+UsbHcInsertMemBlockToPool (\r
+ IN USBHC_MEM_BLOCK *Head,\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+ ASSERT ((Head != NULL) && (Block != NULL));\r
+ Block->Next = Head->Next;\r
+ Head->Next = Block;\r
+}\r
+\r
+\r
+/**\r
+ Is the memory block empty?\r
+\r
+ @param Block The memory block to check.\r
+\r
+ @retval TRUE The memory block is empty.\r
+ @retval FALSE The memory block isn't empty.\r
+\r
+**/\r
+BOOLEAN\r
+UsbHcIsMemBlockEmpty (\r
+ IN USBHC_MEM_BLOCK *Block\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; Index < Block->BitsLen; Index++) {\r
+ if (Block->Bits[Index] != 0) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+/**\r
+ Unlink the memory block from the pool's list.\r
+\r
+ @param Head The block list head of the memory's pool.\r
+ @param BlockToUnlink The memory block to unlink.\r
+\r
+**/\r
+VOID\r
+UsbHcUnlinkMemBlock (\r
+ IN USBHC_MEM_BLOCK *Head,\r
+ IN USBHC_MEM_BLOCK *BlockToUnlink\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+\r
+ ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ if (Block->Next == BlockToUnlink) {\r
+ Block->Next = BlockToUnlink->Next;\r
+ BlockToUnlink->Next = NULL;\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller.\r
+\r
+ @param PciIo The PciIo that can be used to access the host controller.\r
+ @param Check4G Whether the host controller requires allocated memory\r
+ from one 4G address space.\r
+ @param Which4G The 4G memory area each memory allocated should be from.\r
+\r
+ @retval EFI_SUCCESS The memory pool is initialized.\r
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+ IN BOOLEAN Check4G,\r
+ IN UINT32 Which4G\r
+ )\r
+{\r
+ USBHC_MEM_POOL *Pool;\r
+ UINTN PageNumber;\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS TempPtr;\r
+\r
+ PageNumber = sizeof(USBHC_MEM_POOL)/PAGESIZE +1;\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ PageNumber,\r
+ &TempPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+ ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);\r
+\r
+ Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr);\r
+ Pool->Check4G = Check4G;\r
+ Pool->Which4G = Which4G;\r
+ Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);\r
+\r
+ if (Pool->Head == NULL) {\r
+ Pool = NULL;\r
+ }\r
+\r
+ return Pool;\r
+}\r
+\r
+\r
+/**\r
+ Release the memory management pool.\r
+\r
+ @param Pool The USB memory pool to free.\r
+\r
+ @retval EFI_SUCCESS The memory pool is freed.\r
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+ IN USBHC_MEM_POOL *Pool\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Block;\r
+\r
+ ASSERT (Pool->Head != NULL);\r
+\r
+ //\r
+ // Unlink all the memory blocks from the pool, then free them.\r
+ // UsbHcUnlinkMemBlock can't be used to unlink and free the\r
+ // first block.\r
+ //\r
+ for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
+ UsbHcFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ UsbHcFreeMemBlock (Pool, Pool->Head);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+\r
+ @param Pool The host controller's memory pool.\r
+ @param Size Size of the memory to allocate.\r
+\r
+ @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Head;\r
+ USBHC_MEM_BLOCK *Block;\r
+ USBHC_MEM_BLOCK *NewBlock;\r
+ VOID *Mem;\r
+ UINTN AllocSize;\r
+ UINTN Pages;\r
+\r
+ Mem = NULL;\r
+ AllocSize = USBHC_MEM_ROUND (Size);\r
+ Head = Pool->Head;\r
+ ASSERT (Head != NULL);\r
+\r
+ //\r
+ // First check whether current memory blocks can satisfy the allocation.\r
+ //\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Mem != NULL) {\r
+ return Mem;\r
+ }\r
+\r
+ //\r
+ // Create a new memory block if there is not enough memory\r
+ // in the pool. If the allocation size is larger than the\r
+ // default page number, just allocate a large enough memory\r
+ // block. Otherwise allocate default pages.\r
+ //\r
+ if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {\r
+ Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
+ } else {\r
+ Pages = USBHC_MEM_DEFAULT_PAGES;\r
+ }\r
+\r
+ NewBlock = UsbHcAllocMemBlock (Pool, Pages);\r
+\r
+ if (NewBlock == NULL) {\r
+ DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Add the new memory block to the pool, then allocate memory from it\r
+ //\r
+ UsbHcInsertMemBlockToPool (Head, NewBlock);\r
+ Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);\r
+\r
+ if (Mem != NULL) {\r
+ ZeroMem (Mem, Size);\r
+ }\r
+\r
+ return Mem;\r
+}\r
+\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The memory to free.\r
+ @param Size The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ USBHC_MEM_BLOCK *Head;\r
+ USBHC_MEM_BLOCK *Block;\r
+ UINT8 *ToFree;\r
+ UINTN AllocSize;\r
+ UINTN Byte;\r
+ UINTN Bit;\r
+ UINTN Count;\r
+\r
+ Head = Pool->Head;\r
+ AllocSize = USBHC_MEM_ROUND (Size);\r
+ ToFree = (UINT8 *) Mem;\r
+\r
+ for (Block = Head; Block != NULL; Block = Block->Next) {\r
+ //\r
+ // scan the memory block list for the memory block that\r
+ // completely contains the memory to free.\r
+ //\r
+ if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {\r
+ //\r
+ // compute the start byte and bit in the bit array\r
+ //\r
+ Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;\r
+ Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;\r
+\r
+ //\r
+ // reset associated bits in bit arry\r
+ //\r
+ for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {\r
+ ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+ Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));\r
+ NEXT_BIT (Byte, Bit);\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If Block == NULL, it means that the current memory isn't\r
+ // in the host controller's pool. This is critical because\r
+ // the caller has passed in a wrong memory point\r
+ //\r
+ ASSERT (Block != NULL);\r
+\r
+ //\r
+ // Release the current memory block if it is empty and not the head\r
+ //\r
+ if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {\r
+ UsbHcFreeMemBlock (Pool, Block);\r
+ }\r
+\r
+ return ;\r
+}\r
--- /dev/null
+/** @file\r
+This file contains the definination for host controller memory\r
+management routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _USB_HC_MEM_H_\r
+#define _USB_HC_MEM_H_\r
+\r
+#define USB_HC_BIT(a) ((UINTN)(1 << (a)))\r
+\r
+#define USB_HC_BIT_IS_SET(Data, Bit) \\r
+ ((BOOLEAN)(((Data) & USB_HC_BIT(Bit)) == USB_HC_BIT(Bit)))\r
+\r
+#define USB_HC_HIGH_32BIT(Addr64) \\r
+ ((UINT32)(RShiftU64((UINTN)(Addr64), 32) & 0XFFFFFFFF))\r
+\r
+typedef struct _USBHC_MEM_BLOCK USBHC_MEM_BLOCK;\r
+struct _USBHC_MEM_BLOCK {\r
+ UINT8 *Bits; // Bit array to record which unit is allocated\r
+ UINTN BitsLen;\r
+ UINT8 *Buf;\r
+ UINT8 *BufHost;\r
+ UINTN BufLen; // Memory size in bytes\r
+ VOID *Mapping;\r
+ USBHC_MEM_BLOCK *Next;\r
+};\r
+\r
+//\r
+// USBHC_MEM_POOL is used to manage the memory used by USB\r
+// host controller. EHCI requires the control memory and transfer\r
+// data to be on the same 4G memory.\r
+//\r
+typedef struct _USBHC_MEM_POOL {\r
+ BOOLEAN Check4G;\r
+ UINT32 Which4G;\r
+ USBHC_MEM_BLOCK *Head;\r
+} USBHC_MEM_POOL;\r
+\r
+//\r
+// Memory allocation unit, must be 2^n, n>4\r
+//\r
+#define USBHC_MEM_UNIT 64\r
+\r
+#define USBHC_MEM_UNIT_MASK (USBHC_MEM_UNIT - 1)\r
+#define USBHC_MEM_DEFAULT_PAGES 16\r
+\r
+#define USBHC_MEM_ROUND(Len) (((Len) + USBHC_MEM_UNIT_MASK) & (~USBHC_MEM_UNIT_MASK))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define NEXT_BIT(Byte, Bit) \\r
+ do { \\r
+ (Bit)++; \\r
+ if ((Bit) > 7) { \\r
+ (Byte)++; \\r
+ (Bit) = 0; \\r
+ } \\r
+ } while (0)\r
+\r
+\r
+\r
+/**\r
+ Initialize the memory management pool for the host controller.\r
+\r
+ @param PciIo The PciIo that can be used to access the host controller.\r
+ @param Check4G Whether the host controller requires allocated memory\r
+ from one 4G address space.\r
+ @param Which4G The 4G memory area each memory allocated should be from.\r
+\r
+ @retval EFI_SUCCESS The memory pool is initialized.\r
+ @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.\r
+\r
+**/\r
+USBHC_MEM_POOL *\r
+UsbHcInitMemPool (\r
+ IN BOOLEAN Check4G,\r
+ IN UINT32 Which4G\r
+ );\r
+\r
+\r
+/**\r
+ Release the memory management pool.\r
+\r
+ @param Pool The USB memory pool to free.\r
+\r
+ @retval EFI_SUCCESS The memory pool is freed.\r
+ @retval EFI_DEVICE_ERROR Failed to free the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+UsbHcFreeMemPool (\r
+ IN USBHC_MEM_POOL *Pool\r
+ );\r
+\r
+\r
+/**\r
+ Allocate some memory from the host controller's memory pool\r
+ which can be used to communicate with host controller.\r
+\r
+ @param Pool The host controller's memory pool.\r
+ @param Size Size of the memory to allocate.\r
+\r
+ @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+UsbHcAllocateMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN UINTN Size\r
+ );\r
+\r
+\r
+/**\r
+ Free the allocated memory back to the memory pool.\r
+\r
+ @param Pool The memory pool of the host controller.\r
+ @param Mem The memory to free.\r
+ @param Size The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+UsbHcFreeMem (\r
+ IN USBHC_MEM_POOL *Pool,\r
+ IN VOID *Mem,\r
+ IN UINTN Size\r
+ );\r
+\r
+#endif\r