QuarkSocPkg: Add new package for Quark SoC X1000

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

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

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

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19286 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Michael Kinney
2015-12-15 19:22:23 +00:00
committed by mdkinney
parent 46ff196fde
commit 9b6bbcdbfd
176 changed files with 54761 additions and 0 deletions

View File

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

View File

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

25
QuarkSocPkg/License.txt Normal file
View File

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

View File

@@ -0,0 +1,257 @@
/** @file
Memory controller configuration.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __DDR_MEMORY_CONTROLLER_H__
#define __DDR_MEMORY_CONTROLLER_H__
//
// DDR timing data definitions.
// These are used to create bitmaps of valid timing configurations.
//
#define DUAL_CHANNEL_DDR_TIMING_DATA_FREQUENCY_UNKNOWN 0xFF
#define DUAL_CHANNEL_DDR_TIMING_DATA_REFRESH_RATE_UNKNOWN 0xFF
#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_20 0x01
#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_25 0x00
#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_30 0x02
#define DUAL_CHANNEL_DDR_TIMING_DATA_TCL_ALL 0x03
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_02 0x02
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_03 0x01
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_04 0x00
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRCD_ALL 0x03
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_02 0x02
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_03 0x01
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_04 0x00
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRP_ALL 0x03
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_05 0x05
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_06 0x04
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_07 0x03
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_08 0x02
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_09 0x01
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_10 0x00
#define DUAL_CHANNEL_DDR_TIMING_DATA_TRAS_ALL 0x07
#define DUAL_CHANNEL_DDR_DATA_TYPE_REGISTERED 0x01
#define DUAL_CHANNEL_DDR_DATA_TYPE_UNREGISTERED 0x02
#define DUAL_CHANNEL_DDR_DATA_TYPE_BUFFERED 0x04
#define DUAL_CHANNEL_DDR_DATA_TYPE_UNBUFFERED 0x08
#define DUAL_CHANNEL_DDR_DATA_TYPE_SDR 0x10
#define DUAL_CHANNEL_DDR_DATA_TYPE_DDR 0x20
//
// Maximum number of SDRAM channels supported by the memory controller
//
#define MAX_CHANNELS 1
//
// Maximum number of DIMM sockets supported by the memory controller
//
#define MAX_SOCKETS 1
//
// Maximum number of sides supported per DIMM
//
#define MAX_SIDES 2
//
// Maximum number of "Socket Sets", where a "Socket Set is a set of matching
// DIMM's from the various channels
//
#define MAX_SOCKET_SETS 2
//
// Maximum number of rows supported by the memory controller
//
#define MAX_ROWS (MAX_SIDES * MAX_SOCKETS)
//
// Maximum number of memory ranges supported by the memory controller
//
#define MAX_RANGES (MAX_ROWS + 5)
//
// Maximum Number of Log entries
//
#define MEMORY_LOG_MAX_INDEX 16
typedef struct _MEMORY_LOG_ENTRY {
EFI_STATUS_CODE_VALUE Event;
EFI_STATUS_CODE_TYPE Severity;
UINT8 Data;
} MEMORY_LOG_ENTRY;
typedef struct _MEMORY_LOG {
UINT8 Index;
MEMORY_LOG_ENTRY Entry[MEMORY_LOG_MAX_INDEX];
} MEMORY_LOG;
//
// Defined ECC types
//
#define DUAL_CHANNEL_DDR_ECC_TYPE_NONE 0x01 // No error checking
#define DUAL_CHANNEL_DDR_ECC_TYPE_EC 0x02 // Error checking only
#define DUAL_CHANNEL_DDR_ECC_TYPE_SECC 0x04 // Software Scrubbing ECC
#define DUAL_CHANNEL_DDR_ECC_TYPE_HECC 0x08 // Hardware Scrubbing ECC
#define DUAL_CHANNEL_DDR_ECC_TYPE_CKECC 0x10 // Chip Kill ECC
//
// Row configuration status values
//
#define DUAL_CHANNEL_DDR_ROW_CONFIG_SUCCESS 0x00 // No error
#define DUAL_CHANNEL_DDR_ROW_CONFIG_UNKNOWN 0x01 // Pattern mismatch, no memory
#define DUAL_CHANNEL_DDR_ROW_CONFIG_UNSUPPORTED 0x02 // Memory type not supported
#define DUAL_CHANNEL_DDR_ROW_CONFIG_ADDRESS_ERROR 0x03 // Row/Col/Bnk mismatch
#define DUAL_CHANNEL_DDR_ROW_CONFIG_ECC_ERROR 0x04 // Received ECC error
#define DUAL_CHANNEL_DDR_ROW_CONFIG_NOT_PRESENT 0x05 // Row is not present
#define DUAL_CHANNEL_DDR_ROW_CONFIG_DISABLED 0x06 // Row is disabled
//
// Memory range types
//
typedef enum {
DualChannelDdrMainMemory,
DualChannelDdrSmramCacheable,
DualChannelDdrSmramNonCacheable,
DualChannelDdrGraphicsMemoryCacheable,
DualChannelDdrGraphicsMemoryNonCacheable,
DualChannelDdrReservedMemory,
DualChannelDdrMaxMemoryRangeType
} DUAL_CHANNEL_DDR_MEMORY_RANGE_TYPE;
//
// Memory map range information
//
typedef struct {
EFI_PHYSICAL_ADDRESS PhysicalAddress;
EFI_PHYSICAL_ADDRESS CpuAddress;
EFI_PHYSICAL_ADDRESS RangeLength;
DUAL_CHANNEL_DDR_MEMORY_RANGE_TYPE Type;
} DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE;
typedef struct {
unsigned dramType :1; /**< Type: 0 = RESERVED; 1 = DDR2 */
unsigned dramWidth :1; /**< Width: 0 = x8; 1 = x16 */
unsigned dramDensity :2; /**< Density: 00b = 2Gb; 01b = 1Gb; 10b = 512Mb; 11b = 256Mb */
unsigned dramSpeed :1; /**< Speed Grade: 0 = RESERVED; 1 = 800MT/s;*/
unsigned dramTimings :3; /**< Timings: 4-4-4, 5-5-5, 6-6-6 */
unsigned dramRanks :1; /**< Ranks: 0 = Single Rank; 1 = Dual Rank */
} DramGeometry; /**< DRAM Geometry Descriptor */
typedef union _RegDRP {
UINT32 raw;
struct {
unsigned rank0Enabled :1; /**< Rank 0 Enable */
unsigned rank0DevWidth :2; /**< DRAM Device Width (x8,x16) */
unsigned rank0DevDensity :2; /**< DRAM Device Density (256Mb,512Mb,1Gb,2Gb) */
unsigned reserved2 :1;
unsigned rank1Enabled :1; /**< Rank 1 Enable */
unsigned reserved3 :5;
unsigned dramType :1; /**< DRAM Type (0=DDR2) */
unsigned reserved4 :5;
unsigned reserved5 :14;
} field;
} RegDRP; /**< DRAM Rank Population and Interface Register */
typedef union {
UINT32 raw;
struct {
unsigned dramFrequency :3; /**< DRAM Frequency (000=RESERVED,010=667,011=800) */
unsigned tRP :2; /**< Precharge to Activate Delay (3,4,5,6) */
unsigned reserved1 :1;
unsigned tRCD :2; /**< Activate to CAS Delay (3,4,5,6) */
unsigned reserved2 :1;
unsigned tCL :2; /**< CAS Latency (3,4,5,6) */
unsigned reserved3 :21;
} field;
} RegDTR0; /**< DRAM Timing Register 0 */
typedef union {
UINT32 raw;
struct {
unsigned tWRRD_dly :2; /**< Additional Write to Read Delay (0,1,2,3) */
unsigned reserved1 :1;
unsigned tRDWR_dly :2; /**< Additional Read to Write Delay (0,1,2,3) */
unsigned reserved2 :1;
unsigned tRDRD_dr_dly :1; /**< Additional Read to Read Delay (1,2) */
unsigned reserved3 :1;
unsigned tRD_dly :3; /**< Additional Read Data Sampling Delay (0-7) */
unsigned reserved4 :1;
unsigned tRCVEN_halfclk_dly :4; /**< Additional RCVEN Half Clock Delay Control */
unsigned reserved5 :1;
unsigned readDqDelay :2; /**< Read DQ Delay */
unsigned reserved6 :13;
} field;
} RegDTR1; /**< DRAM Timing Register 1 */
typedef union {
UINT32 raw;
struct {
unsigned ckStaticDisable :1; /**< CK/CK# Static Disable */
unsigned reserved1 :3;
unsigned ckeStaticDisable :2; /**< CKE Static Disable */
unsigned reserved2 :8;
unsigned refreshPeriod :2; /**< Refresh Period (disabled,128clks,3.9us,7.8us) */
unsigned refreshQueueDepth :2; /**< Refresh Queue Depth (1,2,4,8) */
unsigned reserved5 :13;
unsigned initComplete :1; /**< Initialization Complete */
} field;
} RegDCO;
//
// MRC Data Structure
//
typedef struct {
RegDRP drp;
RegDTR0 dtr0;
RegDTR1 dtr1;
RegDCO dco;
UINT32 reg0104;
UINT32 reg0120;
UINT32 reg0121;
UINT32 reg0123;
UINT32 reg0111;
UINT32 reg0130;
UINT8 refreshPeriod; /**< Placeholder for the chosen refresh
* period. This value will NOT be
* programmed into DCO until all
* initialization is done.
*/
UINT8 ddr2Odt; /**< 0 = Disabled, 1 = 75 ohm, 2 = 150ohm, 3 = 50ohm */
UINT8 sku; /**< Detected QuarkNcSocId SKU */
UINT8 capabilities; /**< Capabilities Available on this part */
UINT8 state; /**< NORMAL_BOOT, S3_RESUME */
UINT32 memSize; /**< Memory size */
UINT16 pmBase; /**< PM Base */
UINT16 mrcVersion; /**< MRC Version */
UINT32 hecbase; /**< HECBASE shifted left 16 bits */
DramGeometry geometry; /**< DRAM Geometry */
} MRC_DATA_STRUCTURE; /**< QuarkNcSocId Memory Parameters for MRC */
typedef struct _EFI_MEMINIT_CONFIG_DATA {
MRC_DATA_STRUCTURE MrcData;
} EFI_MEMINIT_CONFIG_DATA;
#endif

View File

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

View File

@@ -0,0 +1,106 @@
/** @file
Some configuration of QNC Package
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __INTEL_QNC_CONFIG_H__
#define __INTEL_QNC_CONFIG_H__
//
// QNC Fixed configurations.
//
//
// Memory arbiter fixed config values.
//
#define QNC_FIXED_CONFIG_ASTATUS ((UINT32) (\
(ASTATUS_PRI_NORMAL << ASTATUS0_DEFAULT_BP) | \
(ASTATUS_PRI_NORMAL << ASTATUS1_DEFAULT_BP) | \
(ASTATUS_PRI_URGENT << ASTATUS0_RASISED_BP) | \
(ASTATUS_PRI_URGENT << ASTATUS1_RASISED_BP) \
))
//
// Memory Manager fixed config values.
//
#define V_DRAM_NON_HOST_RQ_LIMIT 2
//
// RMU Thermal config fixed config values for TS in Vref Mode.
//
#define V_TSCGF1_CONFIG_ISNSCURRENTSEL_VREF_MODE 0x04
#define V_TSCGF2_CONFIG2_ISPARECTRL_VREF_MODE 0x01
#define V_TSCGF1_CONFIG_IBGEN_VREF_MODE 1
#define V_TSCGF2_CONFIG_IDSCONTROL_VREF_MODE 0x011b
#define V_TSCGF2_CONFIG2_ICALCOARSETUNE_VREF_MODE 0x34
//
// RMU Thermal config fixed config values for TS in Ratiometric mode.
//
#define V_TSCGF1_CONFIG_ISNSCURRENTSEL_RATIO_MODE 0x04
#define V_TSCGF1_CONFIG_ISNSCHOPSEL_RATIO_MODE 0x02
#define V_TSCGF1_CONFIG_ISNSINTERNALVREFEN_RATIO_MODE 1
#define V_TSCGF2_CONFIG_IDSCONTROL_RATIO_MODE 0x011f
#define V_TSCGF2_CONFIG_IDSTIMING_RATIO_MODE 0x0001
#define V_TSCGF2_CONFIG2_ICALCONFIGSEL_RATIO_MODE 0x01
#define V_TSCGF2_CONFIG2_ISPARECTRL_RATIO_MODE 0x00
#define V_TSCGF1_CONFIG_IBGEN_RATIO_MODE 0
#define V_TSCGF1_CONFIG_IBGCHOPEN_RATIO_MODE 0
#define V_TSCGF3_CONFIG_ITSGAMMACOEFF_RATIO_MODE 0xC8
#define V_TSCGF2_CONFIG2_ICALCOARSETUNE_RATIO_MODE 0x17
//
// iCLK fixed config values.
//
#define V_MUXTOP_FLEX2 3
#define V_MUXTOP_FLEX1 1
//
// PCIe Root Port fixed config values.
//
#define V_PCIE_ROOT_PORT_SBIC_VALUE (B_QNC_PCIE_IOSFSBCTL_SBIC_IDLE_NEVER)
//
// QNC structures for configuration.
//
typedef union {
struct {
UINT32 PortErrorMask :8;
UINT32 SlotImplemented :1;
UINT32 Reserved1 :1;
UINT32 AspmEnable :1;
UINT32 AspmAutoEnable :1;
UINT32 AspmL0sEnable :2;
UINT32 AspmL1Enable :1;
UINT32 PmeInterruptEnable :1;
UINT32 PhysicalSlotNumber :13;
UINT32 Reserved2 :1;
UINT32 PmSciEnable :1;
UINT32 HotplugSciEnable :1;
} Bits;
UINT32 Uint32;
} PCIEXP_ROOT_PORT_CONFIGURATION;
typedef union {
UINT32 Uint32;
struct {
UINT32 Pcie_0 :1; // 0: Disabled; 1: Enabled*
UINT32 Pcie_1 :1; // 0: Disabled; 1: Enabled*
UINT32 Smbus :1; // 0: Disabled; 1: Enabled*
UINT32 Rsvd :29; // 0
} Bits;
} QNC_DEVICE_ENABLES;
#endif

View File

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

View File

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

View File

@@ -0,0 +1,54 @@
/** @file
Registers definition for Intel QuarkNcSocId.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __INTEL_QNC_REGS_H__
#define __INTEL_QNC_REGS_H__
#include <QNCAccess.h>
//
// PCI HostBridge Segment number
//
#define QNC_PCI_HOST_BRIDGE_SEGMENT_NUMBER 0
//
// PCI RootBridge resource allocation's attribute
//
#define QNC_PCI_ROOT_BRIDGE_RESOURCE_ALLOCATION_ATTRIBUTE \
EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM
//
// PCI HostBridge resource appeture
//
#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSBASE 0x0
#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_BUSLIMIT 0xff
#define QNC_PCI_HOST_BRIDGE_RESOURCE_APPETURE_TSEG_SIZE 0x10000000
//
// PCI RootBridge configure port
//
#define QNC_PCI_ROOT_BRIDGE_CONFIGURATION_ADDRESS_PORT 0xCF8
#define QNC_PCI_ROOT_BRIDGE_CONFIGURATION_DATA_PORT 0xCFC
//
// PCI Rootbridge's support feature
//
#define QNC_PCI_ROOT_BRIDGE_SUPPORTED (EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | \
EFI_PCI_ATTRIBUTE_ISA_IO | \
EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | \
EFI_PCI_ATTRIBUTE_VGA_MEMORY | \
EFI_PCI_ATTRIBUTE_VGA_IO)
#endif // __INTEL_QNC_REGS_H__

View File

@@ -0,0 +1,290 @@
/** @file
Library that provides QNC specific library services in PEI phase
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __INTEL_QNC_LIB_H__
#define __INTEL_QNC_LIB_H__
/**
This function initializes the QNC register before MRC.
It sets RCBA, PMBASE, disable Watchdog timer and initialize QNC GPIO.
If the function cannot complete it'll ASSERT().
**/
VOID
EFIAPI
PeiQNCPreMemInit (
VOID
);
/**
Used to check SCH if it's S3 state. Clear the register state after query.
@retval TRUE if it's S3 state.
@retval FALSE if it's not S3 state.
**/
BOOLEAN
EFIAPI
QNCCheckS3AndClearState (
VOID
);
/**
Used to check SCH if system wakes up from power on reset. Clear the register state after query.
@retval TRUE if system wakes up from power on reset
@retval FALSE if system does not wake up from power on reset
**/
BOOLEAN
EFIAPI
QNCCheckPowerOnResetAndClearState (
VOID
);
/**
This function is used to clear SMI and wake status.
**/
VOID
EFIAPI
QNCClearSmiAndWake (
VOID
);
/**
Used to initialize the QNC register after MRC.
**/
VOID
EFIAPI
PeiQNCPostMemInit (
VOID
);
/** Send DRAM Ready opcode.
@param[in] OpcodeParam Parameter to DRAM ready opcode.
@retval VOID
**/
VOID
EFIAPI
QNCSendOpcodeDramReady (
IN UINT32 OpcodeParam
);
/**
Relocate RMU Main binary to memory after MRC to improve performance.
@param[in] DestBaseAddress - Specify the new memory address for the RMU Main binary.
@param[in] SrcBaseAddress - Specify the current memory address for the RMU Main binary.
@param[in] Size - Specify size of the RMU Main binary.
@retval VOID
**/
VOID
EFIAPI
RmuMainRelocation (
IN CONST UINT32 DestBaseAddress,
IN CONST UINT32 SrcBaseAddress,
IN CONST UINTN Size
);
/**
Get the total memory size
**/
UINT32
EFIAPI
QNCGetTotalMemorysize (
VOID
);
/**
Get the memory range of TSEG.
The TSEG's memory is below TOLM.
@param[out] BaseAddress The base address of TSEG's memory range
@param[out] MemorySize The size of TSEG's memory range
**/
VOID
EFIAPI
QNCGetTSEGMemoryRange (
OUT UINT64 *BaseAddress,
OUT UINT64 *MemorySize
);
/**
Updates the PAM registers in the MCH for the requested range and mode.
@param Start The start address of the memory region
@param Length The length, in bytes, of the memory region
@param ReadEnable Pointer to the boolean variable on whether to enable read for legacy memory section.
If NULL, then read attribute will not be touched by this call.
@param ReadEnable Pointer to the boolean variable on whether to enable write for legacy memory section.
If NULL, then write attribute will not be touched by this call.
@param Granularity A pointer to granularity, in bytes, that the PAM registers support
@retval RETURN_SUCCESS The PAM registers in the MCH were updated
@retval RETURN_INVALID_PARAMETER The memory range is not valid in legacy region.
**/
RETURN_STATUS
EFIAPI
QNCLegacyRegionManipulation (
IN UINT32 Start,
IN UINT32 Length,
IN BOOLEAN *ReadEnable,
IN BOOLEAN *WriteEnable,
OUT UINT32 *Granularity
);
/**
Do early init of pci express rootports on Soc.
**/
VOID
EFIAPI
PciExpressEarlyInit (
VOID
);
/**
Complete initialization of all the pci express rootports on Soc.
**/
EFI_STATUS
EFIAPI
PciExpressInit (
);
/**
Determine if QNC is supported.
@retval FALSE QNC is not supported.
@retval TRUE QNC is supported.
**/
BOOLEAN
EFIAPI
IsQncSupported (
VOID
);
/**
Get the DeviceId of the SoC
@retval PCI DeviceId of the SoC
**/
UINT16
EFIAPI
QncGetSocDeviceId (
VOID
);
/**
Enable SMI detection of legacy flash access violations.
**/
VOID
EFIAPI
QncEnableLegacyFlashAccessViolationSmi (
VOID
);
/**
Setup RMU Thermal sensor registers for Vref mode.
**/
VOID
EFIAPI
QNCThermalSensorSetVRefMode (
VOID
);
/**
Setup RMU Thermal sensor registers for Ratiometric mode.
**/
VOID
EFIAPI
QNCThermalSensorSetRatiometricMode (
VOID
);
/**
Setup RMU Thermal sensor trip point values.
@param[in] CatastrophicTripOnDegreesCelsius - Catastrophic set trip point threshold.
@param[in] HotTripOnDegreesCelsius - Hot set trip point threshold.
@param[in] HotTripOffDegreesCelsius - Hot clear trip point threshold.
@retval VOID
**/
EFI_STATUS
EFIAPI
QNCThermalSensorSetTripValues (
IN CONST UINTN CatastrophicTripOnDegreesCelsius,
IN CONST UINTN HotTripOnDegreesCelsius,
IN CONST UINTN HotTripOffDegreesCelsius
);
/**
Enable RMU Thermal sensor with a Catastrophic Trip point.
@retval EFI_SUCCESS Trip points setup.
@retval EFI_INVALID_PARAMETER Invalid trip point value.
**/
EFI_STATUS
EFIAPI
QNCThermalSensorEnableWithCatastrophicTrip (
IN CONST UINTN CatastrophicTripOnDegreesCelsius
);
/**
Lock all RMU Thermal sensor control & trip point registers.
**/
VOID
EFIAPI
QNCThermalSensorLockAllRegisters (
VOID
);
/**
Set chipset policy for double bit ECC error.
@param[in] PolicyValue Policy to config on double bit ECC error.
**/
VOID
EFIAPI
QNCPolicyDblEccBitErr (
IN CONST UINT32 PolicyValue
);
/**
Determine if running on secure Quark hardware Sku.
@retval FALSE Base Quark Sku or unprovisioned Secure Sku running.
@retval TRUE Provisioned SecureSku hardware running.
**/
BOOLEAN
EFIAPI
QncIsSecureProvisionedSku (
VOID
);
#endif

View File

@@ -0,0 +1,167 @@
/** @file
Library functions for Setting QNC internal network port
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __QNC_ACCESS_LIB_H__
#define __QNC_ACCESS_LIB_H__
#include <IntelQNCRegs.h>
#define MESSAGE_READ_DW(Port, Reg) \
(UINT32)((QUARK_OPCODE_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
#define MESSAGE_WRITE_DW(Port, Reg) \
(UINT32)((QUARK_OPCODE_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
#define ALT_MESSAGE_READ_DW(Port, Reg) \
(UINT32)((QUARK_ALT_OPCODE_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
#define ALT_MESSAGE_WRITE_DW(Port, Reg) \
(UINT32)((QUARK_ALT_OPCODE_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
#define MESSAGE_IO_READ_DW(Port, Reg) \
(UINT32)((QUARK_OPCODE_IO_READ << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
#define MESSAGE_IO_WRITE_DW(Port, Reg) \
(UINT32)((QUARK_OPCODE_IO_WRITE << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
#define MESSAGE_SHADOW_DW(Port, Reg) \
(UINT32)((QUARK_DRAM_BASE_ADDR_READY << QNC_MCR_OP_OFFSET) | ((Port << QNC_MCR_PORT_OFFSET) & 0xFF0000) | ((Reg << QNC_MCR_REG_OFFSET) & 0xFF00) | 0xF0)
/**
Read required data from QNC internal message network
**/
UINT32
EFIAPI
QNCPortRead(
UINT8 Port,
UINT32 RegAddress
);
/**
Write prepared data into QNC internal message network.
**/
VOID
EFIAPI
QNCPortWrite (
UINT8 Port,
UINT32 RegAddress,
UINT32 WriteValue
);
/**
Read required data from QNC internal message network
**/
UINT32
EFIAPI
QNCAltPortRead(
UINT8 Port,
UINT32 RegAddress
);
/**
Write prepared data into QNC internal message network.
**/
VOID
EFIAPI
QNCAltPortWrite (
UINT8 Port,
UINT32 RegAddress,
UINT32 WriteValue
);
/**
Read required data from QNC internal message network
**/
UINT32
EFIAPI
QNCPortIORead(
UINT8 Port,
UINT32 RegAddress
);
/**
Write prepared data into QNC internal message network.
**/
VOID
EFIAPI
QNCPortIOWrite (
UINT8 Port,
UINT32 RegAddress,
UINT32 WriteValue
);
/**
This is for the special consideration for QNC MMIO write, as required by FWG,
a reading must be performed after MMIO writing to ensure the expected write
is processed and data is flushed into chipset
**/
RETURN_STATUS
EFIAPI
QNCMmIoWrite (
UINT32 MmIoAddress,
QNC_MEM_IO_WIDTH Width,
UINT32 DataNumber,
VOID *pData
);
UINT32
EFIAPI
QncHsmmcRead (
VOID
);
VOID
EFIAPI
QncHsmmcWrite (
UINT32 WriteValue
);
VOID
EFIAPI
QncImrWrite (
UINT32 ImrBaseOffset,
UINT32 ImrLow,
UINT32 ImrHigh,
UINT32 ImrReadMask,
UINT32 ImrWriteMask
);
VOID
EFIAPI
QncIClkAndThenOr (
UINT32 RegAddress,
UINT32 AndValue,
UINT32 OrValue
);
VOID
EFIAPI
QncIClkOr (
UINT32 RegAddress,
UINT32 OrValue
);
UINTN
EFIAPI
QncGetPciExpressBaseAddress (
VOID
);
#endif

View File

@@ -0,0 +1,63 @@
/** @file
QNC Smm Library Services header file.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __QNC_SMM_LIB_H__
#define __QNC_SMM_LIB_H__
/**
This routine is the chipset code that accepts a request to "open" a region of SMRAM.
The region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
The use of "open" means that the memory is visible from all boot-service
and SMM agents.
@retval FALSE Cannot open a locked SMRAM region
@retval TRUE Success to open SMRAM region.
**/
BOOLEAN
EFIAPI
QNCOpenSmramRegion (
VOID
);
/**
This routine is the chipset code that accepts a request to "close" a region of SMRAM.
The region could be legacy AB or TSEG near top of physical memory.
The use of "close" means that the memory is only visible from SMM agents,
not from BS or RT code.
@retval FALSE Cannot open a locked SMRAM region
@retval TRUE Success to open SMRAM region.
**/
BOOLEAN
EFIAPI
QNCCloseSmramRegion (
VOID
);
/**
This routine is the chipset code that accepts a request to "lock" SMRAM.
The region could be legacy AB or TSEG near top of physical memory.
The use of "lock" means that the memory can no longer be opened
to BS state.
**/
VOID
EFIAPI
QNCLockSmramRegion (
VOID
);
#endif

View File

@@ -0,0 +1,42 @@
/** @file
Memory Initialization PPI used in EFI PEI interface
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __QNC_MEMORY_INIT_H__
#define __QNC_MEMORY_INIT_H__
#include "mrc.h"
#define PEI_QNC_MEMORY_INIT_PPI_GUID \
{0x21ff1fee, 0xd33a, 0x4fce, {0xa6, 0x5e, 0x95, 0x5e, 0xa3, 0xc4, 0x1f, 0x40}}
//
// PPI Function Declarations
//
typedef
VOID
(EFIAPI *PEI_QNC_MEMORY_INIT) (
IN OUT MRCParams_t *MRCDATA
);
typedef struct _PEI_QNC_MEMORY_INIT_PPI {
PEI_QNC_MEMORY_INIT MrcStart;
}PEI_QNC_MEMORY_INIT_PPI;
extern EFI_GUID gQNCMemoryInitPpiGuid;
#endif

View File

@@ -0,0 +1,54 @@
/** @file
This file defines the QNC Info Protocol.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _PCH_INFO_H_
#define _PCH_INFO_H_
//
// Extern the GUID for protocol users.
//
extern EFI_GUID gEfiQncInfoProtocolGuid;
//
// Forward reference for ANSI C compatibility
//
typedef struct _EFI_QNC_INFO_PROTOCOL EFI_QNC_INFO_PROTOCOL;
//
// Protocol revision number
// Any backwards compatible changes to this protocol will result in an update in the revision number
// Major changes will require publication of a new protocol
//
// Revision 1: Original version
// Revision 2: Add RCVersion item to EFI_QNC_INFO_PROTOCOL
//
#define QNC_INFO_PROTOCOL_REVISION_1 1
#define QNC_INFO_PROTOCOL_REVISION_2 2
//
// RCVersion[7:0] is the release number.
//
#define QNC_RC_VERSION 0x01020000
//
// Protocol definition
//
struct _EFI_QNC_INFO_PROTOCOL {
UINT8 Revision;
UINT8 BusNumber;
UINT32 RCVersion;
};
#endif

View File

@@ -0,0 +1,37 @@
/** @file
Protocol used for Platform Policy definition.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _PLATFORM_POLICY_H_
#define _PLATFORM_POLICY_H_
typedef struct _EFI_PLATFORM_POLICY_PROTOCOL EFI_PLATFORM_POLICY_PROTOCOL;
#define EFI_PLATFORM_POLICY_PROTOCOL_GUID \
{ \
0x2977064f, 0xab96, 0x4fa9, { 0x85, 0x45, 0xf9, 0xc4, 0x02, 0x51, 0xe0, 0x7f } \
}
//
// Protocol to describe various platform information. Add to this as needed.
//
struct _EFI_PLATFORM_POLICY_PROTOCOL {
UINT8 NumRsvdSmbusAddresses;
UINT8 *RsvdSmbusAddresses;
};
extern EFI_GUID gEfiPlatformPolicyProtocolGuid;
#endif

View File

@@ -0,0 +1,90 @@
/** @file
This file defines the QNC S3 support Protocol.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _QNC_S3_SUPPORT_PROTOCOL_H_
#define _QNC_S3_SUPPORT_PROTOCOL_H_
//
// Extern the GUID for protocol users.
//
extern EFI_GUID gEfiQncS3SupportProtocolGuid;
//
// Forward reference for ANSI C compatibility
//
typedef struct _EFI_QNC_S3_SUPPORT_PROTOCOL EFI_QNC_S3_SUPPORT_PROTOCOL;
typedef enum {
QncS3ItemTypeInitPcieRootPortDownstream,
QncS3ItemTypeMax
} EFI_QNC_S3_DISPATCH_ITEM_TYPE;
//
// It's better not to use pointer here because the size of pointer in DXE is 8, but it's 4 in PEI
// plug 4 to ParameterSize in PEIM if you really need it
//
typedef struct {
UINT32 Reserved;
} EFI_QNC_S3_PARAMETER_INIT_PCIE_ROOT_PORT_DOWNSTREAM;
typedef union {
EFI_QNC_S3_PARAMETER_INIT_PCIE_ROOT_PORT_DOWNSTREAM PcieRootPortData;
} EFI_DISPATCH_CONTEXT_UNION;
typedef struct {
EFI_QNC_S3_DISPATCH_ITEM_TYPE Type;
VOID *Parameter;
} EFI_QNC_S3_DISPATCH_ITEM;
//
// Member functions
//
typedef
EFI_STATUS
(EFIAPI *EFI_QNC_S3_SUPPORT_SET_S3_DISPATCH_ITEM) (
IN EFI_QNC_S3_SUPPORT_PROTOCOL * This,
IN EFI_QNC_S3_DISPATCH_ITEM * DispatchItem,
OUT VOID **S3DispatchEntryPoint,
OUT VOID **Context
);
/*++
Routine Description:
Set an item to be dispatched at S3 resume time. At the same time, the entry point
of the QNC S3 support image is returned to be used in subsequent boot script save
call
Arguments:
This - Pointer to the protocol instance.
DispatchItem - The item to be dispatched.
S3DispatchEntryPoint - The entry point of the QNC S3 support image.
Returns:
EFI_STATUS
--*/
//
// Protocol definition
//
struct _EFI_QNC_S3_SUPPORT_PROTOCOL {
EFI_QNC_S3_SUPPORT_SET_S3_DISPATCH_ITEM SetDispatchItem;
};
#endif

View File

@@ -0,0 +1,121 @@
/** @file
Intel-only SMM Child Dispatcher Protocol.
This protocol provides a parent dispatch service for a collection of
chipset-specific SMI source.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __SMM_ICHN_DISPATCH2_H__
#define __SMM_ICHN_DISPATCH2_H__
//
// Share some common definitions with Framework SMM
//
#include <Protocol/SmmIchnDispatch.h>
#include <PiSmm.h>
//
// Global ID for the ICH SMI Protocol
//
#define EFI_SMM_ICHN_DISPATCH2_PROTOCOL_GUID \
{ \
0xadf3a128, 0x416d, 0x4060, {0x8d, 0xdf, 0x30, 0xa1, 0xd7, 0xaa, 0xb6, 0x99 } \
}
typedef struct _EFI_SMM_ICHN_DISPATCH2_PROTOCOL EFI_SMM_ICHN_DISPATCH2_PROTOCOL;
typedef struct {
EFI_SMM_ICHN_SMI_TYPE Type;
} EFI_SMM_ICHN_REGISTER_CONTEXT;
//
// Member functions
//
/**
Register a child SMI source dispatch function with a parent SMM driver
@param This Protocol instance pointer.
@param DispatchFunction Pointer to dispatch function to be invoked for
this SMI source
@param RegisterContext Pointer to the dispatch function's context.
The caller fills this context in before calling
the register function to indicate to the register
function the ICHN SMI source for which the dispatch
function should be invoked.
@param DispatchHandle Handle generated by the dispatcher to track the
function instance.
@retval EFI_SUCCESS The dispatch function has been successfully
registered and the SMI source has been enabled.
@retval EFI_DEVICE_ERROR The driver was unable to enable the SMI source.
@retval EFI_OUT_OF_RESOURCES Not enough memory (system or SMM) to manage this
child.
@retval EFI_INVALID_PARAMETER RegisterContext is invalid. The ICHN input value
is not within valid range.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_SMM_ICHN_DISPATCH2_REGISTER) (
IN CONST EFI_SMM_ICHN_DISPATCH2_PROTOCOL *This,
IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
IN OUT EFI_SMM_ICHN_REGISTER_CONTEXT *RegisterContext,
OUT EFI_HANDLE *DispatchHandle
);
/**
Unregister a child SMI source dispatch function with a parent SMM driver
@param This Protocol instance pointer.
@param DispatchHandle Handle of dispatch function to deregister.
@retval EFI_SUCCESS The dispatch function has been successfully
unregistered and the SMI source has been disabled
if there are no other registered child dispatch
functions for this SMI source.
@retval EFI_INVALID_PARAMETER Handle is invalid.
@retval other
**/
typedef
EFI_STATUS
(EFIAPI *EFI_SMM_ICHN_DISPATCH2_UNREGISTER) (
IN EFI_SMM_ICHN_DISPATCH2_PROTOCOL *This,
IN EFI_HANDLE DispatchHandle
);
//
// Interface structure for the SMM Ich n specific SMI Dispatch Protocol
//
/**
@par Protocol Description:
Provides a parent dispatch service for ICH SMI sources.
@param Register
Installs a child service to be dispatched by this protocol.
@param UnRegister
Removes a child service dispatched by this protocol.
**/
struct _EFI_SMM_ICHN_DISPATCH2_PROTOCOL {
EFI_SMM_ICHN_DISPATCH2_REGISTER Register;
EFI_SMM_ICHN_DISPATCH2_UNREGISTER UnRegister;
};
extern EFI_GUID gEfiSmmIchnDispatch2ProtocolGuid;
#endif

View File

@@ -0,0 +1,351 @@
/** @file
This file defines the EFI SPI Protocol which implements the
Intel(R) ICH SPI Host Controller Compatibility Interface.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _SPI_H_
#define _SPI_H_
//
// Define the SPI protocol GUID
//
// EDK and EDKII have different GUID formats
//
#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
#define EFI_SPI_PROTOCOL_GUID \
{ \
0x1156efc6, 0xea32, 0x4396, 0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 \
}
#define EFI_SMM_SPI_PROTOCOL_GUID \
{ \
0xD9072C35, 0xEB8F, 0x43ad, 0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 \
}
#else
#define EFI_SPI_PROTOCOL_GUID \
{ \
0x1156efc6, 0xea32, 0x4396, \
{ \
0xb5, 0xd5, 0x26, 0x93, 0x2e, 0x83, 0xc3, 0x13 \
} \
}
#define EFI_SMM_SPI_PROTOCOL_GUID \
{ \
0xD9072C35, 0xEB8F, 0x43ad, \
{ \
0xA2, 0x20, 0x34, 0xD4, 0x0E, 0x2A, 0x82, 0x85 \
} \
}
#endif
//
// Extern the GUID for protocol users.
//
extern EFI_GUID gEfiSpiProtocolGuid;
extern EFI_GUID gEfiSmmSpiProtocolGuid;
//
// Forward reference for ANSI C compatibility
//
typedef struct _EFI_SPI_PROTOCOL EFI_SPI_PROTOCOL;
//
// SPI protocol data structures and definitions
//
//
// Number of Prefix Opcodes allowed on the SPI interface
//
#define SPI_NUM_PREFIX_OPCODE 2
//
// Number of Opcodes in the Opcode Menu
//
#define SPI_NUM_OPCODE 8
#ifdef SERVER_BIOS_FLAG
//
// SPI default opcode slots
//
#define SPI_OPCODE_JEDEC_ID_INDEX 0
#endif // SERVER_BIOS_FLAG
//
// Opcode Type
// EnumSpiOpcodeCommand: Command without address
// EnumSpiOpcodeRead: Read with address
// EnumSpiOpcodeWrite: Write with address
//
typedef enum {
EnumSpiOpcodeReadNoAddr,
EnumSpiOpcodeWriteNoAddr,
EnumSpiOpcodeRead,
EnumSpiOpcodeWrite,
EnumSpiOpcodeMax
} SPI_OPCODE_TYPE;
typedef enum {
EnumSpiCycle20MHz,
EnumSpiCycle33MHz,
EnumSpiCycle66MHz, // not supported by PCH
EnumSpiCycle50MHz,
EnumSpiCycleMax
} SPI_CYCLE_FREQUENCY;
typedef enum {
EnumSpiRegionAll,
EnumSpiRegionBios,
EnumSpiRegionMe,
EnumSpiRegionGbE,
EnumSpiRegionDescriptor,
EnumSpiRegionPlatformData,
EnumSpiRegionMax
} SPI_REGION_TYPE;
//
// Hardware Sequencing required operations (as listed in CougarPoint EDS Table 5-55: "Hardware
// Sequencing Commands and Opcode Requirements"
//
typedef enum {
EnumSpiOperationWriteStatus,
EnumSpiOperationProgramData_1_Byte,
EnumSpiOperationProgramData_64_Byte,
EnumSpiOperationReadData,
EnumSpiOperationWriteDisable,
EnumSpiOperationReadStatus,
EnumSpiOperationWriteEnable,
EnumSpiOperationFastRead,
EnumSpiOperationEnableWriteStatus,
EnumSpiOperationErase_256_Byte,
EnumSpiOperationErase_4K_Byte,
EnumSpiOperationErase_8K_Byte,
EnumSpiOperationErase_64K_Byte,
EnumSpiOperationFullChipErase,
EnumSpiOperationJedecId,
EnumSpiOperationDualOutputFastRead,
EnumSpiOperationDiscoveryParameters,
EnumSpiOperationOther,
EnumSpiOperationMax
} SPI_OPERATION;
//
// Opcode menu entries
// Type Operation Type (value to be programmed to the OPTYPE register)
// Code The opcode (value to be programmed to the OPMENU register)
// Frequency The expected frequency to be used (value to be programmed to the SSFC
// Register)
// Operation Which Hardware Sequencing required operation this opcode respoinds to.
// The required operations are listed in EDS Table 5-55: "Hardware
// Sequencing Commands and Opcode Requirements"
// If the opcode does not corresponds to any operation listed, use
// EnumSpiOperationOther
//
typedef struct _SPI_OPCODE_MENU_ENTRY {
SPI_OPCODE_TYPE Type;
UINT8 Code;
SPI_CYCLE_FREQUENCY Frequency;
SPI_OPERATION Operation;
} SPI_OPCODE_MENU_ENTRY;
//
// Initialization data table loaded to the SPI host controller
// VendorId Vendor ID of the SPI device
// DeviceId0 Device ID0 of the SPI device
// DeviceId1 Device ID1 of the SPI device
// PrefixOpcode Prefix opcodes which are loaded into the SPI host controller
// OpcodeMenu Opcodes which are loaded into the SPI host controller Opcode Menu
// BiosStartOffset The offset of the start of the BIOS image relative to the flash device.
// Please note this is a Flash Linear Address, NOT a memory space address.
// This value is platform specific and depends on the system flash map.
// This value is only used on non Descriptor mode.
// BiosSize The the BIOS Image size in flash. This value is platform specific
// and depends on the system flash map. Please note BIOS Image size may
// be smaller than BIOS Region size (in Descriptor Mode) or the flash size
// (in Non Descriptor Mode), and in this case, BIOS Image is supposed to be
// placed at the top end of the BIOS Region (in Descriptor Mode) or the flash
// (in Non Descriptor Mode)
//
typedef struct _SPI_INIT_TABLE {
UINT8 VendorId;
UINT8 DeviceId0;
UINT8 DeviceId1;
UINT8 PrefixOpcode[SPI_NUM_PREFIX_OPCODE];
SPI_OPCODE_MENU_ENTRY OpcodeMenu[SPI_NUM_OPCODE];
UINTN BiosStartOffset;
UINTN BiosSize;
} SPI_INIT_TABLE;
//
// Public Info struct to show current initialized state of the spi interface.
// OpcodeIndex must be less then SPI_NUM_OPCODE for operation to be supported.
//
typedef struct _SPI_INIT_INFO {
SPI_INIT_TABLE *InitTable;
UINT8 JedecIdOpcodeIndex;
UINT8 OtherOpcodeIndex;
UINT8 WriteStatusOpcodeIndex;
UINT8 ProgramOpcodeIndex;
UINT8 ReadOpcodeIndex;
UINT8 EraseOpcodeIndex;
UINT8 ReadStatusOpcodeIndex;
UINT8 FullChipEraseOpcodeIndex;
} SPI_INIT_INFO;
//
// Protocol member functions
//
typedef
EFI_STATUS
(EFIAPI *EFI_SPI_INIT) (
IN EFI_SPI_PROTOCOL * This,
IN SPI_INIT_TABLE * InitTable
);
/*++
Routine Description:
Initializes the host controller to execute SPI commands.
Arguments:
This Pointer to the EFI_SPI_PROTOCOL instance.
InitTable Pointer to caller-allocated buffer containing the SPI
interface initialization table.
Returns:
EFI_SUCCESS Opcode initialization on the SPI host controller completed.
EFI_ACCESS_DENIED The SPI configuration interface is locked.
EFI_OUT_OF_RESOURCES Not enough resource available to initialize the device.
EFI_DEVICE_ERROR Device error, operation failed.
--*/
typedef
EFI_STATUS
(EFIAPI *EFI_SPI_LOCK) (
IN EFI_SPI_PROTOCOL * This
);
/*++
Routine Description:
Lock the SPI Static Configuration Interface.
Once locked, the interface is no longer open for configuration changes.
The lock state automatically clears on next system reset.
Arguments:
This Pointer to the EFI_SPI_PROTOCOL instance.
Returns:
EFI_SUCCESS Lock operation succeed.
EFI_DEVICE_ERROR Device error, operation failed.
EFI_ACCESS_DENIED The interface has already been locked.
--*/
typedef
EFI_STATUS
(EFIAPI *EFI_SPI_EXECUTE) (
IN EFI_SPI_PROTOCOL * This,
IN UINT8 OpcodeIndex,
IN UINT8 PrefixOpcodeIndex,
IN BOOLEAN DataCycle,
IN BOOLEAN Atomic,
IN BOOLEAN ShiftOut,
IN UINTN Address,
IN UINT32 DataByteCount,
IN OUT UINT8 *Buffer,
IN SPI_REGION_TYPE SpiRegionType
);
/*++
Routine Description:
Execute SPI commands from the host controller.
Arguments:
This Pointer to the EFI_SPI_PROTOCOL instance.
OpcodeIndex Index of the command in the OpCode Menu.
PrefixOpcodeIndex Index of the first command to run when in an atomic cycle sequence.
DataCycle TRUE if the SPI cycle contains data
Atomic TRUE if the SPI cycle is atomic and interleave cycles are not allowed.
ShiftOut If DataByteCount is not zero, TRUE to shift data out and FALSE to shift data in.
Address In Descriptor Mode, for Descriptor Region, GbE Region, ME Region and Platform
Region, this value specifies the offset from the Region Base; for BIOS Region,
this value specifies the offset from the start of the BIOS Image. In Non
Descriptor Mode, this value specifies the offset from the start of the BIOS Image.
Please note BIOS Image size may be smaller than BIOS Region size (in Descriptor
Mode) or the flash size (in Non Descriptor Mode), and in this case, BIOS Image is
supposed to be placed at the top end of the BIOS Region (in Descriptor Mode) or
the flash (in Non Descriptor Mode)
DataByteCount Number of bytes in the data portion of the SPI cycle.
Buffer Pointer to caller-allocated buffer containing the dada received or sent during the SPI cycle.
SpiRegionType SPI Region type. Values EnumSpiRegionBios, EnumSpiRegionGbE, EnumSpiRegionMe,
EnumSpiRegionDescriptor, and EnumSpiRegionPlatformData are only applicable in
Descriptor mode. Value EnumSpiRegionAll is applicable to both Descriptor Mode
and Non Descriptor Mode, which indicates "SpiRegionOffset" is actually relative
to base of the 1st flash device (i.e., it is a Flash Linear Address).
Returns:
EFI_SUCCESS Command succeed.
EFI_INVALID_PARAMETER The parameters specified are not valid.
EFI_UNSUPPORTED Command not supported.
EFI_DEVICE_ERROR Device error, command aborts abnormally.
--*/
typedef
EFI_STATUS
(EFIAPI *EFI_SPI_INFO) (
IN EFI_SPI_PROTOCOL *This,
OUT SPI_INIT_INFO **InitInfoPtr
);
/*++
Routine Description:
Return info about SPI host controller, to help callers usage of Execute
service.
If 0xff is returned as an opcode index in init info struct
then device does not support the operation.
Arguments:
This Pointer to the EFI_SPI_PROTOCOL instance.
InitInfoPtr Pointer to init info written to this memory location.
Returns:
EFI_SUCCESS Information returned.
EFI_INVALID_PARAMETER Invalid parameter.
EFI_NOT_READY Required resources not setup.
Others Unexpected error happened.
--*/
//
// Protocol definition
//
struct _EFI_SPI_PROTOCOL {
EFI_SPI_INIT Init;
EFI_SPI_LOCK Lock;
EFI_SPI_EXECUTE Execute;
EFI_SPI_INFO Info;
};
#endif

View File

@@ -0,0 +1,183 @@
/** @file
Macros to simplify and abstract the interface to PCI configuration.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _QNC_ACCESS_H_
#define _QNC_ACCESS_H_
#include "QuarkNcSocId.h"
#include "QNCCommonDefinitions.h"
#define EFI_LPC_PCI_ADDRESS( Register ) \
EFI_PCI_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, Register)
//
// QNC Controller PCI access macros
//
#define QNC_RCRB_BASE (QNCMmio32 (PciDeviceMmBase (0, PCI_DEVICE_NUMBER_QNC_LPC, 0), R_QNC_LPC_RCBA) & B_QNC_LPC_RCBA_MASK)
//
// Device 0x1f, Function 0
//
#define LpcPciCfg32( Register ) \
QNCMmPci32(0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register )
#define LpcPciCfg32Or( Register, OrData ) \
QNCMmPci32Or( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData )
#define LpcPciCfg32And( Register, AndData ) \
QNCMmPci32And( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData )
#define LpcPciCfg32AndThenOr( Register, AndData, OrData ) \
QNCMmPci32AndThenOr( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData )
#define LpcPciCfg16( Register ) \
QNCMmPci16( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register )
#define LpcPciCfg16Or( Register, OrData ) \
QNCMmPci16Or( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData )
#define LpcPciCfg16And( Register, AndData ) \
QNCMmPci16And( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData )
#define LpcPciCfg16AndThenOr( Register, AndData, OrData ) \
QNCMmPci16AndThenOr( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData )
#define LpcPciCfg8( Register ) \
QNCMmPci8( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register )
#define LpcPciCfg8Or( Register, OrData ) \
QNCMmPci8Or( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, OrData )
#define LpcPciCfg8And( Register, AndData ) \
QNCMmPci8And( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData )
#define LpcPciCfg8AndThenOr( Register, AndData, OrData ) \
QNCMmPci8AndThenOr( 0,PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, Register, AndData, OrData )
//
// Root Complex Register Block
//
#define MmRcrb32( Register ) \
QNCMmio32( QNC_RCRB_BASE, Register )
#define MmRcrb32Or( Register, OrData ) \
QNCMmio32Or( QNC_RCRB_BASE, Register, OrData )
#define MmRcrb32And( Register, AndData ) \
QNCMmio32And( QNC_RCRB_BASE, Register, AndData )
#define MmRcrb32AndThenOr( Register, AndData, OrData ) \
QNCMmio32AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData )
#define MmRcrb16( Register ) \
QNCMmio16( QNC_RCRB_BASE, Register )
#define MmRcrb16Or( Register, OrData ) \
QNCMmio16Or( QNC_RCRB_BASE, Register, OrData )
#define MmRcrb16And( Register, AndData ) \
QNCMmio16And( QNC_RCRB_BASE, Register, AndData )
#define MmRcrb16AndThenOr( Register, AndData, OrData ) \
QNCMmio16AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData )
#define MmRcrb8( Register ) \
QNCMmio8( QNC_RCRB_BASE, Register )
#define MmRcrb8Or( Register, OrData ) \
QNCMmio8Or( QNC_RCRB_BASE, Register, OrData )
#define MmRcrb8And( Register, AndData ) \
QNCMmio8And( QNC_RCRB_BASE, Register, AndData )
#define MmRcrb8AndThenOr( Register, AndData, OrData ) \
QNCMmio8AndThenOr( QNC_RCRB_BASE, Register, AndData, OrData )
//
// Memory Controller PCI access macros
//
//
// Device 0, Function 0
//
#define McD0PciCfg64(Register) QNCMmPci32 (0, MC_BUS, 0, 0, Register)
#define McD0PciCfg64Or(Register, OrData) QNCMmPci32Or (0, MC_BUS, 0, 0, Register, OrData)
#define McD0PciCfg64And(Register, AndData) QNCMmPci32And (0, MC_BUS, 0, 0, Register, AndData)
#define McD0PciCfg64AndThenOr(Register, AndData, OrData) QNCMmPci32AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData)
#define McD0PciCfg32(Register) QNCMmPci32 (0, MC_BUS, 0, 0, Register)
#define McD0PciCfg32Or(Register, OrData) QNCMmPci32Or (0, MC_BUS, 0, 0, Register, OrData)
#define McD0PciCfg32And(Register, AndData) QNCMmPci32And (0, MC_BUS, 0, 0, Register, AndData)
#define McD0PciCfg32AndThenOr(Register, AndData, OrData) QNCMmPci32AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData)
#define McD0PciCfg16(Register) QNCMmPci16 (0, MC_BUS, 0, 0, Register)
#define McD0PciCfg16Or(Register, OrData) QNCMmPci16Or (0, MC_BUS, 0, 0, Register, OrData)
#define McD0PciCfg16And(Register, AndData) QNCMmPci16And (0, MC_BUS, 0, 0, Register, AndData)
#define McD0PciCfg16AndThenOr(Register, AndData, OrData) QNCMmPci16AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData)
#define McD0PciCfg8(Register) QNCMmPci8 (0, MC_BUS, 0, 0, Register)
#define McD0PciCfg8Or(Register, OrData) QNCMmPci8Or (0, MC_BUS, 0, 0, Register, OrData)
#define McD0PciCfg8And(Register, AndData) QNCMmPci8And (0, MC_BUS, 0, 0, Register, AndData)
#define McD0PciCfg8AndThenOr( Register, AndData, OrData ) QNCMmPci8AndThenOr (0, MC_BUS, 0, 0, Register, AndData, OrData)
//
// Memory Controller Hub Memory Mapped IO register access ???
//
#define MCH_REGION_BASE (McD0PciCfg64 (MC_MCHBAR_OFFSET) & ~BIT0)
#define McMmioAddress(Register) ((UINTN) MCH_REGION_BASE + (UINTN) (Register))
#define McMmio32Ptr(Register) ((volatile UINT32*) McMmioAddress (Register))
#define McMmio64Ptr(Register) ((volatile UINT64*) McMmioAddress (Register))
#define McMmio64(Register) *McMmio64Ptr( Register )
#define McMmio64Or(Register, OrData) (McMmio64 (Register) |= (UINT64)(OrData))
#define McMmio64And(Register, AndData) (McMmio64 (Register) &= (UINT64)(AndData))
#define McMmio64AndThenOr(Register, AndData, OrData) (McMmio64 ( Register ) = (McMmio64( Register ) & (UINT64)(AndData)) | (UINT64)(OrData))
#define McMmio32(Register) *McMmio32Ptr (Register)
#define McMmio32Or(Register, OrData) (McMmio32 (Register) |= (UINT32)(OrData))
#define McMmio32And(Register, AndData) (McMmio32 (Register) &= (UINT32)(AndData))
#define McMmio32AndThenOr(Register, AndData, OrData) (McMmio32 (Register) = (McMmio32 (Register) & (UINT32) (AndData)) | (UINT32) (OrData))
#define McMmio16Ptr(Register) ((volatile UINT16*) McMmioAddress (Register))
#define McMmio16(Register) *McMmio16Ptr (Register)
#define McMmio16Or(Register, OrData) (McMmio16 (Register) |= (UINT16) (OrData))
#define McMmio16And(Register, AndData) (McMmio16 (Register) &= (UINT16) (AndData))
#define McMmio16AndThenOr(Register, AndData, OrData) (McMmio16 (Register) = (McMmio16 (Register) & (UINT16) (AndData)) | (UINT16) (OrData))
#define McMmio8Ptr(Register) ((volatile UINT8 *)McMmioAddress (Register))
#define McMmio8(Register) *McMmio8Ptr (Register)
#define McMmio8Or(Register, OrData) (McMmio8 (Register) |= (UINT8) (OrData))
#define McMmio8And(Register, AndData) (McMmio8 (Register) &= (UINT8) (AndData))
#define McMmio8AndThenOr(Register, AndData, OrData) (McMmio8 (Register) = (McMmio8 (Register) & (UINT8) (AndData)) | (UINT8) (OrData))
//
// QNC memory mapped related data structure deifinition
//
typedef enum {
QNCMmioWidthUint8 = 0,
QNCMmioWidthUint16 = 1,
QNCMmioWidthUint32 = 2,
QNCMmioWidthUint64 = 3,
QNCMmioWidthMaximum
} QNC_MEM_IO_WIDTH;
#endif

View File

@@ -0,0 +1,356 @@
/** @file
This header file provides common definitions just for MCH using to avoid including extra module's file.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _QNC_COMMON_DEFINITIONS_H_
#define _QNC_COMMON_DEFINITIONS_H_
//
// PCI CONFIGURATION MAP REGISTER OFFSETS
//
#ifndef PCI_VID
#define PCI_VID 0x0000 // Vendor ID Register
#define PCI_DID 0x0002 // Device ID Register
#define PCI_CMD 0x0004 // PCI Command Register
#define PCI_STS 0x0006 // PCI Status Register
#define PCI_RID 0x0008 // Revision ID Register
#define PCI_IFT 0x0009 // Interface Type
#define PCI_SCC 0x000A // Sub Class Code Register
#define PCI_BCC 0x000B // Base Class Code Register
#define PCI_CLS 0x000C // Cache Line Size
#define PCI_PMLT 0x000D // Primary Master Latency Timer
#define PCI_HDR 0x000E // Header Type Register
#define PCI_BIST 0x000F // Built in Self Test Register
#define PCI_BAR0 0x0010 // Base Address Register 0
#define PCI_BAR1 0x0014 // Base Address Register 1
#define PCI_BAR2 0x0018 // Base Address Register 2
#define PCI_PBUS 0x0018 // Primary Bus Number Register
#define PCI_SBUS 0x0019 // Secondary Bus Number Register
#define PCI_SUBUS 0x001A // Subordinate Bus Number Register
#define PCI_SMLT 0x001B // Secondary Master Latency Timer
#define PCI_BAR3 0x001C // Base Address Register 3
#define PCI_IOBASE 0x001C // I/O base Register
#define PCI_IOLIMIT 0x001D // I/O Limit Register
#define PCI_SECSTATUS 0x001E // Secondary Status Register
#define PCI_BAR4 0x0020 // Base Address Register 4
#define PCI_MEMBASE 0x0020 // Memory Base Register
#define PCI_MEMLIMIT 0x0022 // Memory Limit Register
#define PCI_BAR5 0x0024 // Base Address Register 5
#define PCI_PRE_MEMBASE 0x0024 // Prefetchable memory Base register
#define PCI_PRE_MEMLIMIT 0x0026 // Prefetchable memory Limit register
#define PCI_PRE_MEMBASE_U 0x0028 // Prefetchable memory base upper 32 bits
#define PCI_PRE_MEMLIMIT_U 0x002C // Prefetchable memory limit upper 32 bits
#define PCI_SVID 0x002C // Subsystem Vendor ID
#define PCI_SID 0x002E // Subsystem ID
#define PCI_IOBASE_U 0x0030 // I/O base Upper Register
#define PCI_IOLIMIT_U 0x0032 // I/O Limit Upper Register
#define PCI_CAPP 0x0034 // Capabilities Pointer
#define PCI_EROM 0x0038 // Expansion ROM Base Address
#define PCI_INTLINE 0x003C // Interrupt Line Register
#define PCI_INTPIN 0x003D // Interrupt Pin Register
#define PCI_MAXGNT 0x003E // Max Grant Register
#define PCI_BRIDGE_CNTL 0x003E // Bridge Control Register
#define PCI_MAXLAT 0x003F // Max Latency Register
#endif
//
// Bit Difinitions
//
#ifndef BIT0
#define BIT0 0x0001
#define BIT1 0x0002
#define BIT2 0x0004
#define BIT3 0x0008
#define BIT4 0x0010
#define BIT5 0x0020
#define BIT6 0x0040
#define BIT7 0x0080
#define BIT8 0x0100
#define BIT9 0x0200
#define BIT10 0x0400
#define BIT11 0x0800
#define BIT12 0x1000
#define BIT13 0x2000
#define BIT14 0x4000
#define BIT15 0x8000
#define BIT16 0x00010000
#define BIT17 0x00020000
#define BIT18 0x00040000
#define BIT19 0x00080000
#define BIT20 0x00100000
#define BIT21 0x00200000
#define BIT22 0x00400000
#define BIT23 0x00800000
#define BIT24 0x01000000
#define BIT25 0x02000000
#define BIT26 0x04000000
#define BIT27 0x08000000
#define BIT28 0x10000000
#define BIT29 0x20000000
#define BIT30 0x40000000
#define BIT31 0x80000000
#endif
//
// Common Memory mapped Io access macros ------------------------------------------
//
#define QNCMmioAddress( BaseAddr, Register ) \
( (UINTN)BaseAddr + \
(UINTN)(Register) \
)
//
// UINT64
//
#define QNCMmio64Ptr( BaseAddr, Register ) \
( (volatile UINT64 *)QNCMmioAddress( BaseAddr, Register ) )
#define QNCMmio64( BaseAddr, Register ) \
*QNCMmio64Ptr( BaseAddr, Register )
#define QNCMmio64Or( BaseAddr, Register, OrData ) \
QNCMmio64( BaseAddr, Register ) = \
(UINT64) ( \
QNCMmio64( BaseAddr, Register ) | \
(UINT64)(OrData) \
)
#define QNCMmio64And( BaseAddr, Register, AndData ) \
QNCMmio64( BaseAddr, Register ) = \
(UINT64) ( \
QNCMmio64( BaseAddr, Register ) & \
(UINT64)(AndData) \
)
#define QNCMmio64AndThenOr( BaseAddr, Register, AndData, OrData ) \
QNCMmio64( BaseAddr, Register ) = \
(UINT64) ( \
( QNCMmio64( BaseAddr, Register ) & \
(UINT64)(AndData) \
) | \
(UINT64)(OrData) \
)
//
// UINT32
//
#define QNCMmio32Ptr( BaseAddr, Register ) \
( (volatile UINT32 *)QNCMmioAddress( BaseAddr, Register ) )
#define QNCMmio32( BaseAddr, Register ) \
*QNCMmio32Ptr( BaseAddr, Register )
#define QNCMmio32Or( BaseAddr, Register, OrData ) \
QNCMmio32( BaseAddr, Register ) = \
(UINT32) ( \
QNCMmio32( BaseAddr, Register ) | \
(UINT32)(OrData) \
)
#define QNCMmio32And( BaseAddr, Register, AndData ) \
QNCMmio32( BaseAddr, Register ) = \
(UINT32) ( \
QNCMmio32( BaseAddr, Register ) & \
(UINT32)(AndData) \
)
#define QNCMmio32AndThenOr( BaseAddr, Register, AndData, OrData ) \
QNCMmio32( BaseAddr, Register ) = \
(UINT32) ( \
( QNCMmio32( BaseAddr, Register ) & \
(UINT32)(AndData) \
) | \
(UINT32)(OrData) \
)
//
// UINT16
//
#define QNCMmio16Ptr( BaseAddr, Register ) \
( (volatile UINT16 *)QNCMmioAddress( BaseAddr, Register ) )
#define QNCMmio16( BaseAddr, Register ) \
*QNCMmio16Ptr( BaseAddr, Register )
#define QNCMmio16Or( BaseAddr, Register, OrData ) \
QNCMmio16( BaseAddr, Register ) = \
(UINT16) ( \
QNCMmio16( BaseAddr, Register ) | \
(UINT16)(OrData) \
)
#define QNCMmio16And( BaseAddr, Register, AndData ) \
QNCMmio16( BaseAddr, Register ) = \
(UINT16) ( \
QNCMmio16( BaseAddr, Register ) & \
(UINT16)(AndData) \
)
#define QNCMmio16AndThenOr( BaseAddr, Register, AndData, OrData ) \
QNCMmio16( BaseAddr, Register ) = \
(UINT16) ( \
( QNCMmio16( BaseAddr, Register ) & \
(UINT16)(AndData) \
) | \
(UINT16)(OrData) \
)
//
// UINT8
//
#define QNCMmio8Ptr( BaseAddr, Register ) \
( (volatile UINT8 *)QNCMmioAddress( BaseAddr, Register ) )
#define QNCMmio8( BaseAddr, Register ) \
*QNCMmio8Ptr( BaseAddr, Register )
#define QNCMmio8Or( BaseAddr, Register, OrData ) \
QNCMmio8( BaseAddr, Register ) = \
(UINT8) ( \
QNCMmio8( BaseAddr, Register ) | \
(UINT8)(OrData) \
)
#define QNCMmio8And( BaseAddr, Register, AndData ) \
QNCMmio8( BaseAddr, Register ) = \
(UINT8) ( \
QNCMmio8( BaseAddr, Register ) & \
(UINT8)(AndData) \
)
#define QNCMmio8AndThenOr( BaseAddr, Register, AndData, OrData ) \
QNCMmio8( BaseAddr, Register ) = \
(UINT8) ( \
( QNCMmio8( BaseAddr, Register ) & \
(UINT8)(AndData) \
) | \
(UINT8)(OrData) \
)
//
// Common Memory mapped Pci access macros ------------------------------------------
//
#define QNCMmPciAddress( Segment, Bus, Device, Function, Register ) \
( (UINTN) QncGetPciExpressBaseAddress() + \
(UINTN)(Bus << 20) + \
(UINTN)(Device << 15) + \
(UINTN)(Function << 12) + \
(UINTN)(Register) \
)
//
// Macro to calculate the Pci device's base memory mapped address
//
#define PciDeviceMmBase( Bus, Device, Function) \
( (UINTN) QncGetPciExpressBaseAddress () + \
(UINTN)(Bus << 20) + \
(UINTN)(Device << 15) + \
(UINTN)(Function << 12) \
)
//
// UINT32
//
#define QNCMmPci32Ptr( Segment, Bus, Device, Function, Register ) \
( (volatile UINT32 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) )
#define QNCMmPci32( Segment, Bus, Device, Function, Register ) \
*QNCMmPci32Ptr( Segment, Bus, Device, Function, Register )
#define QNCMmPci32Or( Segment, Bus, Device, Function, Register, OrData ) \
QNCMmPci32( Segment, Bus, Device, Function, Register ) = \
(UINT32) ( \
QNCMmPci32( Segment, Bus, Device, Function, Register ) | \
(UINT32)(OrData) \
)
#define QNCMmPci32And( Segment, Bus, Device, Function, Register, AndData ) \
QNCMmPci32( Segment, Bus, Device, Function, Register ) = \
(UINT32) ( \
QNCMmPci32( Segment, Bus, Device, Function, Register ) & \
(UINT32)(AndData) \
)
#define QNCMmPci32AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
QNCMmPci32( Segment, Bus, Device, Function, Register ) = \
(UINT32) ( \
( QNCMmPci32( Segment, Bus, Device, Function, Register ) & \
(UINT32)(AndData) \
) | \
(UINT32)(OrData) \
)
//
// UINT16
//
#define QNCMmPci16Ptr( Segment, Bus, Device, Function, Register ) \
( (volatile UINT16 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) )
#define QNCMmPci16( Segment, Bus, Device, Function, Register ) \
*QNCMmPci16Ptr( Segment, Bus, Device, Function, Register )
#define QNCMmPci16Or( Segment, Bus, Device, Function, Register, OrData ) \
QNCMmPci16( Segment, Bus, Device, Function, Register ) = \
(UINT16) ( \
QNCMmPci16( Segment, Bus, Device, Function, Register ) | \
(UINT16)(OrData) \
)
#define QNCMmPci16And( Segment, Bus, Device, Function, Register, AndData ) \
QNCMmPci16( Segment, Bus, Device, Function, Register ) = \
(UINT16) ( \
QNCMmPci16( Segment, Bus, Device, Function, Register ) & \
(UINT16)(AndData) \
)
#define QNCMmPci16AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
QNCMmPci16( Segment, Bus, Device, Function, Register ) = \
(UINT16) ( \
( QNCMmPci16( Segment, Bus, Device, Function, Register ) & \
(UINT16)(AndData) \
) | \
(UINT16)(OrData) \
)
//
// UINT8
//
#define QNCMmPci8Ptr( Segment, Bus, Device, Function, Register ) \
( (volatile UINT8 *)QNCMmPciAddress( Segment, Bus, Device, Function, Register ) )
#define QNCMmPci8( Segment, Bus, Device, Function, Register ) \
*QNCMmPci8Ptr( Segment, Bus, Device, Function, Register )
#define QNCMmPci8Or( Segment, Bus, Device, Function, Register, OrData ) \
QNCMmPci8( Segment, Bus, Device, Function, Register ) = \
(UINT8) ( \
QNCMmPci8( Segment, Bus, Device, Function, Register ) | \
(UINT8)(OrData) \
)
#define QNCMmPci8And( Segment, Bus, Device, Function, Register, AndData ) \
QNCMmPci8( Segment, Bus, Device, Function, Register ) = \
(UINT8) ( \
QNCMmPci8( Segment, Bus, Device, Function, Register ) & \
(UINT8)(AndData) \
)
#define QNCMmPci8AndThenOr( Segment, Bus, Device, Function, Register, AndData, OrData ) \
QNCMmPci8( Segment, Bus, Device, Function, Register ) = \
(UINT8) ( \
( QNCMmPci8( Segment, Bus, Device, Function, Register ) & \
(UINT8)(AndData) \
) | \
(UINT8)(OrData) \
)
#endif

View File

@@ -0,0 +1,757 @@
/** @file
QuarkNcSocId Register Definitions
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Definitions beginning with "R_" are registers
Definitions beginning with "B_" are bits within registers
Definitions beginning with "V_" are meaningful values of bits within the registers
Definitions beginning with "S_" are register sizes
Definitions beginning with "N_" are the bit position
**/
#ifndef _QUARK_NC_SOC_ID_H_
#define _QUARK_NC_SOC_ID_H_
//
// QNC GMCH Equates
//
//
// DEVICE 0 (Memroy Controller Hub)
//
#define MC_BUS PCI_BUS_NUMBER_QNC
#define MC_DEV 0x00
#define MC_FUN 0x00
#define QUARK_MC_VENDOR_ID V_INTEL_VENDOR_ID
#define QUARK_MC_DEVICE_ID 0x0958
#define QUARK2_MC_DEVICE_ID 0x12C0
#define QNC_MC_REV_ID_A0 0x00
//
// MCR - B0:D0:F0:RD0h (WO)- Message control register
// [31:24] Message opcode - D0 read; E0 write;
// [23:16] Message port
// [15:8 ] Message target register address
// [ 7:4 ] Message write byte enable : F is enable
// [ 3:0 ] Reserved
//
#define QNC_ACCESS_PORT_MCR 0xD0 // Message Control Register
// Always Set to 0xF0
//
//MDR - B0:D0:F0:RD4h (RW)- Message data register
//
#define QNC_ACCESS_PORT_MDR 0xD4 // Message Data Register
//
//MEA - B0:D0:F0:RD8h (RW)- Message extended address register
//
#define QNC_ACCESS_PORT_MEA 0xD8 // Message Extended Address Register
#define QNC_MCR_OP_OFFSET 24 // Offset of the opcode field in MCR
#define QNC_MCR_PORT_OFFSET 16 // Offset of the port field in MCR
#define QNC_MCR_REG_OFFSET 8 // Offset of the register field in MCR
//
// Misc Useful Macros
//
#define LShift16(value) (value << 16)
//
// QNC Message OpCodes and Attributes
//
#define QUARK_OPCODE_READ 0x10 // Quark message bus "read" opcode
#define QUARK_OPCODE_WRITE 0x11 // Quark message bus "write" opcode
//
// Alternative opcodes for the SCSS block
//
#define QUARK_ALT_OPCODE_READ 0x06 // Quark message bus "read" opcode
#define QUARK_ALT_OPCODE_WRITE 0x07 // Quark message bus "write" opcode
//
// QNC Message OpCodes and Attributes for IO
//
#define QUARK_OPCODE_IO_READ 0x02 // Quark message bus "IO read" opcode
#define QUARK_OPCODE_IO_WRITE 0x03 // Quark message bus "IO write" opcode
#define QUARK_DRAM_BASE_ADDR_READY 0x78 // Quark message bus "RMU Main binary shadow" opcode
#define QUARK_ECC_SCRUB_RESUME 0xC2 // Quark Remote Management Unit "scrub resume" opcode
#define QUARK_ECC_SCRUB_PAUSE 0xC3 // Quark Remote Management Unit "scrub pause" opcode
//
// QNC Message Ports and Registers
//
// Start of SB Port IDs
#define QUARK_NC_MEMORY_ARBITER_SB_PORT_ID 0x00
#define QUARK_NC_MEMORY_CONTROLLER_SB_PORT_ID 0x01
#define QUARK_NC_HOST_BRIDGE_SB_PORT_ID 0x03
#define QUARK_NC_RMU_SB_PORT_ID 0x04
#define QUARK_NC_MEMORY_MANAGER_SB_PORT_ID 0x05
#define QUARK_SC_USB_AFE_SB_PORT_ID 0x14
#define QUARK_SC_PCIE_AFE_SB_PORT_ID 0x16
#define QUARK_SCSS_SOC_UNIT_SB_PORT_ID 0x31
#define QUARK_SCSS_FUSE_SB_PORT_ID 0x33
#define QUARK_ICLK_SB_PORT_ID 0x32
#define QUARK_SCSS_CRU_SB_PORT_ID 0x34
//
// Quark Memory Arbiter Registers.
//
#define QUARK_NC_MEMORY_ARBITER_REG_ASTATUS 0x21 // Memory Arbiter PRI Status encodings register.
#define ASTATUS_PRI_CASUAL 0x0 // Serviced only if convenient
#define ASTATUS_PRI_IMPENDING 0x1 // Serviced if the DRAM is in Self-Refresh.
#define ASTATUS_PRI_NORMAL 0x2 // Normal request servicing.
#define ASTATUS_PRI_URGENT 0x3 // Urgent request servicing.
#define ASTATUS1_RASISED_BP (10)
#define ASTATUS1_RASISED_BP_MASK (0x03 << ASTATUS1_RASISED_BP)
#define ASTATUS0_RASISED_BP (8)
#define ASTATUS0_RASISED_BP_MASK (0x03 << ASTATUS1_RASISED_BP)
#define ASTATUS1_DEFAULT_BP (2)
#define ASTATUS1_DEFAULT_BP_MASK (0x03 << ASTATUS1_RASISED_BP)
#define ASTATUS0_DEFAULT_BP (0)
#define ASTATUS0_DEFAULT_BP_MASK (0x03 << ASTATUS1_RASISED_BP)
//
// Quark Memory Controller Registers.
//
#define QUARK_NC_MEMORY_CONTROLLER_REG_DFUSESTAT 0x70 // Fuse status register.
#define B_DFUSESTAT_ECC_DIS (BIT0) // Disable ECC.
//
// Quark Remote Management Unit Registers.
//
#define QNC_MSG_TMPM_REG_PMBA 0x70 // Power Management I/O Base Address
#define QUARK_NC_RMU_REG_CONFIG 0x71 // Remote Management Unit configuration register.
#define TS_LOCK_AUX_TRIP_PT_REGS_ENABLE (BIT6)
#define TS_LOCK_THRM_CTRL_REGS_ENABLE (BIT5)
#define QUARK_NC_RMU_REG_OPTIONS_1 0x72 // Remote Management Unit Options register 1.
#define OPTIONS_1_DMA_DISABLE (BIT0)
#define QUARK_NC_RMU_REG_WDT_CONTROL 0x74 // Remote Management Unit Watchdog control register.
#define B_WDT_CONTROL_DBL_ECC_BIT_ERR_MASK (BIT19 | BIT18)
#define B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP 18
#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_NONE (0x0 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)
#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_CAT (0x1 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)
#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_WARM (0x2 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)
#define V_WDT_CONTROL_DBL_ECC_BIT_ERR_SERR (0x3 << B_WDT_CONTROL_DBL_ECC_BIT_ERR_BP)
#define QUARK_NC_RMU_REG_TS_MODE 0xB0 // Remote Management Unit Thermal sensor mode register.
#define TS_ENABLE (BIT15)
#define QUARK_NC_RMU_REG_TS_TRIP 0xB2 // Remote Management Unit Thermal sensor programmable trip point register.
#define TS_HOT_TRIP_CLEAR_THOLD_BP 24
#define TS_HOT_TRIP_CLEAR_THOLD_MASK (0xFF << TS_HOT_TRIP_CLEAR_THOLD_BP)
#define TS_CAT_TRIP_CLEAR_THOLD_BP 16
#define TS_CAT_TRIP_CLEAR_THOLD_MASK (0xFF << TS_CAT_TRIP_CLEAR_THOLD_BP)
#define TS_HOT_TRIP_SET_THOLD_BP 8
#define TS_HOT_TRIP_SET_THOLD_MASK (0xFF << TS_HOT_TRIP_SET_THOLD_BP)
#define TS_CAT_TRIP_SET_THOLD_BP 0
#define TS_CAT_TRIP_SET_THOLD_MASK (0xFF << TS_CAT_TRIP_SET_THOLD_BP)
#define QUARK_NC_ECC_SCRUB_CONFIG_REG 0x50
#define SCRUB_CFG_INTERVAL_SHIFT 0x00
#define SCRUB_CFG_INTERVAL_MASK 0xFF
#define SCRUB_CFG_BLOCKSIZE_SHIFT 0x08
#define SCRUB_CFG_BLOCKSIZE_MASK 0x1F
#define SCRUB_CFG_ACTIVE (BIT13)
#define SCRUB_CFG_INVALID 0x00000FFF
#define QUARK_NC_ECC_SCRUB_START_MEM_REG 0x76
#define QUARK_NC_ECC_SCRUB_END_MEM_REG 0x77
#define QUARK_NC_ECC_SCRUB_NEXT_READ_REG 0x7C
#define SCRUB_RESUME_MSG() ((UINT32)( \
(QUARK_ECC_SCRUB_RESUME << QNC_MCR_OP_OFFSET) | \
(QUARK_NC_RMU_SB_PORT_ID << QNC_MCR_PORT_OFFSET) | \
0xF0))
#define SCRUB_PAUSE_MSG() ((UINT32)( \
(QUARK_ECC_SCRUB_PAUSE << QNC_MCR_OP_OFFSET) | \
(QUARK_NC_RMU_SB_PORT_ID << QNC_MCR_PORT_OFFSET) | \
0xF0))
//
// Quark Memory Manager Registers
//
#define QUARK_NC_MEMORY_MANAGER_ESRAMPGCTRL_BLOCK 0x82
#define BLOCK_ENABLE_PG (1 << 28)
#define BLOCK_DISABLE_PG (1 << 29)
#define QUARK_NC_MEMORY_MANAGER_BIMRVCTL 0x19
#define EnableIMRInt BIT31
#define QUARK_NC_MEMORY_MANAGER_BSMMVCTL 0x1C
#define EnableSMMInt BIT31
#define QUARK_NC_MEMORY_MANAGER_BTHCTRL 0x20
#define DRAM_NON_HOST_RQ_LIMIT_BP 0
#define DRAM_NON_HOST_RQ_LIMIT_MASK (0x3f << DRAM_NON_HOST_RQ_LIMIT_BP)
#define QUARK_NC_TOTAL_IMR_SET 0x8
#define QUARK_NC_MEMORY_MANAGER_IMR0 0x40
#define QUARK_NC_MEMORY_MANAGER_IMR1 0x44
#define QUARK_NC_MEMORY_MANAGER_IMR2 0x48
#define QUARK_NC_MEMORY_MANAGER_IMR3 0x4C
#define QUARK_NC_MEMORY_MANAGER_IMR4 0x50
#define QUARK_NC_MEMORY_MANAGER_IMR5 0x54
#define QUARK_NC_MEMORY_MANAGER_IMR6 0x58
#define QUARK_NC_MEMORY_MANAGER_IMR7 0x5C
#define QUARK_NC_MEMORY_MANAGER_IMRXL 0x00
#define IMR_LOCK BIT31
#define IMR_EN BIT30
#define IMRL_MASK 0x00FFFFFC
#define IMRL_RESET 0x00000000
#define QUARK_NC_MEMORY_MANAGER_IMRXH 0x01
#define IMRH_MASK 0x00FFFFFC
#define IMRH_RESET 0x00000000
#define QUARK_NC_MEMORY_MANAGER_IMRXRM 0x02
#define QUARK_NC_MEMORY_MANAGER_IMRXWM 0x03
#define IMRX_ALL_ACCESS 0xFFFFFFFF
#define CPU_SNOOP BIT30
#define RMU BIT29
#define CPU0_NON_SMM BIT0
//
// Quark Host Bridge Registers
//
#define QNC_MSG_FSBIC_REG_HMISC 0x03 // Host Misellaneous Controls
#define SMI_EN (BIT19) // SMI Global Enable (from Legacy Bridge)
#define QNC_MSG_FSBIC_REG_HSMMC 0x04 // Host SMM Control
#define NON_HOST_SMM_WR_OPEN (BIT18) // SMM Writes OPEN
#define NON_HOST_SMM_RD_OPEN (BIT17) // SMM Writes OPEN
#define SMM_CODE_RD_OPEN (BIT16) // SMM Code read OPEN
#define SMM_CTL_EN (BIT3) // SMM enable
#define SMM_WRITE_OPEN (BIT2) // SMM Writes OPEN
#define SMM_READ_OPEN (BIT1) // SMM Reads OPEN
#define SMM_LOCKED (BIT0) // SMM Locked
#define SMM_START_MASK 0x0000FFF0
#define SMM_END_MASK 0xFFF00000
#define QUARK_NC_HOST_BRIDGE_HMBOUND_REG 0x08
#define HMBOUND_MASK 0x0FFFFF000
#define HMBOUND_LOCK BIT0
#define QUARK_NC_HOST_BRIDGE_HLEGACY_REG 0x0A
#define HLEGACY_SMI_PIN_VALUE BIT12
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_CAP 0x40
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_DEF_TYPE 0x41
#define QUARK_NC_HOST_BRIDGE_MTRR_FIX64K_00000 0x42
#define QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_80000 0x44
#define QUARK_NC_HOST_BRIDGE_MTRR_FIX16K_A0000 0x46
#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C0000 0x48
#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_C8000 0x4A
#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D0000 0x4C
#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_D8000 0x4E
#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E0000 0x50
#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_E8000 0x52
#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F0000 0x54
#define QUARK_NC_HOST_BRIDGE_MTRR_FIX4K_F8000 0x56
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSBASE 0x58
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK 0x59
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE0 0x5A
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK0 0x5B
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE1 0x5C
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK1 0x5D
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE2 0x5E
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK2 0x5F
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE3 0x60
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK3 0x61
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE4 0x62
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK4 0x63
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE5 0x64
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK5 0x65
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE6 0x66
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK6 0x67
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSBASE7 0x68
#define QUARK_NC_HOST_BRIDGE_IA32_MTRR_PHYSMASK7 0x69
//
// System On Chip Unit (SOCUnit) Registers.
//
#define QUARK_SCSS_SOC_UNIT_STPDDRCFG 0x00
#define B_STPDDRCFG_FORCE_RECOVERY BIT0
#define QUARK_SCSS_SOC_UNIT_SPI_ROM_FUSE 0x25
#define B_ROM_FUSE_IN_SECURE_SKU BIT6
#define QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG 0x31
#define B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK (BIT5 | BIT4 | BIT3)
#define B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP 3
#define B_TSCGF1_CONFIG_ISNSCHOPSEL_MASK (BIT12 | BIT11 | BIT10 | BIT9 | BIT8)
#define B_TSCGF1_CONFIG_ISNSCHOPSEL_BP 8
#define B_TSCGF1_CONFIG_IBGEN BIT17
#define B_TSCGF1_CONFIG_IBGEN_BP 17
#define B_TSCGF1_CONFIG_IBGCHOPEN BIT18
#define B_TSCGF1_CONFIG_IBGCHOPEN_BP 18
#define B_TSCGF1_CONFIG_ISNSINTERNALVREFEN BIT14
#define B_TSCGF1_CONFIG_ISNSINTERNALVREFEN_BP 14
#define QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG 0x32
#define B_TSCGF2_CONFIG_IDSCONTROL_MASK 0x0000FFFF
#define B_TSCGF2_CONFIG_IDSCONTROL_BP 0
#define B_TSCGF2_CONFIG_IDSTIMING_MASK 0xFFFF0000
#define B_TSCGF2_CONFIG_IDSTIMING_BP 16
#define QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2 0x33
#define B_TSCGF2_CONFIG2_ISPARECTRL_MASK 0xFF000000
#define B_TSCGF2_CONFIG2_ISPARECTRL_BP 24
#define B_TSCGF2_CONFIG2_ICALCONFIGSEL_MASK (BIT9 | BIT8)
#define B_TSCGF2_CONFIG2_ICALCONFIGSEL_BP 8
#define B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK 0x000000FF
#define B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP 0
#define QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG 0x34
#define B_TSCGF3_CONFIG_ITSRST BIT0
#define B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP 11
#define B_TSCGF3_CONFIG_ITSGAMMACOEFF_MASK (0xFFF << B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP)
#define QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG 0x36
#define SOCCLKEN_CONFIG_PHY_I_SIDE_RST_L BIT20
#define SOCCLKEN_CONFIG_PHY_I_CMNRESET_L BIT19
#define SOCCLKEN_CONFIG_SBI_BB_RST_B BIT18
#define SOCCLKEN_CONFIG_SBI_RST_100_CORE_B BIT17
#define SOCCLKEN_CONFIG_BB_RST_B BIT16
#define QUARK_SCSS_SOC_UNIT_SOCCLKEN_CONFIG 0x36
#define QUARK_SCSS_SOC_UNIT_CFG_STICKY_RW 0x51
#define B_CFG_STICKY_RW_SMM_VIOLATION BIT0
#define B_CFG_STICKY_RW_HMB_VIOLATION BIT1
#define B_CFG_STICKY_RW_IMR_VIOLATION BIT2
#define B_CFG_STICKY_RW_DECC_VIOLATION BIT3
#define B_CFG_STICKY_RW_WARM_RST BIT4
#define B_CFG_STICKY_RW_FORCE_RECOVERY BIT9
#define B_CFG_STICKY_RW_VIOLATION (B_CFG_STICKY_RW_SMM_VIOLATION | B_CFG_STICKY_RW_HMB_VIOLATION | B_CFG_STICKY_RW_IMR_VIOLATION | B_CFG_STICKY_RW_DECC_VIOLATION)
#define B_CFG_STICKY_RW_ALL (B_CFG_STICKY_RW_VIOLATION | B_CFG_STICKY_RW_WARM_RST)
//
// iCLK Registers.
//
#define QUARK_ICLK_MUXTOP 0x0140
#define B_MUXTOP_FLEX2_MASK (BIT25 | BIT24 | BIT23)
#define B_MUXTOP_FLEX2_BP 23
#define B_MUXTOP_FLEX1_MASK (BIT22 | BIT21 | BIT20)
#define B_MUXTOP_FLEX1_BP 20
#define QUARK_ICLK_SSC1 0x0314
#define QUARK_ICLK_SSC2 0x0414
#define QUARK_ICLK_SSC3 0x0514
#define QUARK_ICLK_REF2_DBUFF0 0x2000
//
// PCIe AFE Unit Registers (QUARK_SC_PCIE_AFE_SB_PORT_ID).
//
#define QUARK_PCIE_AFE_PCIE_RXPICTRL0_L0 0x2080
#define QUARK_PCIE_AFE_PCIE_RXPICTRL0_L1 0x2180
#define OCFGPIMIXLOAD_1_0 BIT6
#define OCFGPIMIXLOAD_1_0_MASK 0xFFFFFF3F
//
// QNC ICH Equates
//
#define V_INTEL_VENDOR_ID 0x8086
#define PCI_BUS_NUMBER_QNC 0x00
//
// PCI to LPC Bridge Registers (D31:F0)
//
#define PCI_DEVICE_NUMBER_QNC_LPC 31
#define PCI_FUNCTION_NUMBER_QNC_LPC 0
#define R_QNC_LPC_VENDOR_ID 0x00
#define V_LPC_VENDOR_ID V_INTEL_VENDOR_ID
#define R_QNC_LPC_DEVICE_ID 0x02
#define QUARK_V_LPC_DEVICE_ID_0 0x095E
#define R_QNC_LPC_REV_ID 0x08
#define R_QNC_LPC_SMBUS_BASE 0x40 //~0x43
#define B_QNC_LPC_SMBUS_BASE_EN (BIT31)
#define B_QNC_LPC_SMBUS_BASE_MASK 0x0000FFC0 //[15:6]
//
// SMBus register offsets from SMBA - "SMBA" (D31:F0:R40h)
// Suggested Value for SMBA = 0x1040
//
#define R_QNC_SMBUS_HCTL 0x00 // Host Control Register R/W
#define B_QNC_SMBUS_START (BIT4) // Start/Stop
#define V_QNC_SMBUS_HCTL_CMD_QUICK 0
#define V_QNC_SMBUS_HCTL_CMD_BYTE 1
#define V_QNC_SMBUS_HCTL_CMD_BYTE_DATA 2
#define V_QNC_SMBUS_HCTL_CMD_WORD_DATA 3
#define V_QNC_SMBUS_HCTL_CMD_PROCESS_CALL 4
#define V_QNC_SMBUS_HCTL_CMD_BLOCK 5
#define R_QNC_SMBUS_HSTS 0x01 // Host Status Register R/W
#define B_QNC_SMBUS_BERR (BIT2) // BUS Error
#define B_QNC_SMBUS_DERR (BIT1) // Device Error
#define B_QNC_SMBUS_BYTE_DONE_STS (BIT0) // Completion Status
#define B_QNC_SMBUS_HSTS_ALL 0x07
#define R_QNC_SMBUS_HCLK 0x02 // Host Clock Divider Register R/W
#define V_QNC_SMBUS_HCLK_100KHZ 0x0054
#define R_QNC_SMBUS_TSA 0x04 // Transmit Slave Address Register R/W
#define V_QNC_SMBUS_RW_SEL_READ 1
#define V_QNC_SMBUS_RW_SEL_WRITE 0
#define R_QNC_SMBUS_HCMD 0x05 // Host Command Register R/W
#define R_QNC_SMBUS_HD0 0x06 // Data 0 Register R/W
#define R_QNC_SMBUS_HD1 0x07 // Data 1 Register R/W
#define R_QNC_SMBUS_HBD 0x20 // Host Block Data Register R/W [255:0] ~ 3Fh
#define R_QNC_LPC_GBA_BASE 0x44
#define B_QNC_LPC_GPA_BASE_MASK 0x0000FFC0
//
// GPIO register offsets from GBA - "GPIO" (D31:F0:R44h)
// Suggested Value for GBA = 0x1080
//
#define R_QNC_GPIO_CGEN_CORE_WELL 0x00
#define R_QNC_GPIO_CGIO_CORE_WELL 0x04
#define R_QNC_GPIO_CGLVL_CORE_WELL 0x08
#define R_QNC_GPIO_CGTPE_CORE_WELL 0x0C // Core well GPIO Trigger Positive Edge Enable
#define R_QNC_GPIO_CGTNE_CORE_WELL 0x10 // Core well GPIO Trigger Negative Edge Enable
#define R_QNC_GPIO_CGGPE_CORE_WELL 0x14 // Core well GPIO GPE Enable
#define R_QNC_GPIO_CGSMI_CORE_WELL 0x18 // Core well GPIO SMI Enable
#define R_QNC_GPIO_CGTS_CORE_WELL 0x1C // Core well GPIO Trigger Status
#define R_QNC_GPIO_RGEN_RESUME_WELL 0x20
#define R_QNC_GPIO_RGIO_RESUME_WELL 0x24
#define R_QNC_GPIO_RGLVL_RESUME_WELL 0x28
#define R_QNC_GPIO_RGTPE_RESUME_WELL 0x2C // Resume well GPIO Trigger Positive Edge Enable
#define R_QNC_GPIO_RGTNE_RESUME_WELL 0x30 // Resume well GPIO Trigger Negative Edge Enable
#define R_QNC_GPIO_RGGPE_RESUME_WELL 0x34 // Resume well GPIO GPE Enable
#define R_QNC_GPIO_RGSMI_RESUME_WELL 0x38 // Resume well GPIO SMI Enable
#define R_QNC_GPIO_RGTS_RESUME_WELL 0x3C // Resume well GPIO Trigger Status
#define R_QNC_GPIO_CNMIEN_CORE_WELL 0x40 // Core well GPIO NMI Enable
#define R_QNC_GPIO_RNMIEN_RESUME_WELL 0x44 // Resume well GPIO NMI Enable
#define R_QNC_LPC_PM1BLK 0x48
#define B_QNC_LPC_PM1BLK_MASK 0x0000FFF0
//
// ACPI register offsets from PM1BLK - "ACPI PM1 Block" (D31:F0:R48h)
// Suggested Value for PM1BLK = 0x1000
//
#define R_QNC_PM1BLK_PM1S 0x00
#define S_QNC_PM1BLK_PM1S 2
#define B_QNC_PM1BLK_PM1S_ALL (BIT15+BIT14+BIT10+BIT5+BIT0)
#define B_QNC_PM1BLK_PM1S_WAKE (BIT15)
#define B_QNC_PM1BLK_PM1S_PCIEWSTS (BIT14)
#define B_QNC_PM1BLK_PM1S_RTC (BIT10)
#define B_QNC_PM1BLK_PM1S_GLOB (BIT5)
#define B_QNC_PM1BLK_PM1S_TO (BIT0)
#define N_QNC_PM1BLK_PM1S_RTC 10
#define R_QNC_PM1BLK_PM1E 0x02
#define S_QNC_PM1BLK_PM1E 2
#define B_QNC_PM1BLK_PM1E_PWAKED (BIT14)
#define B_QNC_PM1BLK_PM1E_RTC (BIT10)
#define B_QNC_PM1BLK_PM1E_GLOB (BIT5)
#define N_QNC_PM1BLK_PM1E_RTC 10
#define R_QNC_PM1BLK_PM1C 0x04
#define B_QNC_PM1BLK_PM1C_SLPEN (BIT13)
#define B_QNC_PM1BLK_PM1C_SLPTP (BIT12+BIT11+BIT10)
#define V_S0 0x00000000
#define V_S3 0x00001400
#define V_S4 0x00001800
#define V_S5 0x00001C00
#define B_QNC_PM1BLK_PM1C_SCIEN (BIT0)
#define R_QNC_PM1BLK_PM1T 0x08
#define R_QNC_LPC_GPE0BLK 0x4C
#define B_QNC_LPC_GPE0BLK_MASK 0x0000FFC0
// Suggested Value for GPE0BLK = 0x10C0
//
#define R_QNC_GPE0BLK_GPE0S 0x00 // General Purpose Event 0 Status
#define S_QNC_GPE0BLK_GPE0S 4
#define B_QNC_GPE0BLK_GPE0S_ALL 0x00003F800 // used to clear the status reg
#define B_QNC_GPE0BLK_GPE0S_PCIE (BIT17) // PCIE
#define B_QNC_GPE0BLK_GPE0S_GPIO (BIT14) // GPIO
#define B_QNC_GPE0BLK_GPE0S_EGPE (BIT13) // External GPE
#define N_QNC_GPE0BLK_GPE0S_THRM 12
#define R_QNC_GPE0BLK_GPE0E 0x04 // General Purpose Event 0 Enable
#define S_QNC_GPE0BLK_GPE0E 4
#define B_QNC_GPE0BLK_GPE0E_PCIE (BIT17) // PCIE
#define B_QNC_GPE0BLK_GPE0E_GPIO (BIT14) // GPIO
#define B_QNC_GPE0BLK_GPE0E_EGPE (BIT13) // External GPE
#define N_QNC_GPE0BLK_GPE0E_THRM 12
#define R_QNC_GPE0BLK_SMIE 0x10 // SMI_B Enable
#define S_QNC_GPE0BLK_SMIE 4
#define B_QNC_GPE0BLK_SMIE_ALL 0x0003871F
#define B_QNC_GPE0BLK_SMIE_APM (BIT4) // APM
#define B_QNC_GPE0BLK_SMIE_SLP (BIT2) // Sleep
#define B_QNC_GPE0BLK_SMIE_SWT (BIT1) // Software Timer
#define N_QNC_GPE0BLK_SMIE_GPIO 9
#define N_QNC_GPE0BLK_SMIE_ESMI 8
#define N_QNC_GPE0BLK_SMIE_APM 4
#define N_QNC_GPE0BLK_SMIE_SPI 3
#define N_QNC_GPE0BLK_SMIE_SLP 2
#define N_QNC_GPE0BLK_SMIE_SWT 1
#define R_QNC_GPE0BLK_SMIS 0x14 // SMI Status Register.
#define S_QNC_GPE0BLK_SMIS 4
#define B_QNC_GPE0BLK_SMIS_ALL 0x0003871F
#define B_QNC_GPE0BLK_SMIS_EOS (BIT31) // End of SMI
#define B_QNC_GPE0BLK_SMIS_APM (BIT4) // APM
#define B_QNC_GPE0BLK_SMIS_SPI (BIT3) // SPI
#define B_QNC_GPE0BLK_SMIS_SLP (BIT2) // Sleep
#define B_QNC_GPE0BLK_SMIS_SWT (BIT1) // Software Timer
#define B_QNC_GPE0BLK_SMIS_BIOS (BIT0) // BIOS
#define N_QNC_GPE0BLK_SMIS_GPIO 9
#define N_QNC_GPE0BLK_SMIS_APM 4
#define N_QNC_GPE0BLK_SMIS_SPI 3
#define N_QNC_GPE0BLK_SMIS_SLP 2
#define N_QNC_GPE0BLK_SMIS_SWT 1
#define R_QNC_GPE0BLK_PMCW 0x28 // Power Management Configuration Core Well
#define B_QNC_GPE0BLK_PMCW_PSE (BIT31) // Periodic SMI Enable
#define R_QNC_GPE0BLK_PMSW 0x2C // Power Management Configuration Suspend/Resume Well
#define B_QNC_GPE0BLK_PMSW_DRAM_INIT (BIT0) // Dram Initialization Sctrachpad
#define R_QNC_LPC_ACTL 0x58
#define V_QNC_LPC_ACTL_SCIS_IRQ9 0x00
//
// Number of PIRQs supported. PIRQA~PIRQH
//
#define QNC_NUMBER_PIRQS 8
#define R_QNC_LPC_PIRQA_ROUT 0x60
#define R_QNC_LPC_PIRQB_ROUT 0x61
#define R_QNC_LPC_PIRQC_ROUT 0x62
#define R_QNC_LPC_PIRQD_ROUT 0x63
#define R_QNC_LPC_PIRQE_ROUT 0x64
#define R_QNC_LPC_PIRQF_ROUT 0x65
#define R_QNC_LPC_PIRQG_ROUT 0x66
#define R_QNC_LPC_PIRQH_ROUT 0x67
//
// Bit values are the same for R_TNC_LPC_PIRQA_ROUT to
// R_TNC_LPC_PIRQH_ROUT
#define B_QNC_LPC_PIRQX_ROUT (BIT3+BIT2+BIT1+BIT0)
#define R_QNC_LPC_WDTBA 0x84
// Watchdog Timer register offsets from WDTBASE (in R_QNC_LPC_WDTBA)------------BEGIN
#define R_QNC_LPC_WDT_WDTCR 0x10
#define R_QNC_LPC_WDT_WDTLR 0x18
// Watchdog Timer register offsets from WDTBASE (in R_QNC_LPC_WDTBA)--------------END
#define R_QNC_LPC_FWH_BIOS_DEC 0xD4
#define B_QNC_LPC_FWH_BIOS_DEC_F8 (BIT31)
#define B_QNC_LPC_FWH_BIOS_DEC_F0 (BIT30)
#define B_QNC_LPC_FWH_BIOS_DEC_E8 (BIT29)
#define B_QNC_LPC_FWH_BIOS_DEC_E0 (BIT28)
#define B_QNC_LPC_FWH_BIOS_DEC_D8 (BIT27)
#define B_QNC_LPC_FWH_BIOS_DEC_D0 (BIT26)
#define B_QNC_LPC_FWH_BIOS_DEC_C8 (BIT25)
#define B_QNC_LPC_FWH_BIOS_DEC_C0 (BIT24)
#define R_QNC_LPC_BIOS_CNTL 0xD8
#define S_QNC_LPC_BIOS_CNTL 4
#define B_QNC_LPC_BIOS_CNTL_PFE (BIT8)
#define B_QNC_LPC_BIOS_CNTL_SMM_BWP (BIT5)
#define B_QNC_LPC_BIOS_CNTL_BCD (BIT2)
#define B_QNC_LPC_BIOS_CNTL_BLE (BIT1)
#define B_QNC_LPC_BIOS_CNTL_BIOSWE (BIT0)
#define N_QNC_LPC_BIOS_CNTL_BLE 1
#define N_QNC_LPC_BIOS_CNTL_BIOSWE 0
#define R_QNC_LPC_RCBA 0xF0
#define B_QNC_LPC_RCBA_MASK 0xFFFFC000
#define B_QNC_LPC_RCBA_EN (BIT0)
//---------------------------------------------------------------------------
// Fixed IO Decode on QuarkNcSocId
//
// 20h(2B) 24h(2B) 28h(2B) 2Ch(2B) 30h(2B) 34h(2B) 38h(2B) 3Ch(2B) : R/W 8259 master
// 40h(3B): R/W 8254
// 43h(1B): W 8254
// 50h(3B): R/W 8254
// 53h(1B): W 8254
// 61h(1B): R/W NMI Controller
// 63h(1B): R/W NMI Controller - can be disabled
// 65h(1B): R/W NMI Controller - can be disabled
// 67h(1B): R/W NMI Controller - can be disabled
// 70h(1B): W NMI & RTC
// 71h(1B): R/W RTC
// 72h(1B): R RTC; W NMI&RTC
// 73h(1B): R/W RTC
// 74h(1B): R RTC; W NMI&RTC
// 75h(1B): R/W RTC
// 76h(1B): R RTC; W NMI&RTC
// 77h(1B): R/W RTC
// 84h(3B): R/W Internal/LPC
// 88h(1B): R/W Internal/LPC
// 8Ch(3B): R/W Internal/LPC
// A0h(2B) A4h(2B) A8h(2B) ACh(2B) B0h(2B) B4h(2B) B8h(2B) BCh(2B): R/W 8259 slave
// B2h(1B) B3h(1B): R/W Power management
// 3B0h-3BBh: R/W VGA
// 3C0h-3DFh: R/W VGA
// CF8h(4B): R/W Internal
// CF9h(1B): R/W LPC
// CFCh(4B): R/W Internal
//---------------------------------------------------------------------------
#define R_APM_CNT 0xB2
//
// Reset Generator I/O Port
//
#define RST_CNT 0xCF9
#define B_RST_CNT_COLD_RST (BIT3) // Cold reset
#define B_RST_CNT_WARM_RST (BIT1) // Warm reset
//
// Processor interface registers (NMI)
//
#define PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0 20
#define PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1 21
#define PCI_FUNCTION_NUMBER_QNC_IOSF2AHB 0
//
// Pci Express Root Ports (D23:F0/F1)
//
#define PCI_DEVICE_NUMBER_PCIE_ROOTPORT 23
#define PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 0
#define PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1 1
#define MAX_PCI_EXPRESS_ROOT_PORTS 2
#define R_QNC_PCIE_BNUM 0x18
#define R_QNC_PCIE_CAP_PTR 0x34
#define PCIE_CAPID 0x10 //PCIE Capability ID
#define PCIE_CAP_EXT_HEARDER_OFFSET 0x100 //PCIE Capability ID
#define PCIE_DEV_CAP_OFFSET 0x04 //PCIE Device Capability reg offset
#define PCIE_LINK_CAP_OFFSET 0x0C //PCIE Link Capability reg offset
#define PCIE_LINK_CNT_OFFSET 0x10 //PCIE Link control reg offset
#define PCIE_LINK_STS_OFFSET 0x12 //PCIE Link status reg offset
#define PCIE_SLOT_CAP_OFFSET 0x14 //PCIE Link Capability reg offset
#define R_QNC_PCIE_XCAP 0x42 //~ 43h
#define B_QNC_PCIE_XCAP_SI (BIT8) //slot implemented
#define R_QNC_PCIE_DCAP 0x44 //~ 47h
#define B_QNC_PCIE_DCAP_E1AL (BIT11 | BIT10 | BIT9) // L1 Acceptable exit latency
#define B_QNC_PCIE_DCAP_E0AL (BIT8 | BIT7 | BIT6) // L0 Acceptable exit latency
#define R_QNC_PCIE_DCTL 0x48 //~ 49h
#define B_QNC_PCIE_DCTL_URE (BIT3) //Unsupported Request Reporting Enable
#define B_QNC_PCIE_DCTL_FEE (BIT2) //Fatal error Reporting Enable
#define B_QNC_PCIE_DCTL_NFE (BIT1) //Non Fatal error Reporting Enable
#define B_QNC_PCIE_DCTL_CEE (BIT0) //Correctable error Reporting Enable
#define R_QNC_PCIE_LCAP 0x4C //~ 4Fh
#define B_QNC_PCIE_LCAP_CPM (BIT18) //clock power management supported
#define B_QNC_PCIE_LCAP_EL1_MASK (BIT17 | BIT16 | BIT15) //L1 Exit latency mask
#define B_QNC_PCIE_LCAP_EL0_MASK (BIT14 | BIT13 | BIT12) //L0 Exit latency mask
#define B_QNC_PCIE_LCAP_APMS_MASK (BIT11 | BIT10) //Active state link PM support mask
#define V_QNC_PCIE_LCAP_APMS_OFFSET 10 //Active state link PM support mask
#define R_QNC_PCIE_LCTL 0x50 //~ 51h
#define B_QNC_PCIE_LCTL_CCC (BIT6) // Clock clock configuration
#define B_QNC_PCIE_LCTL_RL (BIT5) // Retrain link
#define R_QNC_PCIE_LSTS 0x52 //~ 53h
#define B_QNC_PCIE_LSTS_SCC (BIT12) //Slot clock configuration
#define B_QNC_PCIE_LSTS_LT (BIT11) //Link training
#define R_QNC_PCIE_SLCAP 0x54 //~ 57h
#define B_QNC_PCIE_SLCAP_MASK_RSV_VALUE 0x0006007F
#define V_QNC_PCIE_SLCAP_SLV 0x0A //Slot power limit value [14:7]
#define V_QNC_PCIE_SLCAP_SLV_OFFSET 7 //Slot power limit value offset is 7 [14:7]
#define V_QNC_PCIE_SLCAP_PSN_OFFSET 19 //Slot number offset is 19 [31:19]
#define R_QNC_PCIE_SLCTL 0x58 //~ 59h
#define B_QNC_PCIE_SLCTL_HPE (BIT5) // Hot plug interrupt enable
#define B_QNC_PCIE_SLCTL_PDE (BIT3) // Presense detect change enable
#define B_QNC_PCIE_SLCTL_ABE (BIT0) // Attention Button Pressed Enable
#define R_QNC_PCIE_SLSTS 0x5A //~ 5Bh
#define B_QNC_PCIE_SLSTS_PDS (BIT6) // Present Detect State = 1b : has device connected
#define B_QNC_PCIE_SLSTS_PDC (BIT3) // Present Detect changed = 1b : PDS state has changed
#define B_QNC_PCIE_SLSTS_ABP (BIT0) // Attention Button Pressed
#define R_QNC_PCIE_RCTL 0x5C //~ 5Dh
#define B_QNC_PCIE_RCTL_PIE (BIT3) //Root PCI-E PME Interrupt Enable
#define B_QNC_PCIE_RCTL_SFE (BIT2) //Root PCI-E System Error on Fatal Error Enable
#define B_QNC_PCIE_RCTL_SNE (BIT1) //Root PCI-E System Error on Non-Fatal Error Enable
#define B_QNC_PCIE_RCTL_SCE (BIT0) //Root PCI-E System Error on Correctable Error Enable
#define R_QNC_PCIE_SVID 0x94 //~ 97h
#define R_QNC_PCIE_CCFG 0xD0 //~ D3h
#define B_QNC_PCIE_CCFG_UPSD (BIT24) // Upstream Posted Split Disable
#define B_QNC_PCIE_CCFG_UNRS (BIT15) // Upstream Non-Posted Request Size
#define B_QNC_PCIE_CCFG_UPRS (BIT14) // Upstream Posted Request Size
#define R_QNC_PCIE_MPC2 0xD4 //~ D7h
#define B_QNC_PCIE_MPC2_IPF (BIT11) // ISOF Packet Fast Transmit Mode
#define R_QNC_PCIE_MPC 0xD8 //~ DBh
#define B_QNC_PCIE_MPC_PMCE (BIT31) // PM SCI Enable
#define B_QNC_PCIE_MPC_HPCE (BIT30) // Hot plug SCI enable
#define B_QNC_PCIE_MPC_HPME (BIT1) // Hot plug SMI enable
#define B_QNC_PCIE_MPC_PMME (BIT0) // PM SMI Enable
#define R_QNC_PCIE_IOSFSBCTL 0xF6
#define B_QNC_PCIE_IOSFSBCTL_SBIC_MASK (BIT1 | BIT0) // IOSF Sideband ISM Idle Counter.
#define B_QNC_PCIE_IOSFSBCTL_SBIC_IDLE_NEVER (BIT1 | BIT0) // Never transition to IDLE.
#define V_PCIE_MAX_TRY_TIMES 200
//
// Misc PCI register offsets and sizes
//
#define R_EFI_PCI_SVID 0x2C
//
// IO_APIC
//
#define IOAPIC_BASE 0xFEC00000
#define IOAPIC_SIZE 0x1000
//
// Chipset configuration registers RCBA - "Root Complex Base Address" (D31:F0:RF0h)
// Suggested Value for RCBA = 0xFED1C000
//
#define R_QNC_RCRB_SPIBASE 0x3020 // SPI (Serial Peripheral Interface) in RCRB
#define R_QNC_RCRB_SPIS (R_QNC_RCRB_SPIBASE + 0x00) // SPI Status
#define B_QNC_RCRB_SPIS_SCL (BIT15) // SPI Configuration Lockdown
#define B_QNC_RCRB_SPIS_BAS (BIT3) // Blocked Access Status
#define B_QNC_RCRB_SPIS_CDS (BIT2) // Cycle Done Status
#define B_QNC_RCRB_SPIS_SCIP (BIT0) // SPI Cycle in Progress
#define R_QNC_RCRB_SPIC (R_QNC_RCRB_SPIBASE + 0x02) // SPI Control
#define B_QNC_RCRB_SPIC_DC (BIT14) // SPI Data Cycle Enable
#define B_QNC_RCRB_SPIC_DBC 0x3F00 // SPI Data Byte Count (1..8,16,24,32,40,48,56,64)
#define B_QNC_RCRB_SPIC_COP (BIT6+BIT5+BIT4) // SPI Cycle Opcode Pointer
#define B_QNC_RCRB_SPIC_SPOP (BIT3) // Sequence Prefix Opcode Pointer
#define B_QNC_RCRB_SPIC_ACS (BIT2) // SPI Atomic Cycle Sequence
#define B_QNC_RCRB_SPIC_SCGO (BIT1) // SPI Cycle Go
#define R_QNC_RCRB_SPIA (R_QNC_RCRB_SPIBASE + 0x04) // SPI Address
#define B_QNC_RCRB_SPIA_MASK 0x00FFFFFF // SPI Address mask
#define R_QNC_RCRB_SPID0 (R_QNC_RCRB_SPIBASE + 0x08) // SPI Data 0
#define R_QNC_RCRB_SPIPREOP (R_QNC_RCRB_SPIBASE + 0x54) // Prefix Opcode Configuration
#define R_QNC_RCRB_SPIOPTYPE (R_QNC_RCRB_SPIBASE + 0x56) // Opcode Type Configuration
#define B_QNC_RCRB_SPIOPTYPE_NOADD_READ 0
#define B_QNC_RCRB_SPIOPTYPE_NOADD_WRITE (BIT0)
#define B_QNC_RCRB_SPIOPTYPE_ADD_READ (BIT1)
#define B_QNC_RCRB_SPIOPTYPE_ADD_WRITE (BIT0 + BIT1)
#define R_QNC_RCRB_SPIOPMENU (R_QNC_RCRB_SPIBASE + 0x58) // Opcode Menu Configuration //R_OPMENU
#define R_QNC_RCRB_SPIPBR0 (R_QNC_RCRB_SPIBASE + 0x60) // Protected BIOS Range 0.
#define R_QNC_RCRB_SPIPBR1 (R_QNC_RCRB_SPIBASE + 0x64) // Protected BIOS Range 1.
#define R_QNC_RCRB_SPIPBR2 (R_QNC_RCRB_SPIBASE + 0x68) // Protected BIOS Range 2.
#define B_QNC_RCRB_SPIPBRn_WPE (BIT31) // Write Protection Enable for above 3 registers.
#define R_QNC_RCRB_AGENT0IR 0x3140 // AGENT0 interrupt route
#define R_QNC_RCRB_AGENT1IR 0x3142 // AGENT1 interrupt route
#define R_QNC_RCRB_AGENT2IR 0x3144 // AGENT2 interrupt route
#define R_QNC_RCRB_AGENT3IR 0x3146 // AGENT3 interrupt route
#endif

View File

@@ -0,0 +1,38 @@
/** @file
Common header file shared by all source files.
This file includes package header files, library classes and protocol, PPI & GUID definitions.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __COMMON_HEADER_H_
#define __COMMON_HEADER_H_
#include <PiPei.h>
#include <IntelQNCBase.h>
#include <Library/IntelQNCLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/CpuLib.h>
#include <Library/PciCf8Lib.h>
#include <Library/IoLib.h>
#include <Library/PciLib.h>
#include <Library/PcdLib.h>
#include <Library/DebugLib.h>
#include <Library/TimerLib.h>
#include <Library/QNCAccessLib.h>
#include <IndustryStandard/Pci22.h>
#endif

View File

@@ -0,0 +1,777 @@
/** @file
Lib function for Pei QNC.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "CommonHeader.h"
/**
This function provides the necessary SOC initialization
before MRC running. It sets RCBA, GPIO, PMBASE
and some parts of SOC through SOC message method.
If the function cannot complete it'll ASSERT().
**/
VOID
EFIAPI
PeiQNCPreMemInit (
VOID
)
{
UINT32 RegValue;
// QNCPortWrite(Port#, Offset, Value)
//
// Set the fixed PRI Status encodings config.
//
QNCPortWrite (
QUARK_NC_MEMORY_ARBITER_SB_PORT_ID,
QUARK_NC_MEMORY_ARBITER_REG_ASTATUS,
QNC_FIXED_CONFIG_ASTATUS
);
// Sideband register write to Remote Management Unit
QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QNC_MSG_TMPM_REG_PMBA, (BIT31 | PcdGet16 (PcdPmbaIoBaseAddress)));
// Configurable I/O address in iLB (legacy block)
LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) = BIT31 | PcdGet16 (PcdSmbaIoBaseAddress);
LpcPciCfg32 (R_QNC_LPC_GBA_BASE) = BIT31 | PcdGet16 (PcdGbaIoBaseAddress);
LpcPciCfg32 (R_QNC_LPC_PM1BLK) = BIT31 | PcdGet16 (PcdPm1blkIoBaseAddress);
LpcPciCfg32 (R_QNC_LPC_GPE0BLK) = BIT31 | PcdGet16 (PcdGpe0blkIoBaseAddress);
LpcPciCfg32 (R_QNC_LPC_WDTBA) = BIT31 | PcdGet16 (PcdWdtbaIoBaseAddress);
//
// Program RCBA Base Address
//
LpcPciCfg32AndThenOr (R_QNC_LPC_RCBA, (~B_QNC_LPC_RCBA_MASK), (((UINT32)(PcdGet64 (PcdRcbaMmioBaseAddress))) | B_QNC_LPC_RCBA_EN));
//
// Program Memory Manager fixed config values.
//
RegValue = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BTHCTRL);
RegValue &= ~(DRAM_NON_HOST_RQ_LIMIT_MASK);
RegValue |= (V_DRAM_NON_HOST_RQ_LIMIT << DRAM_NON_HOST_RQ_LIMIT_BP);
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BTHCTRL, RegValue);
//
// Program iCLK fixed config values.
//
QncIClkAndThenOr (
QUARK_ICLK_MUXTOP,
(UINT32) ~(B_MUXTOP_FLEX2_MASK | B_MUXTOP_FLEX1_MASK),
(V_MUXTOP_FLEX2 << B_MUXTOP_FLEX2_BP) | (V_MUXTOP_FLEX1 << B_MUXTOP_FLEX1_BP)
);
QncIClkAndThenOr (
QUARK_ICLK_REF2_DBUFF0,
(UINT32) ~(BIT0), // bit[0] cleared
0
);
QncIClkOr (
QUARK_ICLK_SSC1,
BIT0 // bit[0] set
);
QncIClkOr (
QUARK_ICLK_SSC2,
BIT0 // bit[0] set
);
QncIClkOr (
QUARK_ICLK_SSC3,
BIT0 // bit[0] set
);
//
// Set RMU DMA disable bit post boot.
//
RegValue = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_OPTIONS_1);
RegValue |= OPTIONS_1_DMA_DISABLE;
QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_OPTIONS_1, RegValue);
}
/**
Do north cluster init which needs to be done AFTER MRC init.
@param VOID
@retval VOID
**/
VOID
EFIAPI
PeiQNCPostMemInit (
VOID
)
{
//
// Program SVID/SID the same as VID/DID for all devices except root ports.
//
QNCMmPci32(0, MC_BUS, MC_DEV, MC_FUN, R_EFI_PCI_SVID) = QNCMmPci32(0, MC_BUS, MC_DEV, MC_FUN, PCI_VENDOR_ID_OFFSET);
QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC, PCI_VENDOR_ID_OFFSET);
QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_0, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, PCI_VENDOR_ID_OFFSET);
QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, R_EFI_PCI_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_IOSF2AHB_1, PCI_FUNCTION_NUMBER_QNC_IOSF2AHB, PCI_VENDOR_ID_OFFSET);
return;
}
/**
Used to check QNC if it's S3 state. Clear the register state after query.
@retval TRUE if it's S3 state.
@retval FALSE if it's not S3 state.
**/
BOOLEAN
EFIAPI
QNCCheckS3AndClearState (
VOID
)
{
BOOLEAN S3WakeEventFound;
UINT16 Pm1Sts;
UINT16 Pm1En;
UINT16 Pm1Cnt;
UINT32 Gpe0Sts;
UINT32 Gpe0En;
UINT32 NewValue;
CHAR8 *EventDescStr;
S3WakeEventFound = FALSE;
EventDescStr = NULL;
//
// Read the ACPI registers,
//
Pm1Sts = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S);
Pm1En = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E);
Pm1Cnt = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
Gpe0Sts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S);
Gpe0En = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E);
//
// Clear Power Management 1 Enable Register and
// General Purpost Event 0 Enables Register
//
IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0);
IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0);
if ((Pm1Sts & B_QNC_PM1BLK_PM1S_WAKE) != 0 && (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) == V_S3) {
//
// Detect the actual WAKE event
//
if ((Pm1Sts & B_QNC_PM1BLK_PM1S_RTC) && (Pm1En & B_QNC_PM1BLK_PM1E_RTC)) {
EventDescStr = "RTC Alarm";
S3WakeEventFound = TRUE;
}
if ((Pm1Sts & B_QNC_PM1BLK_PM1S_PCIEWSTS) && !(Pm1En & B_QNC_PM1BLK_PM1E_PWAKED)) {
EventDescStr = "PCIe WAKE";
S3WakeEventFound = TRUE;
}
if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_PCIE) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_PCIE)) {
EventDescStr = "PCIe";
S3WakeEventFound = TRUE;
}
if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_GPIO) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_GPIO)) {
EventDescStr = "GPIO";
S3WakeEventFound = TRUE;
}
if ((Gpe0Sts & B_QNC_GPE0BLK_GPE0S_EGPE) && (Gpe0En & B_QNC_GPE0BLK_GPE0E_EGPE)) {
EventDescStr = "Ext. GPE";
S3WakeEventFound = TRUE;
}
if (S3WakeEventFound == FALSE) {
EventDescStr = "Unknown";
}
DEBUG ((EFI_D_INFO, "S3 Wake Event - %a\n", EventDescStr));
//
// If no Power Button Override event occurs and one enabled wake event occurs,
// just do S3 resume and clear the state.
//
IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, (Pm1Cnt & (~B_QNC_PM1BLK_PM1C_SLPTP)));
//
// Set EOS to de Assert SMI
//
IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS);
//
// Enable SMI globally
//
NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
NewValue |= SMI_EN;
QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
return TRUE;
}
return FALSE;
}
/**
Used to check QNC if system wakes up from power on reset. Clear the register state after query.
@retval TRUE if system wakes up from power on reset
@retval FALSE if system does not wake up from power on reset
**/
BOOLEAN
EFIAPI
QNCCheckPowerOnResetAndClearState (
VOID
)
{
UINT16 Pm1Sts;
UINT16 Pm1Cnt;
//
// Read the ACPI registers,
// PM1_STS information cannot be lost after power down, unless CMOS is cleared.
//
Pm1Sts = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S);
Pm1Cnt = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
//
// If B_SLP_TYP is S5
//
if ((Pm1Sts & B_QNC_PM1BLK_PM1S_WAKE) != 0 && (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) == V_S5) {
IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, (Pm1Cnt & (~B_QNC_PM1BLK_PM1C_SLPTP)));
return TRUE;
}
return FALSE;
}
/**
This function is used to clear SMI and wake status.
**/
VOID
EFIAPI
QNCClearSmiAndWake (
VOID
)
{
UINT32 Gpe0Sts;
UINT32 SmiSts;
//
// Read the ACPI registers
//
Gpe0Sts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S);
SmiSts = IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);
//
// Clear any SMI or wake state from the boot
//
Gpe0Sts |= B_QNC_GPE0BLK_GPE0S_ALL;
SmiSts |= B_QNC_GPE0BLK_SMIS_ALL;
//
// Write them back
//
IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S, Gpe0Sts);
IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, SmiSts);
}
/** Send DRAM Ready opcode.
@param[in] OpcodeParam Parameter to DRAM ready opcode.
@retval VOID
**/
VOID
EFIAPI
QNCSendOpcodeDramReady (
IN UINT32 OpcodeParam
)
{
//
// Before sending DRAM ready place invalid value in Scrub Config.
//
QNCPortWrite (
QUARK_NC_RMU_SB_PORT_ID,
QUARK_NC_ECC_SCRUB_CONFIG_REG,
SCRUB_CFG_INVALID
);
//
// Send opcode and use param to notify HW of new RMU firmware location.
//
McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = OpcodeParam;
McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_SHADOW_DW (QUARK_NC_RMU_SB_PORT_ID, 0);
//
// HW completed tasks on DRAM ready when scrub config read back as zero.
//
while (QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG) != 0) {
MicroSecondDelay (10);
}
}
/**
Relocate RMU Main binary to memory after MRC to improve performance.
@param[in] DestBaseAddress - Specify the new memory address for the RMU Main binary.
@param[in] SrcBaseAddress - Specify the current memory address for the RMU Main binary.
@param[in] Size - Specify size of the RMU Main binary.
@retval VOID
**/
VOID
EFIAPI
RmuMainRelocation (
IN CONST UINT32 DestBaseAddress,
IN CONST UINT32 SrcBaseAddress,
IN CONST UINTN Size
)
{
//
// Shadow RMU Main binary into main memory.
//
CopyMem ((VOID *)(UINTN)DestBaseAddress,(VOID *)(UINTN) SrcBaseAddress, Size);
}
/**
Get the total memory size
**/
UINT32
EFIAPI
QNCGetTotalMemorysize (
VOID
)
{
return QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HMBOUND_REG) & HMBOUND_MASK;
}
/**
Get the memory range of TSEG.
The TSEG's memory is below TOLM.
@param[out] BaseAddress The base address of TSEG's memory range
@param[out] MemorySize The size of TSEG's memory range
**/
VOID
EFIAPI
QNCGetTSEGMemoryRange (
OUT UINT64 *BaseAddress,
OUT UINT64 *MemorySize
)
{
UINT64 Register = 0;
UINT64 SMMAddress = 0;
Register = QncHsmmcRead ();
//
// Get the SMRAM Base address
//
SMMAddress = Register & SMM_START_MASK;
*BaseAddress = LShift16 (SMMAddress);
//
// Get the SMRAM size
//
SMMAddress = ((Register & SMM_END_MASK) | (~SMM_END_MASK)) + 1;
*MemorySize = SMMAddress - (*BaseAddress);
DEBUG ((
EFI_D_INFO,
"TSEG's memory range: BaseAddress = 0x%x, Size = 0x%x\n",
(UINT32)*BaseAddress,
(UINT32)*MemorySize
));
}
/**
Updates the PAM registers in the MCH for the requested range and mode.
@param Start The start address of the memory region
@param Length The length, in bytes, of the memory region
@param ReadEnable Pointer to the boolean variable on whether to enable read for legacy memory section.
If NULL, then read attribute will not be touched by this call.
@param ReadEnable Pointer to the boolean variable on whether to enable write for legacy memory section.
If NULL, then write attribute will not be touched by this call.
@param Granularity A pointer to granularity, in bytes, that the PAM registers support
@retval RETURN_SUCCESS The PAM registers in the MCH were updated
@retval RETURN_INVALID_PARAMETER The memory range is not valid in legacy region.
**/
EFI_STATUS
EFIAPI
QNCLegacyRegionManipulation (
IN UINT32 Start,
IN UINT32 Length,
IN BOOLEAN *ReadEnable,
IN BOOLEAN *WriteEnable,
OUT UINT32 *Granularity
)
{
//
// Do nothing cos no such support on QNC
//
return RETURN_SUCCESS;
}
/**
Determine if QNC is supported.
@retval FALSE QNC is not supported.
@retval TRUE QNC is supported.
**/
BOOLEAN
EFIAPI
IsQncSupported (
VOID
)
{
UINT16 SocVendorId;
UINT16 SocDeviceId;
SocVendorId = MmioRead16 (
PciDeviceMmBase (MC_BUS,
MC_DEV,
MC_FUN) + PCI_VENDOR_ID_OFFSET
);
SocDeviceId = QncGetSocDeviceId();
//
// Verify that this is a supported chipset
//
if ((SocVendorId != QUARK_MC_VENDOR_ID) || ((SocDeviceId != QUARK_MC_DEVICE_ID) && (SocDeviceId != QUARK2_MC_DEVICE_ID))) {
DEBUG ((DEBUG_ERROR, "QNC code doesn't support the Soc VendorId:0x%04x Soc DeviceId:0x%04x!\n", SocVendorId, SocDeviceId));
return FALSE;
}
return TRUE;
}
/**
Get the DeviceId of the SoC
@retval PCI DeviceId of the SoC
**/
UINT16
EFIAPI
QncGetSocDeviceId (
VOID
)
{
UINT16 SocDeviceId;
SocDeviceId = MmioRead16 (
PciDeviceMmBase (
MC_BUS,
MC_DEV,
MC_FUN
) + PCI_DEVICE_ID_OFFSET
);
return SocDeviceId;
}
/**
Enable SMI detection of legacy flash access violations.
**/
VOID
EFIAPI
QncEnableLegacyFlashAccessViolationSmi (
VOID
)
{
UINT32 BcValue;
BcValue = LpcPciCfg32 (R_QNC_LPC_BIOS_CNTL);
//
// Clear BIOSWE & set BLE.
//
BcValue &= (~B_QNC_LPC_BIOS_CNTL_BIOSWE);
BcValue |= (B_QNC_LPC_BIOS_CNTL_BLE);
LpcPciCfg32 (R_QNC_LPC_BIOS_CNTL) = BcValue;
DEBUG ((EFI_D_INFO, "BIOS Control Lock Enabled!\n"));
}
/**
Setup RMU Thermal sensor registers for Vref mode.
**/
VOID
EFIAPI
QNCThermalSensorSetVRefMode (
VOID
)
{
UINT32 Tscgf1Config;
UINT32 Tscgf2Config;
UINT32 Tscgf2Config2;
Tscgf1Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG);
Tscgf2Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG);
Tscgf2Config2 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2);
Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK);
Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCURRENTSEL_VREF_MODE << B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP);
Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGEN);
Tscgf1Config |= (V_TSCGF1_CONFIG_IBGEN_VREF_MODE << B_TSCGF1_CONFIG_IBGEN_BP);
Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ISPARECTRL_MASK);
Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ISPARECTRL_VREF_MODE << B_TSCGF2_CONFIG2_ISPARECTRL_BP);
Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK);
Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCOARSETUNE_VREF_MODE << B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP);
Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSCONTROL_MASK);
Tscgf2Config |= (V_TSCGF2_CONFIG_IDSCONTROL_VREF_MODE << B_TSCGF2_CONFIG_IDSCONTROL_BP);
QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG, Tscgf1Config);
QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG, Tscgf2Config);
QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2, Tscgf2Config2);
}
/**
Setup RMU Thermal sensor registers for Ratiometric mode.
**/
VOID
EFIAPI
QNCThermalSensorSetRatiometricMode (
VOID
)
{
UINT32 Tscgf1Config;
UINT32 Tscgf2Config;
UINT32 Tscgf2Config2;
UINT32 Tscgf3Config;
Tscgf1Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG);
Tscgf2Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG);
Tscgf2Config2 = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2);
Tscgf3Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG);
Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCURRENTSEL_MASK);
Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCURRENTSEL_RATIO_MODE << B_TSCGF1_CONFIG_ISNSCURRENTSEL_BP);
Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSCHOPSEL_MASK);
Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSCHOPSEL_RATIO_MODE << B_TSCGF1_CONFIG_ISNSCHOPSEL_BP);
Tscgf1Config &= ~(B_TSCGF1_CONFIG_ISNSINTERNALVREFEN);
Tscgf1Config |= (V_TSCGF1_CONFIG_ISNSINTERNALVREFEN_RATIO_MODE << B_TSCGF1_CONFIG_ISNSINTERNALVREFEN_BP);
Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGEN);
Tscgf1Config |= (V_TSCGF1_CONFIG_IBGEN_RATIO_MODE << B_TSCGF1_CONFIG_IBGEN_BP);
Tscgf1Config &= ~(B_TSCGF1_CONFIG_IBGCHOPEN);
Tscgf1Config |= (V_TSCGF1_CONFIG_IBGCHOPEN_RATIO_MODE << B_TSCGF1_CONFIG_IBGCHOPEN_BP);
Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCONFIGSEL_MASK);
Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCONFIGSEL_RATIO_MODE << B_TSCGF2_CONFIG2_ICALCONFIGSEL_BP);
Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ISPARECTRL_MASK);
Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ISPARECTRL_RATIO_MODE << B_TSCGF2_CONFIG2_ISPARECTRL_BP);
Tscgf2Config2 &= ~(B_TSCGF2_CONFIG2_ICALCOARSETUNE_MASK);
Tscgf2Config2 |= (V_TSCGF2_CONFIG2_ICALCOARSETUNE_RATIO_MODE << B_TSCGF2_CONFIG2_ICALCOARSETUNE_BP);
Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSCONTROL_MASK);
Tscgf2Config |= (V_TSCGF2_CONFIG_IDSCONTROL_RATIO_MODE << B_TSCGF2_CONFIG_IDSCONTROL_BP);
Tscgf2Config &= ~(B_TSCGF2_CONFIG_IDSTIMING_MASK);
Tscgf2Config |= (V_TSCGF2_CONFIG_IDSTIMING_RATIO_MODE << B_TSCGF2_CONFIG_IDSTIMING_BP);
Tscgf3Config &= ~(B_TSCGF3_CONFIG_ITSGAMMACOEFF_MASK);
Tscgf3Config |= (V_TSCGF3_CONFIG_ITSGAMMACOEFF_RATIO_MODE << B_TSCGF3_CONFIG_ITSGAMMACOEFF_BP);
QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF1_CONFIG, Tscgf1Config);
QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG, Tscgf2Config);
QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF2_CONFIG2, Tscgf2Config2);
QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG, Tscgf3Config);
}
/**
Setup RMU Thermal sensor trip point values.
@param[in] CatastrophicTripOnDegreesCelsius - Catastrophic set trip point threshold.
@param[in] HotTripOnDegreesCelsius - Hot set trip point threshold.
@param[in] HotTripOffDegreesCelsius - Hot clear trip point threshold.
@retval EFI_SUCCESS Trip points setup.
@retval EFI_INVALID_PARAMETER Invalid trip point value.
**/
EFI_STATUS
EFIAPI
QNCThermalSensorSetTripValues (
IN CONST UINTN CatastrophicTripOnDegreesCelsius,
IN CONST UINTN HotTripOnDegreesCelsius,
IN CONST UINTN HotTripOffDegreesCelsius
)
{
UINT32 RegisterValue;
//
// Register fields are 8-bit temperature values of granularity 1 degree C
// where 0x00 corresponds to -50 degrees C
// and 0xFF corresponds to 205 degrees C.
//
// User passes unsigned values in degrees Celsius so trips < 0 not supported.
//
// Add 50 to user values to get values for register fields.
//
if ((CatastrophicTripOnDegreesCelsius > 205) || (HotTripOnDegreesCelsius > 205) || (HotTripOffDegreesCelsius > 205)) {
return EFI_INVALID_PARAMETER;
}
//
// Set new values.
//
RegisterValue =
((0 + 50) << TS_CAT_TRIP_CLEAR_THOLD_BP) | // Cat Trip Clear value must be less than Cat Trip Set Value.
((CatastrophicTripOnDegreesCelsius + 50) << TS_CAT_TRIP_SET_THOLD_BP) |
((HotTripOnDegreesCelsius + 50) << TS_HOT_TRIP_SET_THOLD_BP) |
((HotTripOffDegreesCelsius + 50) << TS_HOT_TRIP_CLEAR_THOLD_BP)
;
QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP, RegisterValue);
return EFI_SUCCESS;
}
/**
Enable RMU Thermal sensor with a Catastrophic Trip point.
@retval EFI_SUCCESS Trip points setup.
@retval EFI_INVALID_PARAMETER Invalid trip point value.
**/
EFI_STATUS
EFIAPI
QNCThermalSensorEnableWithCatastrophicTrip (
IN CONST UINTN CatastrophicTripOnDegreesCelsius
)
{
UINT32 Tscgf3Config;
UINT32 TsModeReg;
UINT32 TsTripReg;
//
// Trip Register fields are 8-bit temperature values of granularity 1 degree C
// where 0x00 corresponds to -50 degrees C
// and 0xFF corresponds to 205 degrees C.
//
// User passes unsigned values in degrees Celsius so trips < 0 not supported.
//
// Add 50 to user values to get values for register fields.
//
if (CatastrophicTripOnDegreesCelsius > 205) {
return EFI_INVALID_PARAMETER;
}
Tscgf3Config = QNCAltPortRead (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG);
TsModeReg = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_MODE);
TsTripReg = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP);
//
// Setup Catastrophic Trip point.
//
TsTripReg &= ~(TS_CAT_TRIP_SET_THOLD_MASK);
TsTripReg |= ((CatastrophicTripOnDegreesCelsius + 50) << TS_CAT_TRIP_SET_THOLD_BP);
TsTripReg &= ~(TS_CAT_TRIP_CLEAR_THOLD_MASK);
TsTripReg |= ((0 + 50) << TS_CAT_TRIP_CLEAR_THOLD_BP); // Cat Trip Clear value must be less than Cat Trip Set Value.
QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_TRIP, TsTripReg);
//
// To enable the TS do the following:
// 1) Take the TS out of reset by setting itsrst to 0x0.
// 2) Enable the TS using RMU Thermal sensor mode register.
//
Tscgf3Config &= ~(B_TSCGF3_CONFIG_ITSRST);
TsModeReg |= TS_ENABLE;
QNCAltPortWrite (QUARK_SCSS_SOC_UNIT_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_TSCGF3_CONFIG, Tscgf3Config);
QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_TS_MODE, TsModeReg);
return EFI_SUCCESS;
}
/**
Lock all RMU Thermal sensor control & trip point registers.
**/
VOID
EFIAPI
QNCThermalSensorLockAllRegisters (
VOID
)
{
UINT32 RegValue;
UINT32 LockMask;
LockMask = TS_LOCK_THRM_CTRL_REGS_ENABLE | TS_LOCK_AUX_TRIP_PT_REGS_ENABLE;
RegValue = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG);
RegValue |= LockMask;
QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG, RegValue);
ASSERT ((LockMask == (QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_CONFIG) & LockMask)));
}
/**
Set chipset policy for double bit ECC error.
@param[in] PolicyValue Policy to config on double bit ECC error.
**/
VOID
EFIAPI
QNCPolicyDblEccBitErr (
IN CONST UINT32 PolicyValue
)
{
UINT32 Register;
Register = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_RMU_REG_WDT_CONTROL);
Register &= ~(B_WDT_CONTROL_DBL_ECC_BIT_ERR_MASK);
Register |= PolicyValue;
QNCPortWrite (
QUARK_NC_RMU_SB_PORT_ID,
QUARK_NC_RMU_REG_WDT_CONTROL,
Register
);
}
/**
Determine if running on secure Quark hardware Sku.
@retval FALSE Base Quark Sku or unprovisioned Secure Sku running.
@retval TRUE Provisioned SecureSku hardware running.
**/
BOOLEAN
EFIAPI
QncIsSecureProvisionedSku (
VOID
)
{
// Read QUARK Secure SKU Fuse
return ((QNCAltPortRead (QUARK_SCSS_FUSE_SB_PORT_ID, QUARK_SCSS_SOC_UNIT_SPI_ROM_FUSE) & BIT6) == BIT6);
}

View File

@@ -0,0 +1,63 @@
## @file
# Intel QNC Library Instance
#
# Intel QNC Library Instance
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = IntelQNCLib
FILE_GUID = F5B2EA6C-8148-4a4e-88EA-38A4A51F389F
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = IntelQNCLib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
PciExpress.c
IntelQNCLib.c
CommonHeader.h
[Packages]
MdePkg/MdePkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
TimerLib
DebugLib
PcdLib
PciLib
IoLib
PciCf8Lib
BaseLib
CpuLib
QNCAccessLib
[Pcd]
gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdPmbaIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdWdtbaIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdRcbaMmioBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables
gEfiQuarkNcSocIdTokenSpaceGuid.PcdPcieRootPortConfiguration
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress

View File

@@ -0,0 +1,949 @@
/** @file
QNC PCI Express initialization entry
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "CommonHeader.h"
#define PCIEXP_ROOT_PORT_URE_ENABLE BIT0 // unsupported request reporting enable
#define PCIEXP_ROOT_PORT_FEE_ENABLE BIT1 // Fatal Error Reporting Enable
#define PCIEXP_ROOT_PORT_NFE_ENABLE BIT2 // Non-Fatal Error Reporting Enable
#define PCIEXP_ROOT_PORT_CEE_ENABLE BIT3 // Correctable Error Reporting Enable
#define PCIEXP_ROOT_PORT_SFE_ENABLE BIT4 // System Error on Fatal Error Enable
#define PCIEXP_ROOT_PORT_SNE_ENABLE BIT5 // System Error on Non-Fatal Error Enable
#define PCIEXP_ROOT_PORT_SCE_ENABLE BIT6 // System Error on Correctable Error Enable
EFI_STATUS
PcieStall (
IN UINTN Microseconds
)
{
MicroSecondDelay (Microseconds);
return EFI_SUCCESS;
}
/**
Find the Offset to a given Capabilities ID
CAPID list:
0x01 = PCI Power Management Interface
0x04 = Slot Identification
0x05 = MSI Capability
0x10 = PCI Express Capability
@param[in] Bus Bus number of the interested device
@param[in] Device Device number of the interested device
@param[in] Function Function number of the interested device
@param[in] CapId Capability ID to be scanned
@retval Offset of desired CAPID
**/
UINT32
PcieFindCapId (
UINT8 Bus,
UINT8 Device,
UINT8 Function,
UINT8 CapId
)
{
UINT8 CapHeader;
//
// Always start at Offset 0x34
//
CapHeader = QNCMmPci8 (0, Bus, Device, Function, R_QNC_PCIE_CAP_PTR);
if (CapHeader == 0xFF) {
return 0;
}
while (CapHeader != 0) {
if (QNCMmPci8 (0, Bus, Device, Function, CapHeader) == CapId) {
return CapHeader;
}
CapHeader = QNCMmPci8 (0, Bus, Device, Function, CapHeader + 1);
}
return 0;
}
/**
Search and return the offset of desired Pci Express Capability ID
CAPID list:
0x0001 = Advanced Error Rreporting Capability
0x0002 = Virtual Channel Capability
0x0003 = Device Serial Number Capability
0x0004 = Power Budgeting Capability
@param[in] Bus Bus number of the interested device
@param[in] Device Device number of the interested device
@param[in] Function Function number of the interested device
@param[in] CapId Capability ID to be scanned
@retval Offset of desired CAPID
**/
UINT32
PcieFindExtendedCapId (
UINT8 Bus,
UINT8 Device,
UINT8 Function,
UINT16 CapId
)
{
UINT16 CapHeaderOffset;
UINT16 CapHeaderId;
// Start to search at Offset 0x100
// Get Capability Header
CapHeaderId = 0;
CapHeaderOffset = PCIE_CAP_EXT_HEARDER_OFFSET;
while (CapHeaderOffset != 0 && CapHeaderId != 0xFFFF) {
CapHeaderId = QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset);
if (CapHeaderId == CapId) {
return CapHeaderOffset;
}
CapHeaderOffset = (QNCMmPci16 (0, Bus, Device, Function, CapHeaderOffset + 2) >> 4);
}
return 0;
}
/**
Map Vc on both root port and downstream device
@param[in] Bus1 Bus number of the root port
@param[in] Device1 Device number of the root port
@param[in] Function1 Function number of the root port
@param[in] Bus2 Bus number of the downstream device
@param[in] Device2 Device number of the downstream device
@param[in] Function2 Function number of the downstream device
@retval EFI_SUCCESS Map Vc successful
**/
EFI_STATUS
PcieInitTcxVc0 (
IN UINT8 Bus1,
IN UINT8 Device1,
IN UINT8 Function1,
IN UINT8 Bus2,
IN UINT8 Device2,
IN UINT8 Function2
)
{
UINT32 Offset;
//
// Initialize TCx-VC0 value on the port to only use TC0
//
Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2);
if (Offset == 0) {
return EFI_UNSUPPORTED;
}
QNCMmPci8AndThenOr (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1);
// Set TCx-VC0 value on the Endpoint
Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2);
if (Offset == 0) {
return EFI_UNSUPPORTED;
}
QNCMmPci8AndThenOr (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET), ~0xF, 1);
return EFI_SUCCESS;
}
/**
Map Traffic Class x to Vc0 on both root port and downstream device
@param[in] Bus1 Bus number of the root port
@param[in] Device1 Device number of the root port
@param[in] Function1 Function number of the root port
@param[in] Bus2 Bus number of the downstream device
@param[in] Device2 Device number of the downstream device
@param[in] Function2 Function number of the downstream device
@param[in] TCx Traffic Class to be mapped to vc0
@retval EFI_SUCCESS Map Tcx to Vc0 successful
**/
EFI_STATUS
PcieMapTcxVc0 (
IN UINT8 Bus1,
IN UINT8 Device1,
IN UINT8 Function1,
IN UINT8 Bus2,
IN UINT8 Device2,
IN UINT8 Function2,
IN UINT8 TCx
)
{
UINT32 Offset;
//
// Set TCx-VC0 value on the port
//
Offset = PcieFindExtendedCapId (Bus1, Device1, Function1, 2);
if (Offset == 0) {
return EFI_UNSUPPORTED;
}
QNCMmPci8 (0, Bus1, Device1, Function1, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx);
// Set TCx-VC0 value on the Endpoint
Offset = PcieFindExtendedCapId (Bus2, Device2, Function2, 2);
if (Offset == 0) {
return EFI_UNSUPPORTED;
}
QNCMmPci8 (0, Bus2, Device2, Function2, (Offset + PCIE_SLOT_CAP_OFFSET)) = (UINT8)(1 << TCx);
return EFI_SUCCESS;
}
/**
Set common clock for both root port and downstream device.
@param[in] Bus1 Bus number of the root port
@param[in] Device1 Device number of the root port
@param[in] Function1 Function number of the root port
@param[in] Bus2 Device number of the downstream device
@param[in] Device2 Function number of the downstream device
@retval EFI_SUCCESS Set common clock successful
**/
EFI_STATUS
PcieSetCommonClock (
IN UINT8 Bus1,
IN UINT8 Device1,
IN UINT8 Function1,
IN UINT8 Bus2,
IN UINT8 Device2
)
{
UINT32 CapOffset1;
UINT32 CapOffset2;
UINT8 Function2;
UINT8 CommonClock;
EFI_STATUS Status;
//
// Get the pointer to the Port PCI Express Capability Structure.
//
CommonClock = 0;
CapOffset1 = PcieFindCapId (Bus1, Device1, Function1, PCIE_CAPID);
if (CapOffset1 == 0) {
return EFI_UNSUPPORTED;
}
//
// Step 1
// Read the Slot Clock Configuration bit of the Link status register of the root port and the endpoint device connected to the port
// If both components have this bit set to 1, then System BIOS should set the "Common Clock Configuration" bit in the Link Control Registers
// for both components at both sides of the link to indicate that components at both ends
// of the link use a common clock source
//
//
// Check the Port Slot Clock Configuration Bit.
//
if ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) == 0) {
return EFI_UNSUPPORTED;
}
for (Function2 = 0; Function2 < 8; Function2++) {
//
// Check the Endpoint Slot Clock Configuration Bit.
//
CapOffset2 = PcieFindCapId (Bus2, Device2, Function2, PCIE_CAPID);
if ((CapOffset2 != 0) &&
((QNCMmPci16 (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_SCC) != 0)) {
//
// Common clock is supported, set common clock bit on root port
// and the endpoint
//
if (CommonClock == 0) {
QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC);
CommonClock++;
}
QNCMmPci8Or (0, Bus2, Device2, Function2, (CapOffset2 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_CCC);
}
}
//
// Step 2 If the Common Clock Configuration bit was changed by BIOS in step 1,
// System BIOS should initiate a link training by setting the Retrain Link bit
// in the Link Control register of the root port (D28:F0/F1 offset
// 50h [5]) to "1b" and then poll the Link Training bit in the Link Status
// register of the root port (D28:F0/F1/F2/F3/F4/F5 offset 52h [11]) until it is
// "0b".
//
if (CommonClock == 0) {
Status = EFI_UNSUPPORTED;
} else {
//
// Retrain the Link per PCI Express Specification.
//
QNCMmPci8Or (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_CNT_OFFSET), B_QNC_PCIE_LCTL_RL);
//
// Wait until Re-Training has completed.
//
while ((QNCMmPci16 (0, Bus1, Device1, Function1, (CapOffset1 + PCIE_LINK_STS_OFFSET)) & B_QNC_PCIE_LSTS_LT) != 0);
Status = EFI_SUCCESS;
}
return Status;
}
/**
Enables the CLKREQ# PM on all the end point functions
@param[in] Bus Bus number of the downstream device
@param[in] Device Device number of the downstream device
@retval None
**/
VOID
PcieSetClkreq (
IN UINT8 Bus,
IN UINT8 Device
)
{
UINT8 Function;
UINT32 CapOffset;
//
// Parse thro all the functions of the endpoint and find the PCIe Cap ID (offset 10h) and if
// exists then enable the CLKREQ# bit (BIT8) on that function
//
for (Function = 0; Function < 8; Function++) {
//
// Find the PCIe Cap Id (offset 10h)
//
CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);
if (CapOffset == 0) {
continue;
}
//
// Check if CLKREQ# is supported by the endpoints
//
if ((QNCMmPci32 (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CAP_OFFSET))
& B_QNC_PCIE_LCAP_CPM) != B_QNC_PCIE_LCAP_CPM) {
//
// CLKREQ# is not supported so dont do anything
//
return;
}
}
//
// Now enable the CLKREQ#
//
for (Function = 0; Function < 8; Function++) {
//
// Find the PCIe Cap Id (offset 10h)
//
CapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);
if (CapOffset == 0) {
continue;
}
QNCMmPci16Or (0, Bus, Device, Function, (CapOffset + PCIE_LINK_CNT_OFFSET), BIT8);
}
}
/**
Configure ASPM automatically for both root port and downstream device.
@param[in] RootBus Bus number of the root port
@param[in] RootDevice Device number of the root port
@param[in] RootFunction Function number of the root port
@param[in] EndpointBus Bus number of the downstream device
@param[in] EndpointDevice Device number of the downstream device
@param[in] EndpointFunction Function number of the downstream device
@param[in] LinkAspmVal Currently used ASPM setting
@retval EFI_SUCCESS Configure ASPM successful
**/
EFI_STATUS
PcieSetAspmAuto (
IN UINT8 RootBus,
IN UINT8 RootDevice,
IN UINT8 RootFunction,
IN UINT8 EndpointBus,
IN UINT8 EndpointDevice,
IN UINT8 EndpointFunction,
OUT UINT16 *LinkAspmVal
)
{
UINT32 RootPcieCapOffset;
UINT32 EndpointPcieCapOffset;
UINT16 RootPortAspm;
UINT16 EndPointAspm;
UINT16 EndPointVendorId;
UINT16 EndPointDeviceId;
UINT8 EndPointRevId;
UINT16 AspmVal;
UINT32 PortLxLat;
UINT32 EndPointLxLat;
UINT32 LxLat;
//
// Get the pointer to the Port PCI Express Capability Structure.
//
RootPcieCapOffset = PcieFindCapId (RootBus, RootDevice, RootFunction, PCIE_CAPID);
if (RootPcieCapOffset == 0) {
return EFI_UNSUPPORTED;
}
//
// Get the pointer to the Endpoint PCI Express Capability Structure.
//
EndpointPcieCapOffset = PcieFindCapId (EndpointBus, EndpointDevice, EndpointFunction, PCIE_CAPID);
if (EndpointPcieCapOffset == 0) {
return EFI_UNSUPPORTED;
}
//
// Obtain initial ASPM settings from respective port capability registers.
//
RootPortAspm = (QNCMmPci16 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
//
// Configure downstream device if present.
//
EndPointAspm = (QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
//
// Mask APMC with values from lookup table.
// RevID of 0xFF applies to all steppings.
//
EndPointVendorId = QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, 0);
EndPointDeviceId = QNCMmPci16 (0, EndpointBus, EndpointDevice, EndpointFunction, 2);
EndPointRevId = QNCMmPci8 (0, EndpointBus, EndpointDevice, EndpointFunction, 8);
// TODO: Mask with latency/acceptable latency comparison results.
AspmVal = RootPortAspm;
if (RootPortAspm > EndPointAspm) {
AspmVal = EndPointAspm;
}
//
// Check if L1 should be enabled based on port and endpoint L1 exit latency.
//
if(AspmVal & BIT1) {
PortLxLat = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;
EndPointLxLat = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL1_MASK;
LxLat = PortLxLat;
if(PortLxLat < EndPointLxLat) {
LxLat = EndPointLxLat;
}
//
// check if the value is bigger than endpoint L1 acceptable exit latency, if it is
// larger than accepted value, then we should disable L1
//
LxLat >>= 6;
if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E1AL)) {
AspmVal &= ~BIT1;
}
}
//
// Check if L0s should be enabled based on port and endpoint L0s exit latency.
//
if(AspmVal & BIT0) {
PortLxLat = QNCMmPci32 (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset+ PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;
EndPointLxLat = QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_EL0_MASK;
LxLat = PortLxLat;
if(PortLxLat < EndPointLxLat) {
LxLat = EndPointLxLat;
}
//
// check if the value is bigger than endpoint L0s acceptable exit latency, if it is
// larger than accepted value, then we should disable L0s
//
LxLat >>= 6;
if(LxLat > (QNCMmPci32 (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_DEV_CAP_OFFSET)) & B_QNC_PCIE_DCAP_E0AL)) {
AspmVal &= ~BIT0;
}
}
RootPortAspm = AspmVal;
*LinkAspmVal = AspmVal;
//
// Set Endpoint Aspm
//
QNCMmPci16AndThenOr (0, EndpointBus, EndpointDevice, EndpointFunction, (EndpointPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, AspmVal);
//
// Set Root Port Aspm
//
QNCMmPci16AndThenOr (0, RootBus, RootDevice, RootFunction, (RootPcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, RootPortAspm);
return EFI_SUCCESS;
}
/**
Configure ASPM based on the given setting for the interested device.
@param[in] Bus Bus number of the interested device
@param[in] Device Device number of the interested device
@param[in] Function Function number of the interested device
@param[in] AspmSetting Aspm setting
@param[in] LinkAspmVal Currently used ASPM setting
@retval EFI_SUCCESS Configure ASPM successful
**/
EFI_STATUS
PcieSetAspmManual (
IN UINT8 Bus,
IN UINT8 Device,
IN UINT8 Function,
IN UINT8 AspmSetting,
OUT UINT16 *LinkAspmVal
)
{
UINT32 PcieCapOffset;
UINT16 PortAspm;
//
// Get the pointer to the Port PCI Express Capability Structure.
//
PcieCapOffset = PcieFindCapId (Bus, Device, Function, PCIE_CAPID);
if (PcieCapOffset == 0) {
return EFI_UNSUPPORTED;
}
// Read the Link Capability register's ASPM setting
PortAspm = (QNCMmPci16 (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CAP_OFFSET)) & B_QNC_PCIE_LCAP_APMS_MASK) >> V_QNC_PCIE_LCAP_APMS_OFFSET;
// Mask it with the Setup selection
PortAspm &= AspmSetting;
*LinkAspmVal = PortAspm;
// Write it to the Link Control register
QNCMmPci16AndThenOr (0, Bus, Device, Function, (PcieCapOffset + PCIE_LINK_CNT_OFFSET), 0xFFFC, PortAspm);
return EFI_SUCCESS;
}
/**
Perform Initialization on one PCI Express root port.
@param[in] RootPortIndex Index of PCI Express root port
@param[in] RootPortConfig Pointer to the given pcie root port configuration
@param[in] PciExpressBar Base address of pcie space
@param[in] QNCRootComplexBar Base address of root complex
@param[in] QNCPmioBase Base address of PM IO space
@param[in] QNCGpeBase Base address of gpe IO space
@retval EFI_SUCCESS Initialization successful
**/
EFI_STATUS
QNCRootPortInit (
IN UINT32 RootPortIndex,
IN PCIEXP_ROOT_PORT_CONFIGURATION *RootPortConfig,
IN UINT64 PciExpressBar,
IN UINT32 QNCRootComplexBar,
IN UINT32 QNCPmioBase,
IN UINT32 QNCGpeBase
)
{
UINT64 RPBase;
UINT64 EndPointBase;
UINT64 LpcBase;
UINT16 AspmVal;
UINT16 SlotStatus;
UINTN Index;
UINT32 CapOffset;
UINT32 DwordReg;
RPBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + ((PCI_DEVICE_NUMBER_PCIE_ROOTPORT) << 3) + ((PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex) << 0)) << 12);
LpcBase = PciExpressBar + (((PCI_BUS_NUMBER_QNC << 8) + (31 << 3) + (0 << 0)) << 12);
CapOffset = PcieFindCapId (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), PCIE_CAPID);
if (CapOffset == 0) {
return EFI_UNSUPPORTED;
}
//
// Initialize "Slot Implmemented Bit" for this root port
//
if (RootPortConfig[RootPortIndex].Bits.SlotImplemented) {
QNCMmio16Or (RPBase, R_QNC_PCIE_XCAP, B_QNC_PCIE_XCAP_SI);
}
//
// For Root Port Slots Numbering on the CRBs.
// Root Port 0 = Slot 1
// Root Port 1 = Slot 2
// Root Port 2 = Slot 3
// Root Port 3 = Slot 4
//
DwordReg = QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP);
DwordReg &= B_QNC_PCIE_SLCAP_MASK_RSV_VALUE;
DwordReg |= (V_QNC_PCIE_SLCAP_SLV << V_QNC_PCIE_SLCAP_SLV_OFFSET);
DwordReg |= ((RootPortConfig[RootPortIndex].Bits.PhysicalSlotNumber) << V_QNC_PCIE_SLCAP_PSN_OFFSET) ;
QNCMmio32 (RPBase, R_QNC_PCIE_SLCAP) = DwordReg;
//
// Check for a Presence Detect Change.
//
SlotStatus = QNCMmio16 (RPBase, R_QNC_PCIE_SLSTS);
if ((SlotStatus & (B_QNC_PCIE_SLSTS_PDS + B_QNC_PCIE_SLSTS_PDC)) == 0) {
return EFI_NOT_FOUND;
}
//
// Temporarily Hardcode the Root Port Bridge Number to 2.
//
// This Endpoint check should immediately pass. Howerver, a 900ms delay
// has been added to match the timing requirements of the PCI Express Base
// Specification, Revision 1.0A, Section 6.6 ("...software must allow 1.0s
// after a reset of a device, before it may determine that a device which
// fails to return a Successful Completion status for a valid Configuration
// Request is a broken device"). Note that a 100ms delay was already added
// after the Root Ports were first taken out of reset.
//
QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF, 0x00020200);
//
// Only do this when a downstream device is present
//
EndPointBase = PciExpressBar + (((2 << 8) + (0 << 3) + (0 << 0)) << 12);
if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
for (Index = 0; Index < V_PCIE_MAX_TRY_TIMES; Index++){
if (QNCMmio16 (EndPointBase, 0x0) != 0xFFFF) {
break;
}
PcieStall (15);
}
if (Index >= V_PCIE_MAX_TRY_TIMES) {
//
// Clear Bus Numbers.
//
QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);
return EFI_NOT_FOUND;
}
}
//
// PCI Express* Virtual Channels
// Clear TC1-7 Traffic classes.
// Map TC0-VC0
//
PcieInitTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0);
PcieMapTcxVc0 (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, 0x0);
//
// Set Common Clock for inserted cards
//
if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
PcieSetCommonClock (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0);
}
//
// Flow for Enabling ASPM
//
if (RootPortConfig[RootPortIndex].Bits.AspmEnable) {
if (RootPortConfig[RootPortIndex].Bits.AspmAutoEnable) {
PcieSetAspmAuto (PCI_BUS_NUMBER_QNC, (UINT8)(PCI_DEVICE_NUMBER_PCIE_ROOTPORT), (UINT8)(PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex), 2, 0, 0, &AspmVal);
} else {
//
// Set ASPM values according to setup selections, masked by capabilities
//
PcieSetAspmManual (
PCI_BUS_NUMBER_QNC,
(UINT8) (PCI_DEVICE_NUMBER_PCIE_ROOTPORT),
(UINT8) (PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0 + RootPortIndex),
(UINT8) ((RootPortConfig[RootPortIndex].Bits.AspmL0sEnable & 0x01) | (RootPortConfig[RootPortIndex].Bits.AspmL1Enable << 1)),
&AspmVal
);
}
}
//
// Enable the PCIe CLKREQ#
//
if ((SlotStatus & B_QNC_PCIE_SLSTS_PDS) != 0) {
PcieSetClkreq (2, 0);
}
//
// Clear Bus Numbers
//
QNCMmio32And (RPBase, R_QNC_PCIE_BNUM, 0xFF0000FF);
//
// Additional configurations
//
//
// PCI-E Unsupported Request Reporting Enable
//
if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_URE_ENABLE) {
QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_URE);
}
//
// Device Fatal Error Reporting Enable
//
if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_FEE_ENABLE) {
QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_FEE);
}
//
// Device Non Fatal Error Reporting Enable
//
if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_NFE_ENABLE) {
QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_NFE);
}
//
// Device Correctable Error Reporting Enable
//
if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_CEE_ENABLE) {
QNCMmio16Or (RPBase, R_QNC_PCIE_DCTL, B_QNC_PCIE_DCTL_CEE);
}
//
// Root PCI-E PME Interrupt Enable
//
if (RootPortConfig[RootPortIndex].Bits.PmeInterruptEnable) {
QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_PIE);
}
//
// Root PCI-E System Error on Fatal Error Enable
//
if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SFE_ENABLE) {
QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SFE);
}
//
// Root PCI-E System Error on Non-Fatal Error Enable
//
if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SNE_ENABLE) {
QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SNE);
}
//
// Root PCI-E System Error on Correctable Error Enable
//
if (RootPortConfig[RootPortIndex].Bits.PortErrorMask & PCIEXP_ROOT_PORT_SCE_ENABLE) {
QNCMmio16Or (RPBase, R_QNC_PCIE_RCTL, B_QNC_PCIE_RCTL_SCE);
}
//
// Root PCI-E Powermanagement SCI Enabled
//
if (RootPortConfig[RootPortIndex].Bits.PmSciEnable) {
//
// Make sure that PME Interrupt Enable bit of Root Control register
// of PCI Express Capability struceture is cleared
//
QNCMmio32And (RPBase, R_QNC_PCIE_RCTL, (~B_QNC_PCIE_RCTL_PIE));
QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_PMME), B_QNC_PCIE_MPC_PMCE);
//
// Make sure GPE0 Stutus RW1C Bit is clear.
//
DwordReg = IoRead32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S);
if ((DwordReg & B_QNC_GPE0BLK_GPE0S_PCIE) != 0) {
IoWrite32 (QNCGpeBase + R_QNC_GPE0BLK_GPE0S, B_QNC_GPE0BLK_GPE0S_PCIE);
}
}
//
// PCIe Hot Plug SCI Enable
//
if (RootPortConfig[RootPortIndex].Bits.HotplugSciEnable) {
//
// Write clear for :
// Attention Button Pressed (bit0)
// Presence Detect Changed (bit3)
//
QNCMmio32Or (RPBase, R_QNC_PCIE_SLSTS, (B_QNC_PCIE_SLSTS_PDC | B_QNC_PCIE_SLSTS_ABP));
//
// Sequence 2: Program the following bits in Slot Control register at offset 18h
// of PCI Express* Capability structure:
// Attention Button Pressed Enable (bit0) = 1b
// Presence Detect Changed Enable (bit3) = 1b
// Hot Plug Interrupt Enable (bit5) = 0b
//
QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_SLCTL, (~B_QNC_PCIE_SLCTL_HPE), (B_QNC_PCIE_SLCTL_PDE | B_QNC_PCIE_SLCTL_ABE));
//
// Sequence 3: Program Misc Port Config (MPC) register at PCI config space offset
// D8h as follows:
// Hot Plug SCI Enable (HPCE, bit30) = 1b
// Hot Plug SMI Enable (HPME, bit1) = 0b
//
QNCMmio32AndThenOr (RPBase, R_QNC_PCIE_MPC, (~B_QNC_PCIE_MPC_HPME), B_QNC_PCIE_MPC_HPCE);
}
return EFI_SUCCESS;
}
/**
Perform Initialization of the Downstream Root Ports
**/
VOID
QNCDownStreamPortsInit (
IN PCIEXP_ROOT_PORT_CONFIGURATION *RootPortConfig,
IN QNC_DEVICE_ENABLES *QNCDeviceEnables,
IN UINT64 PciExpressBar,
IN UINT32 QNCRootComplexBar,
IN UINT32 QNCPmioBase,
IN UINT32 QNCGpeBase,
OUT UINTN *RpEnableMask
)
{
EFI_STATUS Status;
UINT32 Index;
//
// Initialize every root port and downstream device
//
for (Index = 0;Index < MAX_PCI_EXPRESS_ROOT_PORTS;Index++) {
if ((QNCDeviceEnables->Uint32 & (1 << Index)) != 0) {
Status = QNCRootPortInit (
Index,
RootPortConfig,
PciExpressBar,
QNCRootComplexBar,
QNCPmioBase,
QNCGpeBase
);
if (!EFI_ERROR (Status)) {
(*RpEnableMask) |= LShiftU64(1, Index);
DEBUG ((EFI_D_INFO, " Root Port %x device found, enabled. RpEnableMask: 0x%x\n", Index + 1, *RpEnableMask));
}
}
}
}
/**
Do early init of pci express rootports on Soc.
**/
VOID
EFIAPI
PciExpressEarlyInit (
VOID
)
{
//
// Setup Message Bus Idle Counter (SBIC) values.
//
QNCMmPci8(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_IOSFSBCTL) = QNCMmPci8AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_IOSFSBCTL, (~B_QNC_PCIE_IOSFSBCTL_SBIC_MASK), V_PCIE_ROOT_PORT_SBIC_VALUE);
QNCMmPci8(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_IOSFSBCTL) = QNCMmPci8AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_IOSFSBCTL, (~B_QNC_PCIE_IOSFSBCTL_SBIC_MASK), V_PCIE_ROOT_PORT_SBIC_VALUE);
//
// Program SVID/SID the same as VID/DID for Root ports.
//
QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, PCI_VENDOR_ID_OFFSET);
QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_SVID) = QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, PCI_VENDOR_ID_OFFSET);
//
// Set the IPF bit in MCR2
//
QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_MPC2) = QNCMmPci32Or(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_MPC2, B_QNC_PCIE_MPC2_IPF);
QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_MPC2) = QNCMmPci32Or(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_1, R_QNC_PCIE_MPC2, B_QNC_PCIE_MPC2_IPF);
//
// Set up the Posted and Non Posted Request sizes for PCIe
//
QNCMmPci32(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_CCFG) = QNCMmPci32AndThenOr(0, PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_PCIE_ROOTPORT, PCI_FUNCTION_NUMBER_PCIE_ROOTPORT_0, R_QNC_PCIE_CCFG, ~B_QNC_PCIE_CCFG_UPSD, (B_QNC_PCIE_CCFG_UNRS | B_QNC_PCIE_CCFG_UPRS));
return;
}
/**
Complete initialization all the pci express rootports on Soc.
**/
EFI_STATUS
EFIAPI
PciExpressInit (
)
{
UINT64 PciExpressBar;
UINT32 QNCRootComplexBar;
UINT32 QNCGpioBase;
UINT32 QNCPmioBase;
UINT32 QNCGpeBase;
UINTN RpEnableMask;
PCIEXP_ROOT_PORT_CONFIGURATION *mRootPortConfig;
QNC_DEVICE_ENABLES mQNCDeviceEnables;
//
// Get BAR registers
//
QNCRootComplexBar = QNC_RCRB_BASE;
QNCGpioBase = LpcPciCfg32 (R_QNC_LPC_GBA_BASE) & B_QNC_LPC_GPA_BASE_MASK;
QNCPmioBase = LpcPciCfg32 (R_QNC_LPC_PM1BLK) & B_QNC_LPC_PM1BLK_MASK;
QNCGpeBase = LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & B_QNC_LPC_GPE0BLK_MASK;
RpEnableMask = 0; // assume all root ports are disabled
PciExpressBar = PcdGet64 (PcdPciExpressBaseAddress);
//
// Get platform information from PCD entries
//
mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables);
mRootPortConfig = (PCIEXP_ROOT_PORT_CONFIGURATION*) PcdGetPtr (PcdPcieRootPortConfiguration);
DEBUG ((EFI_D_INFO, " mRootPortConfig: 0x%x, value1: 0x%x, value2: 0x%x, value3: 0x%x, value4: 0x%x\n",
mRootPortConfig, mRootPortConfig[0].Uint32, mRootPortConfig[1].Uint32,
mRootPortConfig[2].Uint32, mRootPortConfig[3].Uint32));
QNCDownStreamPortsInit (
mRootPortConfig,
&mQNCDeviceEnables,
PciExpressBar,
QNCRootComplexBar,
QNCPmioBase,
QNCGpeBase,
&RpEnableMask
);
return EFI_SUCCESS;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
## @file
# MTRR library provides APIs for MTRR operation.
#
# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = MtrrLib
MODULE_UNI_FILE = MtrrLib.uni
FILE_GUID = 6826b408-f4f3-47ee-917f-af7047f9d937
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = MtrrLib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
MtrrLib.c
[Packages]
MdePkg/MdePkg.dec
UefiCpuPkg/UefiCpuPkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
BaseMemoryLib
BaseLib
CpuLib
DebugLib
QNCAccessLib
[Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs ## SOMETIMES_CONSUMES

View File

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

View File

@@ -0,0 +1,34 @@
/** @file
Base Lib function for QNC internal network access.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// The package level header files this module uses
//
#include <Uefi.h>
/**
Gets the base address of PCI Express for Quark North Cluster.
@return The base address of PCI Express for Quark North Cluster.
**/
UINTN
EFIAPI
QncGetPciExpressBaseAddress (
VOID
)
{
return (UINTN) PcdGet64(PcdPciExpressBaseAddress);
}

View File

@@ -0,0 +1,333 @@
/** @file
Common Lib function for QNC internal network access.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// The package level header files this module uses
//
#include <Uefi.h>
#include <IntelQNCRegs.h>
#include <Library/QNCAccessLib.h>
#include <Library/DebugLib.h>
#include <IndustryStandard/Pci22.h>
UINT32
EFIAPI
QNCPortRead(
UINT8 Port,
UINT32 RegAddress
)
{
McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_READ_DW (Port, RegAddress);
return McD0PciCfg32 (QNC_ACCESS_PORT_MDR);
}
VOID
EFIAPI
QNCPortWrite (
UINT8 Port,
UINT32 RegAddress,
UINT32 WriteValue
)
{
McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue;
McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_WRITE_DW (Port, RegAddress);
}
UINT32
EFIAPI
QNCAltPortRead (
UINT8 Port,
UINT32 RegAddress
)
{
McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = ALT_MESSAGE_READ_DW (Port, RegAddress);
return McD0PciCfg32 (QNC_ACCESS_PORT_MDR);
}
VOID
EFIAPI
QNCAltPortWrite (
UINT8 Port,
UINT32 RegAddress,
UINT32 WriteValue
)
{
McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue;
McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = ALT_MESSAGE_WRITE_DW (Port, RegAddress);
}
UINT32
EFIAPI
QNCPortIORead(
UINT8 Port,
UINT32 RegAddress
)
{
McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_IO_READ_DW (Port, RegAddress);
return McD0PciCfg32 (QNC_ACCESS_PORT_MDR);
}
VOID
EFIAPI
QNCPortIOWrite (
UINT8 Port,
UINT32 RegAddress,
UINT32 WriteValue
)
{
McD0PciCfg32 (QNC_ACCESS_PORT_MDR) = WriteValue;
McD0PciCfg32 (QNC_ACCESS_PORT_MEA) = (RegAddress & 0xFFFFFF00);
McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = MESSAGE_IO_WRITE_DW (Port, RegAddress);
}
RETURN_STATUS
EFIAPI
QNCMmIoWrite (
UINT32 MmIoAddress,
QNC_MEM_IO_WIDTH Width,
UINT32 DataNumber,
VOID *pData
)
/*++
Routine Description:
This is for the special consideration for QNC MMIO write, as required by FWG, a reading must be performed after MMIO writing
to ensure the expected write is processed and data is flushed into chipset
Arguments:
Row -- row number to be cleared ( start from 1 )
Returns:
EFI_SUCCESS
--*/
{
RETURN_STATUS Status;
UINTN Index;
Status = RETURN_SUCCESS;
for (Index =0; Index < DataNumber; Index++) {
switch (Width) {
case QNCMmioWidthUint8:
QNCMmio8 (MmIoAddress, 0) = ((UINT8 *)pData)[Index];
if (QNCMmio8 (MmIoAddress, 0) != ((UINT8*)pData)[Index]) {
Status = RETURN_DEVICE_ERROR;
break;
}
break;
case QNCMmioWidthUint16:
QNCMmio16 (MmIoAddress, 0) = ((UINT16 *)pData)[Index];
if (QNCMmio16 (MmIoAddress, 0) != ((UINT16 *)pData)[Index]) {
Status = RETURN_DEVICE_ERROR;
break;
}
break;
case QNCMmioWidthUint32:
QNCMmio32 (MmIoAddress, 0) = ((UINT32 *)pData)[Index];
if (QNCMmio32 (MmIoAddress, 0) != ((UINT32 *)pData)[Index]) {
Status = RETURN_DEVICE_ERROR;
break;
}
break;
case QNCMmioWidthUint64:
QNCMmio64 (MmIoAddress, 0) = ((UINT64 *)pData)[Index];
if (QNCMmio64 (MmIoAddress, 0) != ((UINT64 *)pData)[Index]) {
Status = RETURN_DEVICE_ERROR;
break;
}
break;
default:
break;
}
}
return Status;
}
UINT32
EFIAPI
QncHsmmcRead (
VOID
)
{
return QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC);
}
VOID
EFIAPI
QncHsmmcWrite (
UINT32 WriteValue
)
{
UINT16 DeviceId;
UINT32 Data32;
//
// Check what Soc we are running on (read Host bridge DeviceId)
//
DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET);
if (DeviceId == QUARK2_MC_DEVICE_ID) {
//
// Disable HSMMC configuration
//
Data32 = QncHsmmcRead ();
Data32 &= ~SMM_CTL_EN;
QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, Data32);
//
// Validate HSMMC configuration is disabled
//
Data32 = QncHsmmcRead ();
ASSERT((Data32 & SMM_CTL_EN) == 0);
//
// Enable HSMMC configuration
//
WriteValue |= SMM_CTL_EN;
}
//
// Write the register value
//
QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, WriteValue);
if (DeviceId == QUARK2_MC_DEVICE_ID) {
//
// Validate HSMMC configuration is enabled
//
Data32 = QncHsmmcRead ();
ASSERT((Data32 & SMM_CTL_EN) != 0);
}
}
VOID
EFIAPI
QncImrWrite (
UINT32 ImrBaseOffset,
UINT32 ImrLow,
UINT32 ImrHigh,
UINT32 ImrReadMask,
UINT32 ImrWriteMask
)
{
UINT16 DeviceId;
UINT32 Data32;
//
// Check what Soc we are running on (read Host bridge DeviceId)
//
DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET);
//
// Disable IMR protection
//
if (DeviceId == QUARK2_MC_DEVICE_ID) {
//
// Disable IMR protection
//
Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL);
Data32 &= ~IMR_EN;
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, Data32);
//
// Validate IMR protection is disabled
//
Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL);
ASSERT((Data32 & IMR_EN) == 0);
//
// Update the IMR (IMRXL must be last as it may enable IMR violation checking)
//
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, ImrReadMask);
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, ImrWriteMask);
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXH, ImrHigh);
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, ImrLow);
//
// Validate IMR protection is enabled/disabled
//
Data32 = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL);
ASSERT((Data32 & IMR_EN) == (ImrLow & IMR_EN));
} else {
//
// Disable IMR protection (allow all access)
//
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, (UINT32)IMRX_ALL_ACCESS);
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, (UINT32)IMRX_ALL_ACCESS);
//
// Update the IMR (IMRXRM/IMRXWM must be last as they restrict IMR access)
//
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXL, (ImrLow & ~IMR_EN));
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXH, ImrHigh);
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXRM, ImrReadMask);
QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, ImrBaseOffset+QUARK_NC_MEMORY_MANAGER_IMRXWM, ImrWriteMask);
}
}
VOID
EFIAPI
QncIClkAndThenOr (
UINT32 RegAddress,
UINT32 AndValue,
UINT32 OrValue
)
{
UINT32 RegValue;
//
// Whenever an iCLK SB register (Endpoint 32h) is being programmed the access
// should always consist of a READ from the address followed by 2 identical
// WRITEs to that address.
//
RegValue = QNCAltPortRead (QUARK_ICLK_SB_PORT_ID, RegAddress);
RegValue &= AndValue;
RegValue |= OrValue;
QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);
QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);
}
VOID
EFIAPI
QncIClkOr (
UINT32 RegAddress,
UINT32 OrValue
)
{
UINT32 RegValue;
//
// Whenever an iCLK SB register (Endpoint 32h) is being programmed the access
// should always consist of a READ from the address followed by 2 identical
// WRITEs to that address.
//
RegValue = QNCAltPortRead (QUARK_ICLK_SB_PORT_ID, RegAddress);
RegValue |= OrValue;
QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);
QNCAltPortWrite (QUARK_ICLK_SB_PORT_ID, RegAddress, RegValue);
}

View File

@@ -0,0 +1,43 @@
## @file
# Base Intel QNC Library Instance
#
# Intel QNC internal network access Library Instance
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = QNCAccessLib
FILE_GUID = CC13B9FB-DAF5-4b42-907F-122216787C05
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = QNCAccessLib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
QNCAccessLib.c
BaseAccess.c
[Packages]
MdePkg/MdePkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
DebugLib
[Pcd]
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress

View File

@@ -0,0 +1,148 @@
/** @file
Runtime Lib function for QNC internal network access.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiDxe.h>
#include <Guid/EventGroup.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeLib.h>
#include <Library/QNCAccessLib.h>
///
/// Set Virtual Address Map Event
///
EFI_EVENT mDxeRuntimeQncAccessLibVirtualNotifyEvent = NULL;
///
/// Module global that contains the base physical address of the PCI Express MMIO range.
///
UINTN mDxeRuntimeQncAccessLibPciExpressBaseAddress = 0;
/**
Convert the physical PCI Express MMIO address to a virtual address.
@param[in] Event The event that is being processed.
@param[in] Context The Event Context.
**/
VOID
EFIAPI
DxeRuntimeQncAccessLibVirtualNotify (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
//
// Convert the physical PCI Express MMIO address to a virtual address.
//
Status = EfiConvertPointer (0, (VOID **) &mDxeRuntimeQncAccessLibPciExpressBaseAddress);
ASSERT_EFI_ERROR (Status);
}
/**
The constructor function to setup globals and goto virtual mode notify.
@param ImageHandle The firmware allocated handle for the EFI image.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The constructor completed successfully.
@retval Other value The constructor did not complete successfully.
**/
EFI_STATUS
EFIAPI
DxeRuntimeQncAccessLibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Cache the physical address of the PCI Express MMIO range into a module global variable
//
mDxeRuntimeQncAccessLibPciExpressBaseAddress = (UINTN) PcdGet64(PcdPciExpressBaseAddress);
//
// Register SetVirtualAddressMap () notify function
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
DxeRuntimeQncAccessLibVirtualNotify,
NULL,
&gEfiEventVirtualAddressChangeGuid,
&mDxeRuntimeQncAccessLibVirtualNotifyEvent
);
ASSERT_EFI_ERROR (Status);
return Status;
}
/**
The destructor function frees any allocated buffers and closes the Set Virtual
Address Map event.
@param ImageHandle The firmware allocated handle for the EFI image.
@param SystemTable A pointer to the EFI System Table.
@retval EFI_SUCCESS The destructor completed successfully.
@retval Other value The destructor did not complete successfully.
**/
EFI_STATUS
EFIAPI
DxeRuntimeQncAccessLibDestructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Close the Set Virtual Address Map event
//
Status = gBS->CloseEvent (mDxeRuntimeQncAccessLibVirtualNotifyEvent);
ASSERT_EFI_ERROR (Status);
return Status;
}
/**
Gets the base address of PCI Express for Quark North Cluster.
@return The base address of PCI Express for Quark North Cluster.
**/
UINTN
EFIAPI
QncGetPciExpressBaseAddress (
VOID
)
{
//
// If system goes to virtual mode then virtual notify callback will update
// mDxeRuntimeQncAccessLibPciExpressBaseAddress with virtual address of
// PCIe memory base.
//
return mDxeRuntimeQncAccessLibPciExpressBaseAddress;
}

View File

@@ -0,0 +1,49 @@
## @file
# DXE Runtime Intel QNC Library Instance
#
# Intel QNC internal network access Library Instance.
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = RuntimeQNCAccessLib
FILE_GUID = E6B51D93-E4C8-4425-9FA9-9DED814220F9
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = QNCAccessLib|DXE_RUNTIME_DRIVER
CONSTRUCTOR = DxeRuntimeQncAccessLibConstructor
DESTRUCTOR = DxeRuntimeQncAccessLibDestructor
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32
#
[Sources]
QNCAccessLib.c
RuntimeAccess.c
[Packages]
MdePkg/MdePkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
BaseLib
DebugLib
PcdLib
UefiBootServicesTableLib
UefiRuntimeLib
[Pcd]
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress

View File

@@ -0,0 +1,322 @@
/** @file
QNC Smm Library Services that implements SMM Region access, S/W SMI generation and detection.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Base.h>
#include <IntelQNCRegs.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/IoLib.h>
#include <Uefi/UefiBaseType.h>
#include <Library/QNCAccessLib.h>
#define BOOT_SERVICE_SOFTWARE_SMI_DATA 0
#define RUNTIME_SOFTWARE_SMI_DATA 1
/**
Triggers a run time or boot time SMI.
This function triggers a software SMM interrupt and set the APMC status with an 8-bit Data.
@param Data The value to set the APMC status.
**/
VOID
InternalTriggerSmi (
IN UINT8 Data
)
{
UINT16 PM1BLK_Base;
UINT16 GPE0BLK_Base;
UINT32 NewValue;
//
// Get PM1BLK_Base & GPE0BLK_Base
//
PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);
//
// Enable APM SMI
//
IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), B_QNC_GPE0BLK_SMIE_APM);
//
// Enable SMI globally
//
NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
NewValue |= SMI_EN;
QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
//
// Set APM_STS
//
IoWrite8 (PcdGet16 (PcdSmmDataPort), Data);
//
// Generate the APM SMI
//
IoWrite8 (PcdGet16 (PcdSmmActivationPort), PcdGet8 (PcdSmmActivationData));
//
// Clear the APM SMI Status Bit
//
IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
//
// Set the EOS Bit
//
IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
}
/**
Triggers an SMI at boot time.
This function triggers a software SMM interrupt at boot time.
**/
VOID
EFIAPI
TriggerBootServiceSoftwareSmi (
VOID
)
{
InternalTriggerSmi (BOOT_SERVICE_SOFTWARE_SMI_DATA);
}
/**
Triggers an SMI at run time.
This function triggers a software SMM interrupt at run time.
**/
VOID
EFIAPI
TriggerRuntimeSoftwareSmi (
VOID
)
{
InternalTriggerSmi (RUNTIME_SOFTWARE_SMI_DATA);
}
/**
Gets the software SMI data.
This function tests if a software SMM interrupt happens. If a software SMI happens,
it retrieves the SMM data and returns it as a non-negative value; otherwise a negative
value is returned.
@return Data The data retrieved from SMM data port in case of a software SMI;
otherwise a negative value.
**/
INTN
InternalGetSwSmiData (
VOID
)
{
UINT8 SmiStatus;
UINT8 Data;
SmiStatus = IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);
if (((SmiStatus & B_QNC_GPE0BLK_SMIS_APM) != 0) &&
(IoRead8 (PcdGet16 (PcdSmmActivationPort)) == PcdGet8 (PcdSmmActivationData))) {
Data = IoRead8 (PcdGet16 (PcdSmmDataPort));
return (INTN)(UINTN)Data;
}
return -1;
}
/**
Test if a boot time software SMI happened.
This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and
it was triggered at boot time, it returns TRUE. Otherwise, it returns FALSE.
@retval TRUE A software SMI triggered at boot time happened.
@retval FLASE No software SMI happened or the software SMI was triggered at run time.
**/
BOOLEAN
EFIAPI
IsBootServiceSoftwareSmi (
VOID
)
{
return (BOOLEAN) (InternalGetSwSmiData () == BOOT_SERVICE_SOFTWARE_SMI_DATA);
}
/**
Test if a run time software SMI happened.
This function tests if a software SMM interrupt happened. If a software SMM interrupt happened and
it was triggered at run time, it returns TRUE. Otherwise, it returns FALSE.
@retval TRUE A software SMI triggered at run time happened.
@retval FLASE No software SMI happened or the software SMI was triggered at boot time.
**/
BOOLEAN
EFIAPI
IsRuntimeSoftwareSmi (
VOID
)
{
return (BOOLEAN) (InternalGetSwSmiData () == RUNTIME_SOFTWARE_SMI_DATA);
}
/**
Clear APM SMI Status Bit; Set the EOS bit.
**/
VOID
EFIAPI
ClearSmi (
VOID
)
{
UINT16 GPE0BLK_Base;
//
// Get GpeBase
//
GPE0BLK_Base = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF);
//
// Clear the APM SMI Status Bit
//
IoOr16 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_APM);
//
// Set the EOS Bit
//
IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS, B_QNC_GPE0BLK_SMIS_EOS);
}
/**
This routine is the chipset code that accepts a request to "open" a region of SMRAM.
The region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
The use of "open" means that the memory is visible from all boot-service
and SMM agents.
@retval FALSE Cannot open a locked SMRAM region
@retval TRUE Success to open SMRAM region.
**/
BOOLEAN
EFIAPI
QNCOpenSmramRegion (
VOID
)
{
UINT32 Smram;
// Read the SMRAM register
Smram = QncHsmmcRead ();
//
// Is the platform locked?
//
if (Smram & SMM_LOCKED) {
// Cannot Open a locked region
DEBUG ((EFI_D_WARN, "Cannot open a locked SMRAM region\n"));
return FALSE;
}
//
// Open all SMRAM regions for Host access only
//
Smram |= (SMM_WRITE_OPEN | SMM_READ_OPEN); // Open for Host.
Smram &= ~(NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN); // Not for others.
//
// Write the SMRAM register
//
QncHsmmcWrite (Smram);
return TRUE;
}
/**
This routine is the chipset code that accepts a request to "close" a region of SMRAM.
The region could be legacy AB or TSEG near top of physical memory.
The use of "close" means that the memory is only visible from SMM agents,
not from BS or RT code.
@retval FALSE Cannot open a locked SMRAM region
@retval TRUE Success to open SMRAM region.
**/
BOOLEAN
EFIAPI
QNCCloseSmramRegion (
VOID
)
{
UINT32 Smram;
// Read the SMRAM register.
Smram = QncHsmmcRead ();
//
// Is the platform locked?
//
if(Smram & SMM_LOCKED) {
// Cannot Open a locked region
DEBUG ((EFI_D_WARN, "Cannot close a locked SMRAM region\n"));
return FALSE;
}
Smram &= (~(SMM_WRITE_OPEN | SMM_READ_OPEN | NON_HOST_SMM_WR_OPEN | NON_HOST_SMM_RD_OPEN));
QncHsmmcWrite (Smram);
return TRUE;
}
/**
This routine is the chipset code that accepts a request to "lock" SMRAM.
The region could be legacy AB or TSEG near top of physical memory.
The use of "lock" means that the memory can no longer be opened
to BS state.
**/
VOID
EFIAPI
QNCLockSmramRegion (
VOID
)
{
UINT32 Smram;
// Read the SMRAM register.
Smram = QncHsmmcRead ();
if(Smram & SMM_LOCKED) {
DEBUG ((EFI_D_WARN, "SMRAM region already locked!\n"));
}
Smram |= SMM_LOCKED;
QncHsmmcWrite (Smram);
return;
}

View File

@@ -0,0 +1,51 @@
## @file
# Component description file for Intel QNC SMM Library.
#
# QNC SMM Library that layers on top of the I/O Library to directly
# access SMM power management registers.
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = QNCSmmLib
FILE_GUID = 8A9A62F5-758B-4965-A28B-0AAC292FBD89
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = SmmLib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
QNCSmmLib.c
[Packages]
MdePkg/MdePkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
PcdLib
IoLib
DebugLib
QNCAccessLib
[Pcd]
gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort
gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort
gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationData

View File

@@ -0,0 +1,322 @@
/** @file
System reset Library Services. This library class provides a set of
methods to reset whole system with manipulate QNC.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Base.h>
#include <IntelQNCBase.h>
#include <QNCAccess.h>
#include <Uefi/UefiBaseType.h>
#include <Library/ResetSystemLib.h>
#include <Library/BaseLib.h>
#include <Library/IoLib.h>
#include <Library/PcdLib.h>
#include <Library/CpuLib.h>
#include <Library/QNCAccessLib.h>
//
// Amount of time (seconds) before RTC alarm fires
// This must be < BCD_BASE
//
#define PLATFORM_WAKE_SECONDS_BUFFER 0x06
//
// RTC 'seconds' above which we will not read to avoid potential rollover
//
#define PLATFORM_RTC_ROLLOVER_LIMIT 0x47
//
// BCD is base 10
//
#define BCD_BASE 0x0A
#define PCAT_RTC_ADDRESS_REGISTER 0x70
#define PCAT_RTC_DATA_REGISTER 0x71
//
// Dallas DS12C887 Real Time Clock
//
#define RTC_ADDRESS_SECONDS 0 // R/W Range 0..59
#define RTC_ADDRESS_SECONDS_ALARM 1 // R/W Range 0..59
#define RTC_ADDRESS_MINUTES 2 // R/W Range 0..59
#define RTC_ADDRESS_MINUTES_ALARM 3 // R/W Range 0..59
#define RTC_ADDRESS_HOURS 4 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM
#define RTC_ADDRESS_HOURS_ALARM 5 // R/W Range 1..12 or 0..23 Bit 7 is AM/PM
#define RTC_ADDRESS_DAY_OF_THE_WEEK 6 // R/W Range 1..7
#define RTC_ADDRESS_DAY_OF_THE_MONTH 7 // R/W Range 1..31
#define RTC_ADDRESS_MONTH 8 // R/W Range 1..12
#define RTC_ADDRESS_YEAR 9 // R/W Range 0..99
#define RTC_ADDRESS_REGISTER_A 10 // R/W[0..6] R0[7]
#define RTC_ADDRESS_REGISTER_B 11 // R/W
#define RTC_ADDRESS_REGISTER_C 12 // RO
#define RTC_ADDRESS_REGISTER_D 13 // RO
#define RTC_ADDRESS_CENTURY 50 // R/W Range 19..20 Bit 8 is R/W
/**
Wait for an RTC update to happen
**/
VOID
EFIAPI
WaitForRTCUpdate (
VOID
)
{
UINT8 Data8;
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
if ((Data8 & BIT7) == BIT7) {
while ((Data8 & BIT7) == BIT7) {
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
}
} else {
while ((Data8 & BIT7) == 0) {
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
}
while ((Data8 & BIT7) == BIT7) {
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
}
}
}
/**
Calling this function causes a system-wide reset. This sets
all circuitry within the system to its initial state. This type of reset
is asynchronous to system operation and operates without regard to
cycle boundaries.
System reset should not return, if it returns, it means the system does
not support cold reset.
**/
VOID
EFIAPI
ResetCold (
VOID
)
{
//
// Reference to QuarkNcSocId BWG
// Setting bit 1 will generate a warm reset, driving only RSTRDY# low
//
IoWrite8 (RST_CNT, B_RST_CNT_COLD_RST);
}
/**
Calling this function causes a system-wide initialization. The processors
are set to their initial state, and pending cycles are not corrupted.
System reset should not return, if it returns, it means the system does
not support warm reset.
**/
VOID
EFIAPI
ResetWarm (
VOID
)
{
//
// Reference to QuarkNcSocId BWG
// Setting bit 1 will generate a warm reset, driving only RSTRDY# low
//
IoWrite8 (RST_CNT, B_RST_CNT_WARM_RST);
}
/**
Calling this function causes the system to enter a power state equivalent
to the ACPI G2/S5 or G3 states.
System shutdown should not return, if it returns, it means the system does
not support shut down reset.
**/
VOID
EFIAPI
ResetShutdown (
VOID
)
{
//
// Reference to QuarkNcSocId BWG
// Disable RTC Alarm : (RTC Enable at PM1BLK + 02h[10]))
//
IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, 0);
//
// Firstly, GPE0_EN should be disabled to
// avoid any GPI waking up the system from S5
//
IoWrite32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0E, 0);
//
// Reference to QuarkNcSocId BWG
// Disable Resume Well GPIO : (GPIO bits in GPIOBASE + 34h[8:0])
//
IoWrite32 (PcdGet16 (PcdGbaIoBaseAddress) + R_QNC_GPIO_RGGPE_RESUME_WELL, 0);
//
// No power button status bit to clear for our platform, go to next step.
//
//
// Finally, transform system into S5 sleep state
//
IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, 0xffffc3ff, B_QNC_PM1BLK_PM1C_SLPEN | V_S5);
}
/**
Calling this function causes the system to enter a power state for capsule
update.
Reset update should not return, if it returns, it means the system does
not support capsule update.
**/
VOID
EFIAPI
EnterS3WithImmediateWake (
VOID
)
{
UINT8 Data8;
UINT16 Data16;
UINT32 Data32;
UINTN Eflags;
UINTN RegCr0;
EFI_TIME EfiTime;
UINT32 SmiEnSave;
Eflags = AsmReadEflags ();
if ( (Eflags & 0x200) ) {
DisableInterrupts ();
}
//
// Write all cache data to memory because processor will lost power
//
AsmWbinvd();
RegCr0 = AsmReadCr0();
AsmWriteCr0 (RegCr0 | 0x060000000);
SmiEnSave = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, (SmiEnSave & ~SMI_EN));
//
// Pogram RTC alarm for immediate WAKE
//
//
// Disable SMI sources
//
IoWrite16 (PcdGet16 (PcdGpe0blkIoBaseAddress) + R_QNC_GPE0BLK_SMIE, 0);
//
// Disable RTC alarm interrupt
//
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 & ~BIT5));
//
// Clear RTC alarm if already set
//
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);
Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER); // Read clears alarm status
//
// Disable all WAKE events
//
IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, B_QNC_PM1BLK_PM1E_PWAKED);
//
// Clear all WAKE status bits
//
IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S, B_QNC_PM1BLK_PM1S_ALL);
//
// Avoid RTC rollover
//
do {
WaitForRTCUpdate();
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);
} while (EfiTime.Second > PLATFORM_RTC_ROLLOVER_LIMIT);
//
// Read RTC time
//
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS);
EfiTime.Hour = IoRead8 (PCAT_RTC_DATA_REGISTER);
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES);
EfiTime.Minute = IoRead8 (PCAT_RTC_DATA_REGISTER);
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS);
EfiTime.Second = IoRead8 (PCAT_RTC_DATA_REGISTER);
//
// Set RTC alarm
//
//
// Add PLATFORM_WAKE_SECONDS_BUFFER to current EfiTime.Second
// The maths is to allow for the fact we are adding to a BCD number and require the answer to be BCD (EfiTime.Second)
//
if ((BCD_BASE - (EfiTime.Second & 0x0F)) <= PLATFORM_WAKE_SECONDS_BUFFER) {
Data8 = (((EfiTime.Second & 0xF0) + 0x10) + (PLATFORM_WAKE_SECONDS_BUFFER - (BCD_BASE - (EfiTime.Second & 0x0F))));
} else {
Data8 = EfiTime.Second + PLATFORM_WAKE_SECONDS_BUFFER;
}
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOURS_ALARM);
IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Hour);
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTES_ALARM);
IoWrite8 (PCAT_RTC_DATA_REGISTER, EfiTime.Minute);
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECONDS_ALARM);
IoWrite8 (PCAT_RTC_DATA_REGISTER, Data8);
//
// Enable RTC alarm interrupt
//
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
Data8 = IoRead8 (PCAT_RTC_DATA_REGISTER);
IoWrite8 (PCAT_RTC_DATA_REGISTER, (Data8 | BIT5));
//
// Enable RTC alarm as WAKE event
//
Data16 = IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E);
IoWrite16 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1E, (Data16 | B_QNC_PM1BLK_PM1E_RTC));
//
// Enter S3
//
Data32 = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
Data32 = (UINT32) ((Data32 & 0xffffc3fe) | V_S3 | B_QNC_PM1BLK_PM1C_SCIEN);
IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);
Data32 = Data32 | B_QNC_PM1BLK_PM1C_SLPEN;
IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Data32);
//
// Enable Interrupt if it's enabled before
//
if ( (Eflags & 0x200) ) {
EnableInterrupts ();
}
}

View File

@@ -0,0 +1,52 @@
## @file
# Component description file for Intel QuarkNcSocId Reset System Library.
#
# Reset System Library implementation that bases on QNC.
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = ResetSystemLib
FILE_GUID = AD33A56E-3AAD-40ac-91B1-FA861E8D9D85
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = ResetSystemLib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
ResetSystemLib.c
[Packages]
QuarkSocPkg/QuarkSocPkg.dec
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
PcdLib
IoLib
BaseLib
CpuLib
QNCAccessLib
[Pcd]
gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress

View File

@@ -0,0 +1,31 @@
/** @file
Common header file shared by all source files.
This file includes package header files, library classes and protocol, PPI & GUID definitions.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __COMMON_HEADER_H_
#define __COMMON_HEADER_H_
#include <Uefi.h>
#include <Base.h>
#include <Library/SmbusLib.h>
#include <Library/IoLib.h>
#include <Library/PciLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/QNCAccessLib.h>
#endif

View File

@@ -0,0 +1,803 @@
/** @file
Intel QNC SMBUS library implementation built upon I/O library.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// Include common header file for this module.
//
#include "CommonHeader.h"
/**
Gets Io port base address of Smbus Host Controller.
This internal function depends on a feature flag named PcdIchSmbusFixedIoPortBaseAddress
to retrieve Smbus Io port base. If that feature flag is true, it will get Smbus Io port base
address from a preset Pcd entry named PcdIchSmbusIoPortBaseAddress; otherwise, it will always
read Pci configuration space to get that value in each Smbus bus transaction.
@return The Io port base address of Smbus host controller.
**/
UINTN
InternalGetSmbusIoPortBaseAddress (
VOID
)
{
UINTN IoPortBaseAddress;
if (FeaturePcdGet (PcdSmbaIoBaseAddressFixed)) {
IoPortBaseAddress = (UINTN) PcdGet16 (PcdSmbaIoBaseAddress);
} else {
IoPortBaseAddress = (UINTN) LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) & B_QNC_LPC_SMBUS_BASE_MASK;
}
//
// Make sure that the IO port base address has been properly set.
//
ASSERT (IoPortBaseAddress != 0);
return IoPortBaseAddress;
}
/**
Acquires the ownership of SMBUS.
This internal function reads the host state register.
If the SMBUS is not available, RETURN_TIMEOUT is returned;
Otherwise, it performs some basic initializations and returns
RETURN_SUCCESS.
@param IoPortBaseAddress The Io port base address of Smbus Host controller.
@retval RETURN_SUCCESS The SMBUS command was executed successfully.
@retval RETURN_TIMEOUT A timeout occurred while executing the SMBUS command.
**/
RETURN_STATUS
InternalSmBusAcquire (
UINTN IoPortBaseAddress
)
{
//
// Clear host status register and exit.
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL, 0);
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, 0);
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD1, 0);
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);
return RETURN_SUCCESS;
}
/**
Starts the SMBUS transaction and waits until the end.
This internal function start the SMBUS transaction and waits until the transaction
of SMBUS is over by polling the INTR bit of Host status register.
If the SMBUS is not available, RETURN_TIMEOUT is returned;
Otherwise, it performs some basic initializations and returns
RETURN_SUCCESS.
@param IoPortBaseAddress The Io port base address of Smbus Host controller.
@param HostControl The Host control command to start SMBUS transaction.
@retval RETURN_SUCCESS The SMBUS command was executed successfully.
@retval RETURN_CRC_ERROR The checksum is not correct (PEC is incorrect).
@retval RETURN_DEVICE_ERROR The request was not completed because a failure reflected
in the Host Status Register bit. Device errors are
a result of a transaction collision, illegal command field,
unclaimed cycle (host initiated), or bus errors (collisions).
**/
RETURN_STATUS
InternalSmBusStart (
IN UINTN IoPortBaseAddress,
IN UINT8 HostControl
)
{
UINT8 HostStatus;
//
// Set Host Control Register (Initiate Operation, Interrupt disabled).
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL, HostControl + B_QNC_SMBUS_START);
do {
//
// Poll INTR bit of Host Status Register.
//
HostStatus = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS);
} while ((HostStatus & (B_QNC_SMBUS_BYTE_DONE_STS | B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR)) == 0);
if ((HostStatus & (B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR)) == 0) {
return RETURN_SUCCESS;
}
//
// Clear error bits of Host Status Register.
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, (B_QNC_SMBUS_DERR | B_QNC_SMBUS_BERR));
return RETURN_DEVICE_ERROR;
}
/**
Executes an SMBUS quick, byte or word command.
This internal function executes an SMBUS quick, byte or word commond.
If Status is not NULL, then the status of the executed command is returned in Status.
@param HostControl The value of Host Control Register to set.
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Value The byte/word write to the SMBUS.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
@return The byte/word read from the SMBUS.
**/
UINT16
InternalSmBusNonBlock (
IN UINT8 HostControl,
IN UINTN SmBusAddress,
IN UINT16 Value,
OUT RETURN_STATUS *Status
)
{
RETURN_STATUS ReturnStatus;
UINTN IoPortBaseAddress;
IoPortBaseAddress = InternalGetSmbusIoPortBaseAddress ();
//
// Try to acquire the ownership of QNC SMBUS.
//
ReturnStatus = InternalSmBusAcquire (IoPortBaseAddress);
if (RETURN_ERROR (ReturnStatus)) {
goto Done;
}
//
// Set Host Commond Register.
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCMD, (UINT8) SMBUS_LIB_COMMAND (SmBusAddress));
//
// Write value to Host Data 0 and Host Data 1 Registers.
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, (UINT8) Value);
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD1, (UINT8) (Value >> 8));
//
// Set SMBUS slave address for the device to send/receive from.
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_TSA, (UINT8) SmBusAddress);
//
// Start the SMBUS transaction and wait for the end.
//
ReturnStatus = InternalSmBusStart (IoPortBaseAddress, HostControl);
//
// Read value from Host Data 0 and Host Data 1 Registers.
//
Value = (UINT16)(IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD1) << 8);
Value = (UINT16)(Value | IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD0));
//
// Clear Host Status Register and Auxiliary Status Register.
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);
Done:
if (Status != NULL) {
*Status = ReturnStatus;
}
return Value;
}
/**
Executes an SMBUS quick read command.
Executes an SMBUS quick read command on the SMBUS device specified by SmBusAddress.
Only the SMBUS slave address field of SmBusAddress is required.
If Status is not NULL, then the status of the executed command is returned in Status.
If PEC is set in SmBusAddress, then ASSERT().
If Command in SmBusAddress is not zero, then ASSERT().
If Length in SmBusAddress is not zero, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
**/
VOID
EFIAPI
SmBusQuickRead (
IN UINTN SmBusAddress,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (!SMBUS_LIB_PEC (SmBusAddress));
ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0);
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
InternalSmBusNonBlock (
V_QNC_SMBUS_HCTL_CMD_QUICK,
SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,
0,
Status
);
}
/**
Executes an SMBUS quick write command.
Executes an SMBUS quick write command on the SMBUS device specified by SmBusAddress.
Only the SMBUS slave address field of SmBusAddress is required.
If Status is not NULL, then the status of the executed command is returned in Status.
If PEC is set in SmBusAddress, then ASSERT().
If Command in SmBusAddress is not zero, then ASSERT().
If Length in SmBusAddress is not zero, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
**/
VOID
EFIAPI
SmBusQuickWrite (
IN UINTN SmBusAddress,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (!SMBUS_LIB_PEC (SmBusAddress));
ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0);
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
InternalSmBusNonBlock (
V_QNC_SMBUS_HCTL_CMD_QUICK,
SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE,
0,
Status
);
}
/**
Executes an SMBUS receive byte command.
Executes an SMBUS receive byte command on the SMBUS device specified by SmBusAddress.
Only the SMBUS slave address field of SmBusAddress is required.
The byte received from the SMBUS is returned.
If Status is not NULL, then the status of the executed command is returned in Status.
If Command in SmBusAddress is not zero, then ASSERT().
If Length in SmBusAddress is not zero, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
@return The byte received from the SMBUS.
**/
UINT8
EFIAPI
SmBusReceiveByte (
IN UINTN SmBusAddress,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0);
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
return (UINT8) InternalSmBusNonBlock (
V_QNC_SMBUS_HCTL_CMD_BYTE,
SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,
0,
Status
);
}
/**
Executes an SMBUS send byte command.
Executes an SMBUS send byte command on the SMBUS device specified by SmBusAddress.
The byte specified by Value is sent.
Only the SMBUS slave address field of SmBusAddress is required. Value is returned.
If Status is not NULL, then the status of the executed command is returned in Status.
If Command in SmBusAddress is not zero, then ASSERT().
If Length in SmBusAddress is not zero, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Value The 8-bit value to send.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
@return The parameter of Value.
**/
UINT8
EFIAPI
SmBusSendByte (
IN UINTN SmBusAddress,
IN UINT8 Value,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (SMBUS_LIB_COMMAND (SmBusAddress) == 0);
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
return (UINT8) InternalSmBusNonBlock (
V_QNC_SMBUS_HCTL_CMD_BYTE,
SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE,
Value,
Status
);
}
/**
Executes an SMBUS read data byte command.
Executes an SMBUS read data byte command on the SMBUS device specified by SmBusAddress.
Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
The 8-bit value read from the SMBUS is returned.
If Status is not NULL, then the status of the executed command is returned in Status.
If Length in SmBusAddress is not zero, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
@return The byte read from the SMBUS.
**/
UINT8
EFIAPI
SmBusReadDataByte (
IN UINTN SmBusAddress,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
return (UINT8) InternalSmBusNonBlock (
V_QNC_SMBUS_HCTL_CMD_BYTE_DATA,
SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,
0,
Status
);
}
/**
Executes an SMBUS write data byte command.
Executes an SMBUS write data byte command on the SMBUS device specified by SmBusAddress.
The 8-bit value specified by Value is written.
Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
Value is returned.
If Status is not NULL, then the status of the executed command is returned in Status.
If Length in SmBusAddress is not zero, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Value The 8-bit value to write.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
@return The parameter of Value.
**/
UINT8
EFIAPI
SmBusWriteDataByte (
IN UINTN SmBusAddress,
IN UINT8 Value,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
return (UINT8) InternalSmBusNonBlock (
V_QNC_SMBUS_HCTL_CMD_BYTE_DATA,
SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE,
Value,
Status
);
}
/**
Executes an SMBUS read data word command.
Executes an SMBUS read data word command on the SMBUS device specified by SmBusAddress.
Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
The 16-bit value read from the SMBUS is returned.
If Status is not NULL, then the status of the executed command is returned in Status.
If Length in SmBusAddress is not zero, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
@return The byte read from the SMBUS.
**/
UINT16
EFIAPI
SmBusReadDataWord (
IN UINTN SmBusAddress,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 2);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
return InternalSmBusNonBlock (
V_QNC_SMBUS_HCTL_CMD_WORD_DATA,
SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,
0,
Status
);
}
/**
Executes an SMBUS write data word command.
Executes an SMBUS write data word command on the SMBUS device specified by SmBusAddress.
The 16-bit value specified by Value is written.
Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
Value is returned.
If Status is not NULL, then the status of the executed command is returned in Status.
If Length in SmBusAddress is not zero, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Value The 16-bit value to write.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
@return The parameter of Value.
**/
UINT16
EFIAPI
SmBusWriteDataWord (
IN UINTN SmBusAddress,
IN UINT16 Value,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 2);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
return InternalSmBusNonBlock (
V_QNC_SMBUS_HCTL_CMD_WORD_DATA,
SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE,
Value,
Status
);
}
/**
Executes an SMBUS process call command.
Executes an SMBUS process call command on the SMBUS device specified by SmBusAddress.
The 16-bit value specified by Value is written.
Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
The 16-bit value returned by the process call command is returned.
If Status is not NULL, then the status of the executed command is returned in Status.
If Length in SmBusAddress is not zero, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Value The 16-bit value to write.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
@return The 16-bit value returned by the process call command.
**/
UINT16
EFIAPI
SmBusProcessCall (
IN UINTN SmBusAddress,
IN UINT16 Value,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) == 0);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
return InternalSmBusNonBlock (
V_QNC_SMBUS_HCTL_CMD_PROCESS_CALL,
SmBusAddress & V_QNC_SMBUS_RW_SEL_WRITE,
Value,
Status
);
}
/**
Executes an SMBUS block command.
Executes an SMBUS block read, block write and block write-block read command
on the SMBUS device specified by SmBusAddress.
Bytes are read from the SMBUS and stored in Buffer.
The number of bytes read is returned, and will never return a value larger than 32-bytes.
If Status is not NULL, then the status of the executed command is returned in Status.
It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes.
@param HostControl The value of Host Control Register to set.
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param WriteBuffer Pointer to the buffer of bytes to write to the SMBUS.
@param ReadBuffer Pointer to the buffer of bytes to read from the SMBUS.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
@return The number of bytes read from the SMBUS.
**/
UINTN
InternalSmBusBlock (
IN UINT8 HostControl,
IN UINTN SmBusAddress,
IN UINT8 *WriteBuffer,
OUT UINT8 *ReadBuffer,
OUT RETURN_STATUS *Status
)
{
RETURN_STATUS ReturnStatus;
UINTN Index;
UINTN BytesCount;
UINTN IoPortBaseAddress;
IoPortBaseAddress = InternalGetSmbusIoPortBaseAddress ();
BytesCount = SMBUS_LIB_LENGTH (SmBusAddress);
//
// Try to acquire the ownership of ICH SMBUS.
//
ReturnStatus = InternalSmBusAcquire (IoPortBaseAddress);
if (RETURN_ERROR (ReturnStatus)) {
goto Done;
}
//
// Set Host Command Register.
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCMD, (UINT8) SMBUS_LIB_COMMAND (SmBusAddress));
//
// Clear byte pointer of 32-byte buffer.
//
IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HCTL);
if (WriteBuffer != NULL) {
//
// Write the number of block to Host Block Data Byte Register.
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HD0, (UINT8) BytesCount);
//
// Write data block to Host Block Data Register.
//
for (Index = 0; Index < BytesCount; Index++) {
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HBD + (UINT8)Index, WriteBuffer[Index]);
}
}
//
// Set SMBUS slave address for the device to send/receive from.
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_TSA, (UINT8) SmBusAddress);
//
// Start the SMBUS transaction and wait for the end.
//
ReturnStatus = InternalSmBusStart (IoPortBaseAddress, HostControl);
if (RETURN_ERROR (ReturnStatus)) {
goto Done;
}
if (ReadBuffer != NULL) {
//
// Read the number of block from host block data byte register.
//
BytesCount = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HD0);
//
// Write data block from Host Block Data Register.
//
for (Index = 0; Index < BytesCount; Index++) {
ReadBuffer[Index] = IoRead8 (IoPortBaseAddress + R_QNC_SMBUS_HBD + (UINT8)Index);
}
}
Done:
//
// Clear Host Status Register and Auxiliary Status Register.
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);
if (Status != NULL) {
*Status = ReturnStatus;
}
return BytesCount;
}
/**
Executes an SMBUS read block command.
Executes an SMBUS read block command on the SMBUS device specified by SmBusAddress.
Only the SMBUS slave address and SMBUS command fields of SmBusAddress are required.
Bytes are read from the SMBUS and stored in Buffer.
The number of bytes read is returned, and will never return a value larger than 32-bytes.
If Status is not NULL, then the status of the executed command is returned in Status.
It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes.
If Length in SmBusAddress is not zero, then ASSERT().
If Buffer is NULL, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Buffer Pointer to the buffer to store the bytes read from the SMBUS.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
@return The number of bytes read.
**/
UINTN
EFIAPI
SmBusReadBlock (
IN UINTN SmBusAddress,
OUT VOID *Buffer,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (Buffer != NULL);
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1);
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
return InternalSmBusBlock (
V_QNC_SMBUS_HCTL_CMD_BLOCK,
SmBusAddress | V_QNC_SMBUS_RW_SEL_READ,
NULL,
Buffer,
Status
);
}
/**
Executes an SMBUS write block command.
Executes an SMBUS write block command on the SMBUS device specified by SmBusAddress.
The SMBUS slave address, SMBUS command, and SMBUS length fields of SmBusAddress are required.
Bytes are written to the SMBUS from Buffer.
The number of bytes written is returned, and will never return a value larger than 32-bytes.
If Status is not NULL, then the status of the executed command is returned in Status.
If Length in SmBusAddress is zero or greater than 32, then ASSERT().
If Buffer is NULL, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param Buffer Pointer to the buffer to store the bytes read from the SMBUS.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
@return The number of bytes written.
**/
UINTN
EFIAPI
SmBusWriteBlock (
IN UINTN SmBusAddress,
OUT VOID *Buffer,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (Buffer != NULL);
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1);
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
return InternalSmBusBlock (
V_QNC_SMBUS_HCTL_CMD_BLOCK,
SmBusAddress | V_QNC_SMBUS_RW_SEL_WRITE,
Buffer,
NULL,
Status
);
}
/**
Executes an SMBUS block process call command.
Executes an SMBUS block process call command on the SMBUS device specified by SmBusAddress.
The SMBUS slave address, SMBUS command, and SMBUS length fields of SmBusAddress are required.
Bytes are written to the SMBUS from WriteBuffer. Bytes are then read from the SMBUS into ReadBuffer.
If Status is not NULL, then the status of the executed command is returned in Status.
It is the caller's responsibility to make sure ReadBuffer is large enough for the total number of bytes read.
SMBUS supports a maximum transfer size of 32 bytes, so Buffer does not need to be any larger than 32 bytes.
If Length in SmBusAddress is zero or greater than 32, then ASSERT().
If WriteBuffer is NULL, then ASSERT().
If ReadBuffer is NULL, then ASSERT().
If any reserved bits of SmBusAddress are set, then ASSERT().
@param SmBusAddress Address that encodes the SMBUS Slave Address,
SMBUS Command, SMBUS Data Length, and PEC.
@param WriteBuffer Pointer to the buffer of bytes to write to the SMBUS.
@param ReadBuffer Pointer to the buffer of bytes to read from the SMBUS.
@param Status Return status for the executed command.
This is an optional parameter and may be NULL.
RETURN_TIMEOUT A timeout occurred while executing the SMBUS command.
RETURN_DEVICE_ERROR The request was not completed because a failure
reflected in the Host Status Register bit. Device errors are a result
of a transaction collision, illegal command field, unclaimed cycle
(host initiated), or bus errors (collisions).
RETURN_CRC_ERROR The checksum is not correct (PEC is incorrect)
RETURN_UNSUPPORTED The SMBus operation is not supported.
@return The number of bytes written.
**/
UINTN
EFIAPI
SmBusBlockProcessCall (
IN UINTN SmBusAddress,
IN VOID *WriteBuffer,
OUT VOID *ReadBuffer,
OUT RETURN_STATUS *Status OPTIONAL
)
{
ASSERT (WriteBuffer != NULL);
ASSERT (ReadBuffer != NULL);
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) >= 1);
ASSERT (SMBUS_LIB_LENGTH (SmBusAddress) <= 32);
ASSERT (SMBUS_LIB_RESERVED (SmBusAddress) == 0);
if (Status != NULL) {
*Status = RETURN_UNSUPPORTED;
}
return 0;
}

View File

@@ -0,0 +1,53 @@
## @file
# Component description file for Intel QNC Smbus Library.
#
# SMBUS Library that layers on top of the I/O Library to directly
# access a standard SMBUS host controller.
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = SmbusLib
FILE_GUID = 6F2F36B3-936B-4eb2-83C7-2987B4F9D4EB
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = SmbusLib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
SmbusLib.c
CommonHeader.h
[Packages]
MdePkg/MdePkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
PcdLib
DebugLib
PciLib
IoLib
QNCAccessLib
[FeaturePcd]
gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed
[Pcd]
gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress

View File

@@ -0,0 +1,438 @@
/** @file
The Quark CPU specific programming for PiSmmCpuDxeSmm module.
Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiSmm.h>
#include <Library/SmmCpuFeaturesLib.h>
#include <Register/SmramSaveStateMap.h>
#include <Library/QNCAccessLib.h>
#define EFI_MSR_SMRR_PHYS_MASK_VALID BIT11
#define EFI_MSR_SMRR_MASK 0xFFFFF000
/**
Called during the very first SMI into System Management Mode to initialize
CPU features, including SMBASE, for the currently executing CPU. Since this
is the first SMI, the SMRAM Save State Map is at the default address of
SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing
CPU is specified by CpuIndex and CpuIndex can be used to access information
about the currently executing CPU in the ProcessorInfo array and the
HotPlugCpuData data structure.
@param[in] CpuIndex The index of the CPU to initialize. The value
must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that
was elected as monarch during System Management
Mode initialization.
FALSE if the CpuIndex is not the index of the CPU
that was elected as monarch during System
Management Mode initialization.
@param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION
structures. ProcessorInfo[CpuIndex] contains the
information for the currently executing CPU.
@param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that
contains the ApidId and SmBase arrays.
**/
VOID
EFIAPI
SmmCpuFeaturesInitializeProcessor (
IN UINTN CpuIndex,
IN BOOLEAN IsMonarch,
IN EFI_PROCESSOR_INFORMATION *ProcessorInfo,
IN CPU_HOT_PLUG_DATA *CpuHotPlugData
)
{
SMRAM_SAVE_STATE_MAP *CpuState;
//
// Configure SMBASE.
//
CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);
CpuState->x86.SMBASE = CpuHotPlugData->SmBase[CpuIndex];
//
// Use QNC to initialize SMRR on Quark
//
QNCPortWrite(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSBASE, CpuHotPlugData->SmrrBase);
QNCPortWrite(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK, (~(CpuHotPlugData->SmrrSize - 1) & EFI_MSR_SMRR_MASK) | EFI_MSR_SMRR_PHYS_MASK_VALID);
}
/**
This function updates the SMRAM save state on the currently executing CPU
to resume execution at a specific address after an RSM instruction. This
function must evaluate the SMRAM save state to determine the execution mode
the RSM instruction resumes and update the resume execution address with
either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart
flag in the SMRAM save state must always be cleared. This function returns
the value of the instruction pointer from the SMRAM save state that was
replaced. If this function returns 0, then the SMRAM save state was not
modified.
This function is called during the very first SMI on each CPU after
SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode
to signal that the SMBASE of each CPU has been updated before the default
SMBASE address is used for the first SMI to the next CPU.
@param[in] CpuIndex The index of the CPU to hook. The value
must be between 0 and the NumberOfCpus
field in the System Management System Table
(SMST).
@param[in] CpuState Pointer to SMRAM Save State Map for the
currently executing CPU.
@param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
32-bit execution mode from 64-bit SMM.
@param[in] NewInstructionPointer Instruction pointer to use if resuming to
same execution mode as SMM.
@retval 0 This function did modify the SMRAM save state.
@retval > 0 The original instruction pointer value from the SMRAM save state
before it was replaced.
**/
UINT64
EFIAPI
SmmCpuFeaturesHookReturnFromSmm (
IN UINTN CpuIndex,
IN SMRAM_SAVE_STATE_MAP *CpuState,
IN UINT64 NewInstructionPointer32,
IN UINT64 NewInstructionPointer
)
{
return 0;
}
/**
Hook point in normal execution mode that allows the one CPU that was elected
as monarch during System Management Mode initialization to perform additional
initialization actions immediately after all of the CPUs have processed their
first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
**/
VOID
EFIAPI
SmmCpuFeaturesSmmRelocationComplete (
VOID
)
{
}
/**
Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
returned, then a custom SMI handler is not provided by this library,
and the default SMI handler must be used.
@retval 0 Use the default SMI handler.
@retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
The caller is required to allocate enough SMRAM for each CPU to
support the size of the custom SMI handler.
**/
UINTN
EFIAPI
SmmCpuFeaturesGetSmiHandlerSize (
VOID
)
{
return 0;
}
/**
Install a custom SMI handler for the CPU specified by CpuIndex. This function
is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
than zero and is called by the CPU that was elected as monarch during System
Management Mode initialization.
@param[in] CpuIndex The index of the CPU to install the custom SMI handler.
The value must be between 0 and the NumberOfCpus field
in the System Management System Table (SMST).
@param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
@param[in] SmiStack The stack to use when an SMI is processed by the
the CPU specified by CpuIndex.
@param[in] StackSize The size, in bytes, if the stack used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] GdtBase The base address of the GDT to use when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] IdtBase The base address of the IDT to use when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
processed by the CPU specified by CpuIndex.
@param[in] Cr3 The base address of the page tables to use when an SMI
is processed by the CPU specified by CpuIndex.
**/
VOID
EFIAPI
SmmCpuFeaturesInstallSmiHandler (
IN UINTN CpuIndex,
IN UINT32 SmBase,
IN VOID *SmiStack,
IN UINTN StackSize,
IN UINTN GdtBase,
IN UINTN GdtSize,
IN UINTN IdtBase,
IN UINTN IdtSize,
IN UINT32 Cr3
)
{
}
/**
Determines if MTRR registers must be configured to set SMRAM cache-ability
when executing in System Management Mode.
@retval TRUE MTRR registers must be configured to set SMRAM cache-ability.
@retval FALSE MTRR registers do not need to be configured to set SMRAM
cache-ability.
**/
BOOLEAN
EFIAPI
SmmCpuFeaturesNeedConfigureMtrrs (
VOID
)
{
return TRUE;
}
/**
Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
returns TRUE.
**/
VOID
EFIAPI
SmmCpuFeaturesDisableSmrr (
VOID
)
{
//
// Use QNC to disable SMRR on Quark
//
QNCPortWrite(
QUARK_NC_HOST_BRIDGE_SB_PORT_ID,
QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK,
QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK) & ~EFI_MSR_SMRR_PHYS_MASK_VALID
);
}
/**
Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
returns TRUE.
**/
VOID
EFIAPI
SmmCpuFeaturesReenableSmrr (
VOID
)
{
//
// Use QNC to enable SMRR on Quark
//
QNCPortWrite(
QUARK_NC_HOST_BRIDGE_SB_PORT_ID,
QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK,
QNCPortRead(QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_IA32_MTRR_SMRR_PHYSMASK) | EFI_MSR_SMRR_PHYS_MASK_VALID
);
}
/**
Processor specific hook point each time a CPU enters System Management Mode.
@param[in] CpuIndex The index of the CPU that has entered SMM. The value
must be between 0 and the NumberOfCpus field in the
System Management System Table (SMST).
**/
VOID
EFIAPI
SmmCpuFeaturesRendezvousEntry (
IN UINTN CpuIndex
)
{
}
/**
Processor specific hook point each time a CPU exits System Management Mode.
@param[in] CpuIndex The index of the CPU that is exiting SMM. The value must
be between 0 and the NumberOfCpus field in the System
Management System Table (SMST).
**/
VOID
EFIAPI
SmmCpuFeaturesRendezvousExit (
IN UINTN CpuIndex
)
{
}
/**
Check to see if an SMM register is supported by a specified CPU.
@param[in] CpuIndex The index of the CPU to check for SMM register support.
The value must be between 0 and the NumberOfCpus field
in the System Management System Table (SMST).
@param[in] RegName Identifies the SMM register to check for support.
@retval TRUE The SMM register specified by RegName is supported by the CPU
specified by CpuIndex.
@retval FALSE The SMM register specified by RegName is not supported by the
CPU specified by CpuIndex.
**/
BOOLEAN
EFIAPI
SmmCpuFeaturesIsSmmRegisterSupported (
IN UINTN CpuIndex,
IN SMM_REG_NAME RegName
)
{
return FALSE;
}
/**
Returns the current value of the SMM register for the specified CPU.
If the SMM register is not supported, then 0 is returned.
@param[in] CpuIndex The index of the CPU to read the SMM register. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] RegName Identifies the SMM register to read.
@return The value of the SMM register specified by RegName from the CPU
specified by CpuIndex.
**/
UINT64
EFIAPI
SmmCpuFeaturesGetSmmRegister (
IN UINTN CpuIndex,
IN SMM_REG_NAME RegName
)
{
return 0;
}
/**
Sets the value of an SMM register on a specified CPU.
If the SMM register is not supported, then no action is performed.
@param[in] CpuIndex The index of the CPU to write the SMM register. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] RegName Identifies the SMM register to write.
registers are read-only.
@param[in] Value The value to write to the SMM register.
**/
VOID
EFIAPI
SmmCpuFeaturesSetSmmRegister (
IN UINTN CpuIndex,
IN SMM_REG_NAME RegName,
IN UINT64 Value
)
{
}
/**
Read an SMM Save State register on the target processor. If this function
returns EFI_UNSUPPORTED, then the caller is responsible for reading the
SMM Save Sate register.
@param[in] CpuIndex The index of the CPU to read the SMM Save State. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] Register The SMM Save State register to read.
@param[in] Width The number of bytes to read from the CPU save state.
@param[out] Buffer Upon return, this holds the CPU register value read
from the save state.
@retval EFI_SUCCESS The register was read from Save State.
@retval EFI_INVALID_PARAMTER Buffer is NULL.
@retval EFI_UNSUPPORTED This function does not support reading Register.
**/
EFI_STATUS
EFIAPI
SmmCpuFeaturesReadSaveStateRegister (
IN UINTN CpuIndex,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN Width,
OUT VOID *Buffer
)
{
return EFI_UNSUPPORTED;
}
/**
Writes an SMM Save State register on the target processor. If this function
returns EFI_UNSUPPORTED, then the caller is responsible for writing the
SMM Save Sate register.
@param[in] CpuIndex The index of the CPU to write the SMM Save State. The
value must be between 0 and the NumberOfCpus field in
the System Management System Table (SMST).
@param[in] Register The SMM Save State register to write.
@param[in] Width The number of bytes to write to the CPU save state.
@param[in] Buffer Upon entry, this holds the new CPU register value.
@retval EFI_SUCCESS The register was written to Save State.
@retval EFI_INVALID_PARAMTER Buffer is NULL.
@retval EFI_UNSUPPORTED This function does not support writing Register.
**/
EFI_STATUS
EFIAPI
SmmCpuFeaturesWriteSaveStateRegister (
IN UINTN CpuIndex,
IN EFI_SMM_SAVE_STATE_REGISTER Register,
IN UINTN Width,
IN CONST VOID *Buffer
)
{
return EFI_UNSUPPORTED;
}
/**
This function is hook point called after the gEfiSmmReadyToLockProtocolGuid
notification is completely processed.
**/
VOID
EFIAPI
SmmCpuFeaturesCompleteSmmReadyToLock (
VOID
)
{
}
/**
This API provides a method for a CPU to allocate a specific region for storing page tables.
This API can be called more once to allocate memory for page tables.
Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
is returned. If there is not enough memory remaining to satisfy the request, then NULL is
returned.
This function can also return NULL if there is no preference on where the page tables are allocated in SMRAM.
@param Pages The number of 4 KB pages to allocate.
@return A pointer to the allocated buffer for page tables.
@retval NULL Fail to allocate a specific region for storing page tables,
Or there is no preference on where the page tables are allocated in SMRAM.
**/
VOID *
EFIAPI
SmmCpuFeaturesAllocatePageTableMemory (
IN UINTN Pages
)
{
return NULL;
}

View File

@@ -0,0 +1,34 @@
## @file
# The CPU specific programming for PiSmmCpuDxeSmm module.
#
# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = SmmCpuFeaturesLib
MODULE_UNI_FILE = SmmCpuFeaturesLib.uni
FILE_GUID = 34001BF4-1E93-4e08-B90E-52F2418A5026
MODULE_TYPE = DXE_SMM_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = SmmCpuFeaturesLib
[Packages]
MdePkg/MdePkg.dec
UefiCpuPkg/UefiCpuPkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[Sources]
SmmCpuFeaturesLib.c
[LibraryClasses]
QNCAccessLib

View File

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

View File

@@ -0,0 +1,65 @@
/** @file
Framework PEIM to initialize memory on a QuarkNcSocId Memory Controller.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// Include common header file for this module.
//
#include "MemoryInit.h"
static PEI_QNC_MEMORY_INIT_PPI mPeiQNCMemoryInitPpi =
{ MrcStart };
static EFI_PEI_PPI_DESCRIPTOR PpiListPeiQNCMemoryInit =
{
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gQNCMemoryInitPpiGuid,
&mPeiQNCMemoryInitPpi
};
void Mrc( MRCParams_t *MrcData);
/**
Do memory initialization for QuarkNcSocId DDR3 SDRAM Controller
@param FfsHeader Not used.
@param PeiServices General purpose services available to every PEIM.
@return EFI_SUCCESS Memory initialization completed successfully.
All other error conditions encountered result in an ASSERT.
**/
EFI_STATUS
PeimMemoryInit(
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
Status = (**PeiServices).InstallPpi(PeiServices, &PpiListPeiQNCMemoryInit);
return Status;
}
VOID
EFIAPI
MrcStart(
IN OUT MRCParams_t *MrcData
)
{
Mrc(MrcData);
}

View File

@@ -0,0 +1,41 @@
/** @file
Framework PEIM to initialize memory on an DDR2 SDRAM Memory Controller.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _PEI_QNC_MEMORY_INIT_H_
#define _PEI_QNC_MEMORY_INIT_H_
//
// The package level header files this module uses
//
#include <PiPei.h>
#include <IntelQNCPeim.h>
//
// The protocols, PPI and GUID defintions for this module
//
#include <Ppi/QNCMemoryInit.h>
//
// The Library classes this module consumes
//
#include <Library/DebugLib.h>
#include <Library/PeimEntryPoint.h>
#include <Library/BaseMemoryLib.h>
VOID
EFIAPI
MrcStart (
IN OUT MRCParams_t *MrcData
);
#endif

View File

@@ -0,0 +1,76 @@
## @file
# This is the Memory Initialization Driver for Quark
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
################################################################################
#
# Defines Section - statements that will be processed to create a Makefile.
#
################################################################################
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = MemoryInitPei
FILE_GUID = D2C69B26-82E1-4a1b-AD35-ED0261B9F347
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
ENTRY_POINT = PeimMemoryInit
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[BuildOptions]
GCC:DEBUG_*_*_CC_FLAGS = -DGCC -Wno-unused-function
GCC:RELEASE_*_*_CC_FLAGS = -DNDEBUG -DGCC -Wno-unused-function
INTEL:RELEASE_*_*_CC_FLAGS = /D NDEBUG
MSFT:RELEASE_*_*_CC_FLAGS = /D NDEBUG
[Sources]
memory_options.h
platform.c
lprint.c
meminit.h
meminit.c
meminit_utils.h
meminit_utils.c
gen5_iosf_sb_definitions.h
general_definitions.h
io.h
core_types.h
prememinit.h
prememinit.c
mrc.h
mrc.c
hte.c
hte.h
MemoryInit.h
MemoryInit.c
[Packages]
QuarkSocPkg/QuarkSocPkg.dec
MdePkg/MdePkg.dec
[LibraryClasses]
PeimEntryPoint
DebugLib
BaseMemoryLib
[Ppis]
gQNCMemoryInitPpiGuid # PPI ALWAYS_PRODUCED
[Depex]
TRUE

View File

@@ -0,0 +1,49 @@
/** @file
Core types used in Mrc.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __MRC_CORE_TYPES_H
#define __MRC_CORE_TYPES_H
typedef char char_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef unsigned char bool;
typedef unsigned int size_t;
#ifdef ASM_INC
// Unfortunately h2inc has issue with long long
typedef struct uint64_s
{
uint32_t lo;
uint32_t hi;
}uint64_t;
#else
typedef unsigned long long uint64_t;
#endif
#ifdef SIM
// Native word length is 64bit in simulation environment
typedef uint64_t uintn_t;
#else
// Quark is 32bit
typedef uint32_t uintn_t;
#endif
#define PTR32(a) ((volatile uint32_t*)(uintn_t)(a))
#endif

View File

@@ -0,0 +1,744 @@
/************************************************************************
*
* Copyright (c) 2013-2015 Intel Corporation.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
* MCU register definition
*
************************************************************************/
#ifndef __IOSF_DEFINITIONS_H
#define __IOSF_DEFINITIONS_H
// Define each of the IOSF-SB register offsets used by MRC.
// MCU registers (DUNIT):
// ====
#define DRP 0x0000
#define DTR0 0x0001
#define DTR1 0x0002
#define DTR2 0x0003
#define DTR3 0x0004
#define DTR4 0x0005
#define DPMC0 0x0006
#define DPMC1 0x0007
#define DRFC 0x0008
#define DSCH 0x0009
#define DCAL 0x000A
#define DRMC 0x000B
#define PMSTS 0x000C
#define DCO 0x000F
#define DSTAT 0x0020
#define DECCCTRL 0x0060
#define DFUSESTAT 0x0070
#define SCRMSEED 0x0080
#define SCRMLO 0x0081
#define SCRMHI 0x0082
#define MCU_CH_OFFSET 0x0040
#define MCU_RK_OFFSET 0x0020
////
//
// BEGIN DUnit register definition
//
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t rank0Enabled :1; /**< BIT [0] Rank 0 Enable */
uint32_t rank1Enabled :1; /**< BIT [1] Rank 1 Enable */
uint32_t reserved0 :2;
uint32_t dimm0DevWidth :2; /**< BIT [5:4] DIMM 0 Device Width (Rank0&1) */
uint32_t dimm0DevDensity :2; /**< BIT [7:6] DIMM 0 Device Density */
uint32_t reserved1 :1;
uint32_t dimm1DevWidth :2; /**< BIT [10:9] DIMM 1 Device Width (Rank2&3) */
uint32_t dimm1DevDensity :2; /**< BIT [12:11] DIMM 1 Device Density */
uint32_t split64 :1; /**< BIT [13] split 64B transactions */
uint32_t addressMap :2; /**< BIT [15:14] Address Map select */
uint32_t reserved3 :14;
uint32_t mode32 :1; /**< BIT [30] Select 32bit data interface*/
uint32_t reserved4 :1;
} field;
} RegDRP; /**< DRAM Rank Population and Interface Register */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t dramFrequency :2; /**< DRAM Frequency (000=800,001=1033,010=1333) */
uint32_t reserved1 :2;
uint32_t tRP :4; /**< bit [7:4] Precharge to Activate Delay */
uint32_t tRCD :4; /**< bit [11:8] Activate to CAS Delay */
uint32_t tCL :3; /**< bit [14:12] CAS Latency */
uint32_t reserved4 :1;
uint32_t tXS :1; /**< SRX Delay */
uint32_t reserved5 :1;
uint32_t tXSDLL :1; /**< SRX To DLL Delay */
uint32_t reserved6 :1;
uint32_t tZQCS :1; /**< bit [20] ZQTS recovery Latncy */
uint32_t reserved7 :1;
uint32_t tZQCL :1; /**< bit [22] ZQCL recovery Latncy */
uint32_t reserved8 :1;
uint32_t pmeDelay :2; /**< bit [25:24] Power mode entry delay */
uint32_t reserved9 :2;
uint32_t CKEDLY :4; /**< bit [31:28] */
} field;
} RegDTR0; /**< DRAM Timing Register 0 */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t tWCL :3; /**< bit [2:0] CAS Write Latency */
uint32_t reserved1 :1;
uint32_t tCMD :2; /**< bit [5:4] Command transport duration */
uint32_t reserved2 :2;
uint32_t tWTP :4; /**< Write to Precharge */
uint32_t tCCD :2; /**< CAS to CAS delay */
uint32_t reserved4 :2;
uint32_t tFAW :4; /**< Four bank Activation Window*/
uint32_t tRAS :4; /**< Row Activation Period: */
uint32_t tRRD :2; /**<Row activation to Row activation Delay */
uint32_t reserved5 :2;
uint32_t tRTP :3; /**<Read to Precharge Delay */
uint32_t reserved6 :1;
} field;
} RegDTR1; /**< DRAM Timing Register 1 */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t tRRDR :3; /**< RD to RD from different ranks, same DIMM */
uint32_t reserved1 :5;
uint32_t tWWDR :3; /**< WR to WR from different ranks, same DIMM. */
uint32_t reserved3 :5;
uint32_t tRWDR :4; /**< bit [19:16] RD to WR from different ranks, same DIMM. */
uint32_t reserved5 :12;
} field;
} RegDTR2; /**< DRAM Timing Register 2 */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t tWRDR :3; /**< WR to RD from different ranks, same DIMM. */
uint32_t reserved1 :1;
uint32_t tWRDD :3; /**< WR to RD from different DIMM. */
uint32_t reserved2 :1;
uint32_t tRWSR :4; /**< RD to WR Same Rank. */
uint32_t reserved3 :1;
uint32_t tWRSR :4; /**< WR to RD Same Rank. */
uint32_t reserved4 :5;
uint32_t tXP :2; /**< Time from CKE set on to any command. */
uint32_t PWD_DLY :4; /**< Extended Power-Down Delay. */
uint32_t EnDeRate :1;
uint32_t DeRateOvr :1;
uint32_t DeRateStat :1;
uint32_t reserved5 :1;
} field;
} RegDTR3; /**< DRAM Timing Register 3 */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t WRODTSTRT :2; /**< WR command to ODT assert delay */
uint32_t reserved1 :2;
uint32_t WRODTSTOP :3; /**< Write command to ODT de-assert delay. */
uint32_t reserved2 :1;
uint32_t RDODTSTRT :3; /**< Read command to ODT assert delay */
uint32_t reserved3 :1;
uint32_t RDODTSTOP :3; /**< Read command to ODT de-assert delay */
uint32_t ODTDIS :1; /**< ODT disable */
uint32_t TRGSTRDIS :1; /**< Write target rank is not stretched */
uint32_t RDODTDIS :1; /**< Disable Read ODT */
uint32_t WRBODTDIS :1; /**< Disable Write ODT */
uint32_t reserved5 :13;
} field;
} RegDTR4; /**< DRAM Timing Register 3 */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t SREntryDelay :8; /**< Self-Refresh Entry Delay: */
uint32_t powerModeOpCode :5; /**< SPID Power Mode Opcode */
uint32_t reserved1 :3;
uint32_t PCLSTO :3; /**< Page Close Timeout Period */
uint32_t reserved2 :1;
uint32_t PCLSWKOK :1; /**< Wake Allowed For Page Close Timeout */
uint32_t PREAPWDEN :1; /**< Send Precharge All to rank before entering Power-Down mode. */
uint32_t reserved3 :1;
uint32_t DYNSREN :1; /**< Dynamic Self-Refresh */
uint32_t CLKGTDIS :1; /**< Clock Gating Disabled*/
uint32_t DISPWRDN :1; /**< Disable Power Down*/
uint32_t reserved4 :2;
uint32_t REUTCLKGTDIS :1;
uint32_t ENPHYCLKGATE :1;
uint32_t reserved5 :2;
} field;
} RegDPMC0; /**< DRAM Power Management Control Register 0 */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t REFWMLO :4; /**< Refresh Opportunistic Watermark */
uint32_t REFWMHI :4; /**< Refresh High Watermark*/
uint32_t REFWMPNC :4; /**< Refresh Panic Watermark */
uint32_t tREFI :3; /**< bit [14:12] Refresh Period */
uint32_t reserved1 :1;
uint32_t REFCNTMAX :2; /**< Refresh Max tREFI Interval */
uint32_t reserved2 :2;
uint32_t REFSKEWDIS :1; /**< tREFI counters */
uint32_t REFDBTCLR :1;
uint32_t reserved3 :2;
uint32_t CuRefRate :3;
uint32_t DisRefBW :1;
uint32_t reserved4 :4;
} field;
} RegDRCF; /**< DRAM Refresh Control Register*/
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t reserved1 :8;
uint32_t ZQCINT :3; /**< ZQ Calibration Short Interval: */
uint32_t reserved2 :1;
uint32_t SRXZQCL :2; /** < ZQ Calibration Length */
uint32_t ZQCalType :1;
uint32_t ZQCalStart :1;
uint32_t TQPollStart :1;
uint32_t TQPollRS :2;
uint32_t reserved3 :5;
uint32_t MRRData :8; /**< bit[31:24] */
} field;
} RegDCAL; /**< DRAM Calibration Control*/
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t OOOAGETRH :5; /**< Out-of-Order Aging Threshold */
uint32_t reserved1 :3;
uint32_t OOODIS :1; /**< Out-of-Order Disable */
uint32_t OOOST3DIS :1; /**< Out-of-Order Disabled when RequestBD_Status is 3. */
uint32_t reserved2 :2;
uint32_t NEWBYPDIS :1;
uint32_t reserved3 :3;
uint32_t IPREQMAX :3; /** < Max In-Progress Requests stored in MC */
uint32_t reserved4 :13;
} field;
} RegDSCH; /**< DRAM Scheduler Control Register */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t DRPLOCK :1; /**< DRP lock bit */
uint32_t reserved1 :7;
uint32_t REUTLOCK :1; /**< REUT lock bit */
uint32_t reserved2 :19;
uint32_t PMICTL :1; /**< PRI Control Select: 0-memory_manager, 1-hte */
uint32_t PMIDIS :1; /**< PMIDIS Should be set is using IOSF-SB RW */
uint32_t DIOIC :1; /**< DDRIO initialization is complete */
uint32_t IC :1; /**< D-unit Initialization Complete */
} field;
} RegDCO; /**< DRAM Controller Operation Register*/
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t SBEEN :1; /**< Enable Single Bit Error Detection and Correction */
uint32_t DBEEN :1; /**< Enable Double Bit Error Detection */
uint32_t CBOEN :3; /**< Enable ECC Check Bits Override */
uint32_t SYNSEL :2; /**< ECC Syndrome Bits Select for Observation */
uint32_t CLRSBECNT :1; /**< Clear ECC Single Bit Error Count */
uint32_t CBOV :8; /**< ECC Check Bits Override Value */
uint32_t reserved1 :1; /**< */
uint32_t ENCBGEN :1; /**< Enable Generation of ECC Check Bits */
uint32_t ENCBGESWIZ :1; /**< Enable Same Chip ECC Byte Lane Swizzle */
} field;
} RegDECCCTRL; /**< DRAM ECC Control Register */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t FUS_DUN_ECC_DIS :1;
uint32_t FUS_DUN_MAX_SUPPORTED_MEMORY :3;
uint32_t FUS_DUN_MAX_DEVDEN :2;
uint32_t RESERVED1 :1;
uint32_t FUS_DUN_RANK2_DIS :1;
uint32_t FUS_DUN_OOO_DIS :1;
uint32_t FUS_DUN_MEMX8_DIS :1;
uint32_t FUS_DUN_MEMX16_DIS :1;
uint32_t RESERVED2 :1;
uint32_t FUS_DUN_1N_DIS :1;
uint32_t FUS_DUN_DQ_SCRAMBLER_DIS :1;
uint32_t RESERVED3 :1;
uint32_t FUS_DUN_32BIT_DRAM_IFC :1;
} field;
} RegDFUSESTAT;
#pragma pack()
//
// END DUnit register definition
//
////
////
//
// DRAM Initialization Structures used in JEDEC Message Bus Commands
//
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
unsigned command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
unsigned bankAddress :3; /**< Bank Address (BA[2:0]) */
unsigned BL :2; /**< Burst Length, CDV:1*/
unsigned CL :1; /**< CL Reserved CDV:0 */
unsigned RBT :1; /**< Read Burst Type */
unsigned casLatency :3; /**< cas Latency */
unsigned TM :1; /**< Test mode */
unsigned dllReset :1; /**< DLL Reset */
unsigned writeRecovery :3; /**< Write Recovery for Auto Pre-Charge: 001=2,010=3,011=4,100=5,101=6 */
unsigned PPD :1; /**< DLL Control for Precharge Power-Down CDV:1 */
unsigned reserved1 :3;
unsigned rankSelect :4; /**< Rank Select */
unsigned reserved2 :6;
} field;
} DramInitDDR3MRS0; /**< DDR3 Mode Register Set (MRS) Command */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
unsigned command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
unsigned bankAddress :3; /**< Bank Address (BA[2:0]) */
unsigned dllEnabled :1; /**< CDV=0 */
unsigned DIC0 :1; /**< Output Driver Impedance Control */
unsigned rttNom0 :1; /**< RTT_nom[0] */
unsigned MRC_AL :2; /**< Additive Latency = 0 */
unsigned DIC1 :1; /**< Reserved */
unsigned rttNom1 :1; /**< RTT_nom[1] */
unsigned wlEnabled :1; /**< Write Leveling Enable */
unsigned reserved1 :1;
unsigned rttNom2 :1; /** < RTT_nom[2] */
unsigned reserved2 :1;
unsigned TDQS :1; /**< TDQS Enable */
unsigned Qoff :1; /**< Output Buffers Disabled */
unsigned reserved3 :3;
unsigned rankSelect :4; /**< Rank Select */
unsigned reserved4 :6;
} field;
} DramInitDDR3EMR1; /**< DDR3 Extended Mode Register 1 Set (EMRS1) Command */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
uint32_t bankAddress :3; /**< Bank Address (BA[2:0]) */
uint32_t PASR :3; /**< Partial Array Self-Refresh */
uint32_t CWL :3; /**< CAS Write Latency */
uint32_t ASR :1; /**< Auto Self-Refresh */
uint32_t SRT :1; /**< SR Temperature Range = 0*/
uint32_t reserved1 :1;
uint32_t rtt_WR :2; /**< Rtt_WR */
uint32_t reserved2 :5;
uint32_t rankSelect :4; /**< Rank Select */
uint32_t reserved3 :6;
} field;
} DramInitDDR3EMR2; /**< DDR3 Extended Mode Register 2 Set (EMRS2) Command */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
uint32_t bankAddress :3; /**< Bank Address (BA[2:0]) */
uint32_t MPR_Location :2; /**< MPR Location */
uint32_t MPR :1; /**< MPR: Multi Purpose Register */
uint32_t reserved1 :13;
uint32_t rankSelect :4; /**< Rank Select */
uint32_t reserved2 :6;
} field;
} DramInitDDR3EMR3; /**< DDR3 Extended Mode Register 2 Set (EMRS2) Command */
#pragma pack()
#pragma pack(1)
typedef union {
uint32_t raw;
struct {
uint32_t command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110 - ZQ Calibration,111-NOP */
uint32_t bankAddress :3; /**< Bank Address (BA[2:0]) */
uint32_t multAddress :16; /**< Multiplexed Address (MA[14:0]) */
uint32_t rankSelect :2; /**< Rank Select */
uint32_t reserved3 :8;
} field;
} DramInitMisc; /**< Miscellaneous DDRx Initialization Command */
#pragma pack()
//
// Construct DRAM init command using DramInitXxxx pattern
//
#define DCMD_MRS1(rnk,dat) (0 | ((rnk)<<22) | (1<<3) | ((dat)<<6))
#define DCMD_REF(rnk) (1 | ((rnk)<<22))
#define DCMD_PRE(rnk) (2 | ((rnk)<<22))
#define DCMD_PREA(rnk) (2 | ((rnk)<<22) | (BIT10<<6))
#define DCMD_ACT(rnk,row) (3 | ((rnk)<<22) | ((row)<<6))
#define DCMD_WR(rnk,col) (4 | ((rnk)<<22) | ((col)<<6))
#define DCMD_RD(rnk,col) (5 | ((rnk)<<22) | ((col)<<6))
#define DCMD_ZQCS(rnk) (6 | ((rnk)<<22))
#define DCMD_ZQCL(rnk) (6 | ((rnk)<<22) | (BIT10<<6))
#define DCMD_NOP(rnk) (7 | ((rnk)<<22))
#define DDR3_EMRS1_DIC_40 (0)
#define DDR3_EMRS1_DIC_34 (1)
#define DDR3_EMRS2_RTTWR_60 (BIT9)
#define DDR3_EMRS2_RTTWR_120 (BIT10)
#define DDR3_EMRS1_RTTNOM_0 (0)
#define DDR3_EMRS1_RTTNOM_60 (BIT2)
#define DDR3_EMRS1_RTTNOM_120 (BIT6)
#define DDR3_EMRS1_RTTNOM_40 (BIT6|BIT2)
#define DDR3_EMRS1_RTTNOM_20 (BIT9)
#define DDR3_EMRS1_RTTNOM_30 (BIT9|BIT2)
//
// END DRAM Init...
//
////
// HOST_BRIDGE registers:
#define HMBOUND 0x0020 //ok
// MEMORY_MANAGER registers:
#define BCTRL 0x0004
#define BWFLUSH 0x0008
#define BDEBUG1 0x00C4
////
//
// BEGIN DDRIO registers
//
// DDR IOs & COMPs:
#define DDRIODQ_BL_OFFSET 0x0800
#define DDRIODQ_CH_OFFSET ((NUM_BYTE_LANES/2) * DDRIODQ_BL_OFFSET)
#define DDRIOCCC_CH_OFFSET 0x0800
#define DDRCOMP_CH_OFFSET 0x0100
// CH0-BL01-DQ
#define DQOBSCKEBBCTL 0x0000
#define DQDLLTXCTL 0x0004
#define DQDLLRXCTL 0x0008
#define DQMDLLCTL 0x000C
#define B0RXIOBUFCTL 0x0010
#define B0VREFCTL 0x0014
#define B0RXOFFSET1 0x0018
#define B0RXOFFSET0 0x001C
#define B1RXIOBUFCTL 0x0020
#define B1VREFCTL 0x0024
#define B1RXOFFSET1 0x0028
#define B1RXOFFSET0 0x002C
#define DQDFTCTL 0x0030
#define DQTRAINSTS 0x0034
#define B1DLLPICODER0 0x0038
#define B0DLLPICODER0 0x003C
#define B1DLLPICODER1 0x0040
#define B0DLLPICODER1 0x0044
#define B1DLLPICODER2 0x0048
#define B0DLLPICODER2 0x004C
#define B1DLLPICODER3 0x0050
#define B0DLLPICODER3 0x0054
#define B1RXDQSPICODE 0x0058
#define B0RXDQSPICODE 0x005C
#define B1RXDQPICODER32 0x0060
#define B1RXDQPICODER10 0x0064
#define B0RXDQPICODER32 0x0068
#define B0RXDQPICODER10 0x006C
#define B01PTRCTL0 0x0070
#define B01PTRCTL1 0x0074
#define B01DBCTL0 0x0078
#define B01DBCTL1 0x007C
#define B0LATCTL0 0x0080
#define B1LATCTL0 0x0084
#define B01LATCTL1 0x0088
#define B0ONDURCTL 0x008C
#define B1ONDURCTL 0x0090
#define B0OVRCTL 0x0094
#define B1OVRCTL 0x0098
#define DQCTL 0x009C
#define B0RK2RKCHGPTRCTRL 0x00A0
#define B1RK2RKCHGPTRCTRL 0x00A4
#define DQRK2RKCTL 0x00A8
#define DQRK2RKPTRCTL 0x00AC
#define B0RK2RKLAT 0x00B0
#define B1RK2RKLAT 0x00B4
#define DQCLKALIGNREG0 0x00B8
#define DQCLKALIGNREG1 0x00BC
#define DQCLKALIGNREG2 0x00C0
#define DQCLKALIGNSTS0 0x00C4
#define DQCLKALIGNSTS1 0x00C8
#define DQCLKGATE 0x00CC
#define B0COMPSLV1 0x00D0
#define B1COMPSLV1 0x00D4
#define B0COMPSLV2 0x00D8
#define B1COMPSLV2 0x00DC
#define B0COMPSLV3 0x00E0
#define B1COMPSLV3 0x00E4
#define DQVISALANECR0TOP 0x00E8
#define DQVISALANECR1TOP 0x00EC
#define DQVISACONTROLCRTOP 0x00F0
#define DQVISALANECR0BL 0x00F4
#define DQVISALANECR1BL 0x00F8
#define DQVISACONTROLCRBL 0x00FC
#define DQTIMINGCTRL 0x010C
// CH0-ECC
#define ECCDLLTXCTL 0x2004
#define ECCDLLRXCTL 0x2008
#define ECCMDLLCTL 0x200C
#define ECCB1DLLPICODER0 0x2038
#define ECCB1DLLPICODER1 0x2040
#define ECCB1DLLPICODER2 0x2048
#define ECCB1DLLPICODER3 0x2050
#define ECCB01DBCTL0 0x2078
#define ECCB01DBCTL1 0x207C
#define ECCCLKALIGNREG0 0x20B8
#define ECCCLKALIGNREG1 0x20BC
#define ECCCLKALIGNREG2 0x20C0
// CH0-CMD
#define CMDOBSCKEBBCTL 0x4800
#define CMDDLLTXCTL 0x4808
#define CMDDLLRXCTL 0x480C
#define CMDMDLLCTL 0x4810
#define CMDRCOMPODT 0x4814
#define CMDDLLPICODER0 0x4820
#define CMDDLLPICODER1 0x4824
#define CMDCFGREG0 0x4840
#define CMDPTRREG 0x4844
#define CMDCLKALIGNREG0 0x4850
#define CMDCLKALIGNREG1 0x4854
#define CMDCLKALIGNREG2 0x4858
#define CMDPMCONFIG0 0x485C
#define CMDPMDLYREG0 0x4860
#define CMDPMDLYREG1 0x4864
#define CMDPMDLYREG2 0x4868
#define CMDPMDLYREG3 0x486C
#define CMDPMDLYREG4 0x4870
#define CMDCLKALIGNSTS0 0x4874
#define CMDCLKALIGNSTS1 0x4878
#define CMDPMSTS0 0x487C
#define CMDPMSTS1 0x4880
#define CMDCOMPSLV 0x4884
#define CMDBONUS0 0x488C
#define CMDBONUS1 0x4890
#define CMDVISALANECR0 0x4894
#define CMDVISALANECR1 0x4898
#define CMDVISACONTROLCR 0x489C
#define CMDCLKGATE 0x48A0
#define CMDTIMINGCTRL 0x48A4
// CH0-CLK-CTL
#define CCOBSCKEBBCTL 0x5800
#define CCRCOMPIO 0x5804
#define CCDLLTXCTL 0x5808
#define CCDLLRXCTL 0x580C
#define CCMDLLCTL 0x5810
#define CCRCOMPODT 0x5814
#define CCDLLPICODER0 0x5820
#define CCDLLPICODER1 0x5824
#define CCDDR3RESETCTL 0x5830
#define CCCFGREG0 0x5838
#define CCCFGREG1 0x5840
#define CCPTRREG 0x5844
#define CCCLKALIGNREG0 0x5850
#define CCCLKALIGNREG1 0x5854
#define CCCLKALIGNREG2 0x5858
#define CCPMCONFIG0 0x585C
#define CCPMDLYREG0 0x5860
#define CCPMDLYREG1 0x5864
#define CCPMDLYREG2 0x5868
#define CCPMDLYREG3 0x586C
#define CCPMDLYREG4 0x5870
#define CCCLKALIGNSTS0 0x5874
#define CCCLKALIGNSTS1 0x5878
#define CCPMSTS0 0x587C
#define CCPMSTS1 0x5880
#define CCCOMPSLV1 0x5884
#define CCCOMPSLV2 0x5888
#define CCCOMPSLV3 0x588C
#define CCBONUS0 0x5894
#define CCBONUS1 0x5898
#define CCVISALANECR0 0x589C
#define CCVISALANECR1 0x58A0
#define CCVISACONTROLCR 0x58A4
#define CCCLKGATE 0x58A8
#define CCTIMINGCTL 0x58AC
// COMP
#define CMPCTRL 0x6800
#define SOFTRSTCNTL 0x6804
#define MSCNTR 0x6808
#define NMSCNTRL 0x680C
#define LATCH1CTL 0x6814
#define COMPVISALANECR0 0x681C
#define COMPVISALANECR1 0x6820
#define COMPVISACONTROLCR 0x6824
#define COMPBONUS0 0x6830
#define TCOCNTCTRL 0x683C
#define DQANAODTPUCTL 0x6840
#define DQANAODTPDCTL 0x6844
#define DQANADRVPUCTL 0x6848
#define DQANADRVPDCTL 0x684C
#define DQANADLYPUCTL 0x6850
#define DQANADLYPDCTL 0x6854
#define DQANATCOPUCTL 0x6858
#define DQANATCOPDCTL 0x685C
#define CMDANADRVPUCTL 0x6868
#define CMDANADRVPDCTL 0x686C
#define CMDANADLYPUCTL 0x6870
#define CMDANADLYPDCTL 0x6874
#define CLKANAODTPUCTL 0x6880
#define CLKANAODTPDCTL 0x6884
#define CLKANADRVPUCTL 0x6888
#define CLKANADRVPDCTL 0x688C
#define CLKANADLYPUCTL 0x6890
#define CLKANADLYPDCTL 0x6894
#define CLKANATCOPUCTL 0x6898
#define CLKANATCOPDCTL 0x689C
#define DQSANAODTPUCTL 0x68A0
#define DQSANAODTPDCTL 0x68A4
#define DQSANADRVPUCTL 0x68A8
#define DQSANADRVPDCTL 0x68AC
#define DQSANADLYPUCTL 0x68B0
#define DQSANADLYPDCTL 0x68B4
#define DQSANATCOPUCTL 0x68B8
#define DQSANATCOPDCTL 0x68BC
#define CTLANADRVPUCTL 0x68C8
#define CTLANADRVPDCTL 0x68CC
#define CTLANADLYPUCTL 0x68D0
#define CTLANADLYPDCTL 0x68D4
#define CHNLBUFSTATIC 0x68F0
#define COMPOBSCNTRL 0x68F4
#define COMPBUFFDBG0 0x68F8
#define COMPBUFFDBG1 0x68FC
#define CFGMISCCH0 0x6900
#define COMPEN0CH0 0x6904
#define COMPEN1CH0 0x6908
#define COMPEN2CH0 0x690C
#define STATLEGEN0CH0 0x6910
#define STATLEGEN1CH0 0x6914
#define DQVREFCH0 0x6918
#define CMDVREFCH0 0x691C
#define CLKVREFCH0 0x6920
#define DQSVREFCH0 0x6924
#define CTLVREFCH0 0x6928
#define TCOVREFCH0 0x692C
#define DLYSELCH0 0x6930
#define TCODRAMBUFODTCH0 0x6934
#define CCBUFODTCH0 0x6938
#define RXOFFSETCH0 0x693C
#define DQODTPUCTLCH0 0x6940
#define DQODTPDCTLCH0 0x6944
#define DQDRVPUCTLCH0 0x6948
#define DQDRVPDCTLCH0 0x694C
#define DQDLYPUCTLCH0 0x6950
#define DQDLYPDCTLCH0 0x6954
#define DQTCOPUCTLCH0 0x6958
#define DQTCOPDCTLCH0 0x695C
#define CMDDRVPUCTLCH0 0x6968
#define CMDDRVPDCTLCH0 0x696C
#define CMDDLYPUCTLCH0 0x6970
#define CMDDLYPDCTLCH0 0x6974
#define CLKODTPUCTLCH0 0x6980
#define CLKODTPDCTLCH0 0x6984
#define CLKDRVPUCTLCH0 0x6988
#define CLKDRVPDCTLCH0 0x698C
#define CLKDLYPUCTLCH0 0x6990
#define CLKDLYPDCTLCH0 0x6994
#define CLKTCOPUCTLCH0 0x6998
#define CLKTCOPDCTLCH0 0x699C
#define DQSODTPUCTLCH0 0x69A0
#define DQSODTPDCTLCH0 0x69A4
#define DQSDRVPUCTLCH0 0x69A8
#define DQSDRVPDCTLCH0 0x69AC
#define DQSDLYPUCTLCH0 0x69B0
#define DQSDLYPDCTLCH0 0x69B4
#define DQSTCOPUCTLCH0 0x69B8
#define DQSTCOPDCTLCH0 0x69BC
#define CTLDRVPUCTLCH0 0x69C8
#define CTLDRVPDCTLCH0 0x69CC
#define CTLDLYPUCTLCH0 0x69D0
#define CTLDLYPDCTLCH0 0x69D4
#define FNLUPDTCTLCH0 0x69F0
// PLL
#define MPLLCTRL0 0x7800
#define MPLLCTRL1 0x7808
#define MPLLCSR0 0x7810
#define MPLLCSR1 0x7814
#define MPLLCSR2 0x7820
#define MPLLDFT 0x7828
#define MPLLMON0CTL 0x7830
#define MPLLMON1CTL 0x7838
#define MPLLMON2CTL 0x783C
#define SFRTRIM 0x7850
#define MPLLDFTOUT0 0x7858
#define MPLLDFTOUT1 0x785C
#define MASTERRSTN 0x7880
#define PLLLOCKDEL 0x7884
#define SFRDEL 0x7888
#define CRUVISALANECR0 0x78F0
#define CRUVISALANECR1 0x78F4
#define CRUVISACONTROLCR 0x78F8
#define IOSFVISALANECR0 0x78FC
#define IOSFVISALANECR1 0x7900
#define IOSFVISACONTROLCR 0x7904
//
// END DDRIO registers
//
////
#endif

View File

@@ -0,0 +1,90 @@
/************************************************************************
*
* Copyright (c) 2013-2015 Intel Corporation.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
************************************************************************/
#ifndef __GENERAL_DEFINITIONS_H
#define __GENERAL_DEFINITIONS_H
#undef BIT0
#undef BIT1
#undef BIT2
#undef BIT3
#undef BIT4
#undef BIT5
#undef BIT6
#undef BIT7
#undef BIT8
#undef BIT9
#undef BIT10
#undef BIT11
#undef BIT12
#undef BIT13
#undef BIT14
#undef BIT15
#undef BIT16
#undef BIT17
#undef BIT18
#undef BIT19
#undef BIT20
#undef BIT21
#undef BIT22
#undef BIT23
#undef BIT24
#undef BIT25
#undef BIT26
#undef BIT27
#undef BIT28
#undef BIT29
#undef BIT30
#undef BIT31
// defines
#define BIT0 0x00000001U
#define BIT1 0x00000002U
#define BIT2 0x00000004U
#define BIT3 0x00000008U
#define BIT4 0x00000010U
#define BIT5 0x00000020U
#define BIT6 0x00000040U
#define BIT7 0x00000080U
#define BIT8 0x00000100U
#define BIT9 0x00000200U
#define BIT10 0x00000400U
#define BIT11 0x00000800U
#define BIT12 0x00001000U
#define BIT13 0x00002000U
#define BIT14 0x00004000U
#define BIT15 0x00008000U
#define BIT16 0x00010000U
#define BIT17 0x00020000U
#define BIT18 0x00040000U
#define BIT19 0x00080000U
#define BIT20 0x00100000U
#define BIT21 0x00200000U
#define BIT22 0x00400000U
#define BIT23 0x00800000U
#define BIT24 0x01000000U
#define BIT25 0x02000000U
#define BIT26 0x04000000U
#define BIT27 0x08000000U
#define BIT28 0x10000000U
#define BIT29 0x20000000U
#define BIT30 0x40000000U
#define BIT31 0x80000000U
#define true 0x01
#define false 0x00
#endif

View File

@@ -0,0 +1,542 @@
/** @file
HTE handling routines for MRC use.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "mrc.h"
#include "memory_options.h"
#include "io.h"
#include "hte.h"
#ifdef SIM
VOID delay_n(UINT32 nanoseconds);
#define MySimStall(a) delay_n(a/1000)
#endif
STATIC VOID EnableAllHteErrors(
UINT8 Mask)
/*++
Routine Description:
This function enables to HTE to detect all possible errors for
the given training parameters (per-bit or full byte lane).
Returns:
None
--*/
{
isbW32m(HTE, 0x000200A2, 0xFFFFFFFF);
isbW32m(HTE, 0x000200A3, 0x000000FF);
isbW32m(HTE, 0x000200A4, 0x00000000);
}
STATIC UINT32 CheckHteErrors(
VOID)
/*++
Routine Description:
This function goes and reads the HTE register in order to find any error
Returns:
The errors detected in the HTE status register
--*/
{
return isbR32m(HTE, 0x000200A7);
}
STATIC VOID WaitForHteComplete(
VOID)
/*++
Routine Description:
This function waits until HTE finishes
Returns:
None
--*/
{
UINT32 Tmp;
ENTERFN();
//
// Is the test done?
//
do
{
#ifdef SIM
MySimStall (35000); // 35 ns delay
#endif
} while (0 != (isbR32m(HTE, 0x00020012) & BIT30));
Tmp = isbR32m(HTE, 0x00020011);
Tmp = Tmp | BIT9;
Tmp = Tmp & ~(BIT13 | BIT12);
isbW32m(HTE, 0x00020011, Tmp);
LEAVEFN();
}
STATIC VOID ClearHteErrorRegisters(
VOID)
/*++
Routine Description:
Clears registers related with errors in the HTE.
Returns:
None
--*/
{
UINT32 Tmp;
//
// Clear all HTE errors and enable error checking
// for burst and chunk.
//
Tmp = isbR32m(HTE, 0x000200A1);
Tmp |= BIT8;
isbW32m(HTE, 0x000200A1, Tmp);
}
UINT32 HteMemInit(
MRC_PARAMS *CurrentMrcData,
UINT8 MemInitFlag,
UINT8 HaltHteEngineOnError)
/*++
Routine Description:
Uses HW HTE engine to initialize or test all memory attached to a given DUNIT.
If MemInitFlag is 1, this routine writes 0s to all memory locations to initialize
ECC.
If MemInitFlag is 0, this routine will send an 5AA55AA5 pattern to all memory
locations on the RankMask and then read it back. Then it sends an A55AA55A
pattern to all memory locations on the RankMask and reads it back.
Arguments:
CurrentMrcData: Host struture for all MRC global data.
MemInitFlag: 0 for memtest, 1 for meminit.
HaltHteEngineOnError: Halt the HTE engine on first error observed, or keep
running to see how many errors are found.
Returns:
Errors register showing HTE failures.
Also prints out which rank failed the HTE test if failure occurs.
For rank detection to work, the address map must be left in its default
state. If MRC changes the address map, this function must be modified
to change it back to default at the beginning, then restore it at the end.
--*/
{
UINT32 Offset;
UINT8 TestNum;
UINT8 i;
//
// Clear out the error registers at the start of each memory
// init or memory test run.
//
ClearHteErrorRegisters();
isbW32m(HTE, 0x00020062, 0x00000015);
for (Offset = 0x80; Offset <= 0x8F; Offset++)
{
isbW32m(HTE, Offset, ((Offset & 1) ? 0xA55A : 0x5AA5));
}
isbW32m(HTE, 0x00020021, 0x00000000);
#ifdef QUICKSIM
// Just do 4 cache lines for simulation memtest to save time.
isbW32m(HTE, 0x00020022, 4-1);
#else
isbW32m(HTE, 0x00020022, (CurrentMrcData->mem_size >> 6) - 1);
#endif
isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
isbW32m(HTE, 0x00020066, 0x03000000);
switch (MemInitFlag)
{
case MrcMemInit:
TestNum = 1; // Only 1 write pass through memory is needed to initialize ECC.
break;
case MrcMemTest:
TestNum = 4; // Write/read then write/read with inverted pattern.
break;
default:
DPF(D_INFO, "Unknown parameter for MemInitFlag: %d\n", MemInitFlag);
return 0xFFFFFFFF;
break;
}
DPF(D_INFO, "HteMemInit");
for (i = 0; i < TestNum; i++)
{
DPF(D_INFO, ".");
if (i == 0)
{
isbW32m(HTE, 0x00020061, 0x00000000);
isbW32m(HTE, 0x00020020, 0x00110010);
}
else if (i == 1)
{
isbW32m(HTE, 0x00020061, 0x00000000);
isbW32m(HTE, 0x00020020, 0x00010010);
}
else if (i == 2)
{
isbW32m(HTE, 0x00020061, 0x00010100);
isbW32m(HTE, 0x00020020, 0x00110010);
}
else
{
isbW32m(HTE, 0x00020061, 0x00010100);
isbW32m(HTE, 0x00020020, 0x00010010);
}
isbW32m(HTE, 0x00020011, 0x00111000);
isbW32m(HTE, 0x00020011, 0x00111100);
WaitForHteComplete();
//
// If this is a READ pass, check for errors at the end.
//
if ((i % 2) == 1)
{
//
// Return immediately if error.
//
if (CheckHteErrors())
{
break;
}
}
}
DPF(D_INFO, "done\n", i);
return CheckHteErrors();
}
STATIC UINT16 BasicDataCompareHte(
MRC_PARAMS *CurrentMrcData,
UINT32 Address,
UINT8 FirstRun,
UINT8 Mode)
/*++
Routine Description:
Execute basic single cache line memory write/read/verify test using simple constant
pattern (different for READ_RAIN and WRITE_TRAIN modes.
See BasicWriteReadHTE which is external visible wrapper.
Arguments:
CurrentMrcData: Host struture for all MRC global data.
Address: memory adress being tested (must hit specific channel/rank)
FirstRun: If set then hte registers are configured, otherwise
it is assumed configuration is done and just re-run the test.
Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)
Returns:
Returns byte lane failure on each bit (for Quark only bit0 and bit1)
--*/
{
UINT32 Pattern;
UINT32 Offset;
if (FirstRun)
{
isbW32m(HTE, 0x00020020, 0x01B10021);
isbW32m(HTE, 0x00020021, 0x06000000);
isbW32m(HTE, 0x00020022, Address >> 6);
isbW32m(HTE, 0x00020062, 0x00800015);
isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
isbW32m(HTE, 0x00020061, 0x00030008);
if (Mode == WRITE_TRAIN)
{
Pattern = 0xC33C0000;
}
else // READ_TRAIN
{
Pattern = 0xAA5555AA;
}
for (Offset = 0x80; Offset <= 0x8F; Offset++)
{
isbW32m(HTE, Offset, Pattern);
}
}
isbW32m(HTE, 0x000200A1, 0xFFFF1000);
isbW32m(HTE, 0x00020011, 0x00011000);
isbW32m(HTE, 0x00020011, 0x00011100);
WaitForHteComplete();
//
// Return bits 15:8 of HTE_CH0_ERR_XSTAT to check for any bytelane errors.
//
return ((CheckHteErrors() >> 8) & 0xFF);
}
STATIC UINT16 ReadWriteDataCompareHte(
MRC_PARAMS *CurrentMrcData,
UINT32 Address,
UINT8 LoopCount,
UINT32 LfsrSeedVictim,
UINT32 LfsrSeedAggressor,
UINT8 VictimBit,
UINT8 FirstRun)
/*++
Routine Description:
Examines single cache line memory with write/read/verify test using
multiple data patterns (victim-aggressor algorithm).
See WriteStressBitLanesHTE which is external visible wrapper.
Arguments:
CurrentMrcData: host struture for all MRC global data.
Address: memory adress being tested (must hit specific channel/rank)
LoopCount: number of test iterations
LfsrSeedXxx: victim aggressor data pattern seed
VictimBit: should be 0 as auto rotate feature is in use.
FirstRun: If set then hte registers are configured, otherwise
it is assumed configuration is done and just re-run the test.
Returns:
Returns byte lane failure on each bit (for Quark only bit0 and bit1)
--*/
{
UINT32 Offset;
UINT32 Tmp;
if (FirstRun)
{
isbW32m(HTE, 0x00020020, 0x00910024);
isbW32m(HTE, 0x00020023, 0x00810024);
isbW32m(HTE, 0x00020021, 0x06070000);
isbW32m(HTE, 0x00020024, 0x06070000);
isbW32m(HTE, 0x00020022, Address >> 6);
isbW32m(HTE, 0x00020025, Address >> 6);
isbW32m(HTE, 0x00020062, 0x0000002A);
isbW32m(HTE, 0x00020063, LfsrSeedVictim);
isbW32m(HTE, 0x00020064, LfsrSeedAggressor);
isbW32m(HTE, 0x00020065, LfsrSeedVictim);
//
// Write the pattern buffers to select the victim bit. Start with bit0.
//
for (Offset = 0x80; Offset <= 0x8F; Offset++)
{
if ((Offset % 8) == VictimBit)
{
isbW32m(HTE, Offset, 0x55555555);
}
else
{
isbW32m(HTE, Offset, 0xCCCCCCCC);
}
}
isbW32m(HTE, 0x00020061, 0x00000000);
isbW32m(HTE, 0x00020066, 0x03440000);
isbW32m(HTE, 0x000200A1, 0xFFFF1000);
}
Tmp = 0x10001000 | (LoopCount << 16);
isbW32m(HTE, 0x00020011, Tmp);
isbW32m(HTE, 0x00020011, Tmp | BIT8);
WaitForHteComplete();
return (CheckHteErrors() >> 8) & 0xFF;
}
UINT16 BasicWriteReadHTE(
MRC_PARAMS *CurrentMrcData,
UINT32 Address,
UINT8 FirstRun,
UINT8 Mode)
/*++
Routine Description:
Execute basic single cache line memory write/read/verify test using simple constant
pattern (different for READ_RAIN and WRITE_TRAIN modes.
Arguments:
CurrentMrcData: Host struture for all MRC global data.
Address: memory adress being tested (must hit specific channel/rank)
FirstRun: If set then hte registers are configured, otherwise
it is assumed configuration is done and just re-run the test.
Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)
Returns:
Returns byte lane failure on each bit (for Quark only bit0 and bit1)
--*/
{
UINT16 ByteLaneErrors;
ENTERFN();
//
// Enable all error reporting in preparation for HTE test.
//
EnableAllHteErrors(0xFF);
ClearHteErrorRegisters();
ByteLaneErrors = BasicDataCompareHte(CurrentMrcData, Address, FirstRun,
Mode);
LEAVEFN();
return ByteLaneErrors;
}
UINT16 WriteStressBitLanesHTE(
MRC_PARAMS *CurrentMrcData,
UINT32 Address,
UINT8 FirstRun)
/*++
Routine Description:
Examines single cache line memory with write/read/verify test using
multiple data patterns (victim-aggressor algorithm).
Arguments:
CurrentMrcData: host struture for all MRC global data.
Address: memory adress being tested (must hit specific channel/rank)
FirstRun: If set then hte registers are configured, otherwise
it is assumed configuration is done and just re-run the test.
Returns:
Returns byte lane failure on each bit (for Quark only bit0 and bit1)
--*/
{
UINT16 ByteLaneErrors;
UINT8 VictimBit = 0;
ENTERFN();
//
// Enable all error reporting in preparation for HTE test.
//
EnableAllHteErrors(0xFF);
ClearHteErrorRegisters();
//
// Loop through each bit in the bytelane. Each pass creates a victim bit
// while keeping all other bits the same - as aggressors.
// AVN HTE adds an auto-rotate feature which allows us to program the entire victim/aggressor
// sequence in 1 step. The victim bit rotates on each pass so no need to have software implement
// a victim bit loop like on VLV.
//
ByteLaneErrors = ReadWriteDataCompareHte(CurrentMrcData, Address,
HTE_LOOP_CNT, HTE_LFSR_VICTIM_SEED, HTE_LFSR_AGRESSOR_SEED, VictimBit,
FirstRun);
LEAVEFN();
return ByteLaneErrors;
}
VOID HteMemOp(
UINT32 Address,
UINT8 FirstRun,
UINT8 IsWrite)
/*++
Routine Description:
Execute basic single cache line memory write or read.
This is just for receive enable / fine write levelling purpose.
Arguments:
CurrentMrcData: Host structure for all MRC global data.
Address: memory address used (must hit specific channel/rank)
FirstRun: If set then hte registers are configured, otherwise
it is assumed configuration is done and just re-run the test.
IsWrite: When non-zero memory write operation executed, otherwise read
Returns:
None
--*/
{
UINT32 Offset;
UINT32 Tmp;
EnableAllHteErrors(0xFF);
ClearHteErrorRegisters();
if (FirstRun)
{
Tmp = IsWrite ? 0x01110021 : 0x01010021;
isbW32m(HTE, 0x00020020, Tmp);
isbW32m(HTE, 0x00020021, 0x06000000);
isbW32m(HTE, 0x00020022, Address >> 6);
isbW32m(HTE, 0x00020062, 0x00800015);
isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
isbW32m(HTE, 0x00020061, 0x00030008);
for (Offset = 0x80; Offset <= 0x8F; Offset++)
{
isbW32m(HTE, Offset, 0xC33C0000);
}
}
isbW32m(HTE, 0x000200A1, 0xFFFF1000);
isbW32m(HTE, 0x00020011, 0x00011000);
isbW32m(HTE, 0x00020011, 0x00011100);
WaitForHteComplete();
}

View File

@@ -0,0 +1,72 @@
/** @file
HTE handling routines for MRC use.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __HTE_H
#define __HTE_H
#define STATIC static
#define VOID void
#if !defined(__GNUC__) && (__STDC_VERSION__ < 199901L)
typedef uint32_t UINT32;
typedef uint16_t UINT16;
typedef uint8_t UINT8;
#endif
typedef enum
{
MrcNoHaltSystemOnError,
MrcHaltSystemOnError,
MrcHaltHteEngineOnError,
MrcNoHaltHteEngineOnError
} HALT_TYPE;
typedef enum
{
MrcMemInit, MrcMemTest
} MEM_INIT_OR_TEST;
#define READ_TRAIN 1
#define WRITE_TRAIN 2
#define HTE_MEMTEST_NUM 2
#define HTE_LOOP_CNT 5 // EXP_LOOP_CNT field of HTE_CMD_CTL. This CANNOT be less than 4
#define HTE_LFSR_VICTIM_SEED 0xF294BA21 // Random seed for victim.
#define HTE_LFSR_AGRESSOR_SEED 0xEBA7492D // Random seed for aggressor.
UINT32
HteMemInit(
MRC_PARAMS *CurrentMrcData,
UINT8 MemInitFlag,
UINT8 HaltHteEngineOnError);
UINT16
BasicWriteReadHTE(
MRC_PARAMS *CurrentMrcData,
UINT32 Address,
UINT8 FirstRun,
UINT8 Mode);
UINT16
WriteStressBitLanesHTE(
MRC_PARAMS *CurrentMrcData,
UINT32 Address,
UINT8 FirstRun);
VOID
HteMemOp(
UINT32 Address,
UINT8 FirstRun,
UINT8 IsWrite);
#endif

View File

@@ -0,0 +1,138 @@
/** @file
Declaration of IO handling routines.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __IO_H
#define __IO_H
#include "core_types.h"
#include "general_definitions.h"
#include "gen5_iosf_sb_definitions.h"
// Instruction not present on Quark
#define SFENCE()
#define DEAD_LOOP() for(;;);
////
// Define each of the IOSF_SB ports used by MRC
//
//
// Has to be 0 because of emulation static data
// initialisation:
// Space_t EmuSpace[ SPACE_COUNT] = {0};
//
#define FREE 0x000
// Pseudo side-band ports for access abstraction
// See Wr32/Rd32 functions
#define MEM 0x101
#define MMIO 0x102
#define DCMD 0x0A0
// Real side-band ports
// See Wr32/Rd32 functions
#define MCU 0x001
#define HOST_BRIDGE 0x003
#define MEMORY_MANAGER 0x005
#define HTE 0x011
#define DDRPHY 0x012
#define FUSE 0x033
// End of IOSF_SB ports
////
// Pciexbar address
#define EC_BASE 0xE0000000
#define PCIADDR(bus,dev,fn,reg) ( \
(EC_BASE) + \
((bus) << 20) + \
((dev) << 15) + \
((fn) << 12) + \
(reg))
// Various offsets used in the building sideband commands.
#define SB_OPCODE_OFFSET 24
#define SB_PORT_OFFSET 16
#define SB_REG_OFFEST 8
// Sideband opcodes
#define SB_REG_READ_OPCODE 0x10
#define SB_REG_WRITE_OPCODE 0x11
#define SB_FUSE_REG_READ_OPCODE 0x06
#define SB_FUSE_REG_WRITE_OPCODE 0x07
#define SB_DDRIO_REG_READ_OPCODE 0x06
#define SB_DDRIO_REG_WRITE_OPCODE 0x07
#define SB_DRAM_CMND_OPCODE 0x68
#define SB_WAKE_CMND_OPCODE 0xCA
#define SB_SUSPEND_CMND_OPCODE 0xCC
// Register addresses for sideband command and data.
#define SB_PACKET_REG 0x00D0
#define SB_DATA_REG 0x00D4
#define SB_HADR_REG 0x00D8
// We always flag all 4 bytes in the register reads/writes as required.
#define SB_ALL_BYTES_ENABLED 0xF0
#define SB_COMMAND(Opcode, Port, Reg) \
((Opcode << SB_OPCODE_OFFSET) | \
(Port << SB_PORT_OFFSET) | \
(Reg << SB_REG_OFFEST) | \
SB_ALL_BYTES_ENABLED)
// iosf
#define isbM32m WrMask32
#define isbW32m Wr32
#define isbR32m Rd32
// pci
void pciwrite32(
uint32_t bus,
uint32_t dev,
uint32_t fn,
uint32_t reg,
uint32_t data);
uint32_t pciread32(
uint32_t bus,
uint32_t dev,
uint32_t fn,
uint32_t reg);
// general
uint32_t Rd32(
uint32_t unit,
uint32_t addr);
void Wr32(
uint32_t unit,
uint32_t addr,
uint32_t data);
void WrMask32(
uint32_t unit,
uint32_t addr,
uint32_t data,
uint32_t mask);
#endif

View File

@@ -0,0 +1,388 @@
/** @file
Serial conole output and string formating.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "memory_options.h"
#include "general_definitions.h"
// Resource programmed to PCI bridge, 1MB bound alignment is needed.
// The default value is overwritten by MRC parameter, assuming code
// relocated to eSRAM.
uint32_t UartMmioBase = 0;
// Serial port registers based on SerialPortLib.c
#define R_UART_BAUD_THR 0
#define R_UART_LSR 20
#define B_UART_LSR_RXRDY BIT0
#define B_UART_LSR_TXRDY BIT5
#define B_UART_LSR_TEMT BIT6
// Print mask see DPF and D_Xxxx
#define DPF_MASK DpfPrintMask
// Select class of messages enabled for printing
uint32_t DpfPrintMask =
D_ERROR |
D_INFO |
// D_REGRD |
// D_REGWR |
// D_FCALL |
// D_TRN |
0;
#ifdef NDEBUG
// Don't generate debug code
void dpf( uint32_t mask, char_t* bla, ...)
{
return;
}
uint8_t mgetc(void)
{
return 0;
}
uint8_t mgetch(void)
{
return 0;
}
#else
#ifdef SIM
// Use Vpi console in simulation environment
#include <vpi_user.h>
void dpf( uint32_t mask, char_t* bla, ...)
{
va_list va;
if( 0 == (mask & DPF_MASK)) return;
va_start( va, bla);
vpi_vprintf( bla, va);
va_end(va);
}
#else
#ifdef EMU
// Use standard console in windows environment
#include <stdio.h>
#endif
// Read character from serial port
uint8_t mgetc(void)
{
#ifdef EMU
// Emulation in Windows environment uses console
getchar();
#else
uint8_t c;
while ((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) == 0);
c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);
return c;
#endif
}
uint8_t mgetch(void)
{
#ifdef EMU
return 0;
#else
uint8_t c = 0;
if((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) != 0)
{
c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);
}
return c;
#endif
}
// Print single character
static void printc(
uint8_t c)
{
#ifdef EMU
// Emulation in Windows environment uses console output
putchar(c);
#else
//
// Use MMIO access to serial port on PCI
// while( 0 == (0x20 & inp(0x3f8 + 5)));
// outp(0x3f8 + 0, c);
//
while (0
== (B_UART_LSR_TEMT & *((volatile uint8_t*) (UartMmioBase + R_UART_LSR))))
;
*((volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR)) = c;
#endif
}
// Print 0 terminated string on serial console
static void printstr(
char_t *str)
{
while (*str)
{
printc(*str++);
}
}
// Print 64bit number as hex string on serial console
// the width parameters allows skipping leading zeros
static void printhexx(
uint64_t val,
uint32_t width)
{
uint32_t i;
uint8_t c;
uint8_t empty = 1;
// 64bit number has 16 characters in hex representation
for (i = 16; i > 0; i--)
{
c = *(((uint8_t *)&val) + ((i - 1) >> 1));
if (((i - 1) & 1) != 0)
c = c >> 4;
c = c & 0x0F;
if (c > 9)
c += 'A' - 10;
else
c += '0';
if (c != '0')
{
// end of leading zeros
empty = 0;
}
// don't print leading zero
if (!empty || i <= width)
{
printc(c);
}
}
}
// Print 32bit number as hex string on serial console
// the width parameters allows skipping leading zeros
static void printhex(
uint32_t val,
uint32_t width)
{
uint32_t i;
uint8_t c;
uint8_t empty = 1;
// 32bit number has 8 characters in hex representation
for (i = 8; i > 0; i--)
{
c = (uint8_t) ((val >> 28) & 0x0F);
if (c > 9)
c += 'A' - 10;
else
c += '0';
val = val << 4;
if (c != '0')
{
// end of leading zeros
empty = 0;
}
// don't print leading zero
if (!empty || i <= width)
{
printc(c);
}
}
}
// Print 32bit number as decimal string on serial console
// the width parameters allows skipping leading zeros
static void printdec(
uint32_t val,
uint32_t width)
{
uint32_t i;
uint8_t c = 0;
uint8_t empty = 1;
// Ten digits is enough for 32bit number in decimal
uint8_t buf[10];
for (i = 0; i < sizeof(buf); i++)
{
c = (uint8_t) (val % 10);
buf[i] = c + '0';
val = val / 10;
}
while (i > 0)
{
c = buf[--i];
if (c != '0')
{
// end of leading zeros
empty = 0;
}
// don't print leading zero
if (!empty || i < width)
{
printc(c);
}
}
}
// Consume numeric substring leading the given string
// Return pointer to the first non-numeric character
// Buffer reference by width is updated with number
// converted from the numeric substring.
static char_t *getwidth(
char_t *bla,
uint32_t *width)
{
uint32_t val = 0;
while (*bla >= '0' && *bla <= '9')
{
val = val * 10 + *bla - '0';
bla += 1;
}
if (val > 0)
{
*width = val;
}
return bla;
}
// Consume print format designator from the head of given string
// Return pointer to first character after format designator
// input fmt
// ----- ---
// s -> s
// d -> d
// X -> X
// llX -> L
static char_t *getformat(
char_t *bla,
uint8_t *fmt)
{
if (bla[0] == 's')
{
bla += 1;
*fmt = 's';
}
else if (bla[0] == 'd')
{
bla += 1;
*fmt = 'd';
}
else if (bla[0] == 'X' || bla[0] == 'x')
{
bla += 1;
*fmt = 'X';
}
else if (bla[0] == 'l' && bla[1] == 'l' && bla[2] == 'X')
{
bla += 3;
*fmt = 'L';
}
return bla;
}
// Simplified implementation of standard printf function
// The output is directed to serial console. Only selected
// class of messages is printed (mask has to match DpfPrintMask)
// Supported print formats: %[n]s,%[n]d,%[n]X,,%[n]llX
// The width is ignored for %s format.
void dpf(
uint32_t mask,
char_t* bla,
...)
{
uint32_t* arg = (uint32_t*) (&bla + 1);
// Check UART MMIO base configured
if (0 == UartMmioBase)
return;
// Check event not masked
if (0 == (mask & DPF_MASK))
return;
for (;;)
{
uint8_t x = *bla++;
if (x == 0)
break;
if (x == '\n')
{
printc('\r');
printc('\n');
}
else if (x == '%')
{
uint8_t fmt = 0;
uint32_t width = 1;
bla = getwidth(bla, &width);
bla = getformat(bla, &fmt);
// Print value
if (fmt == 'd')
{
printdec(*arg, width);
arg += 1;
}
else if (fmt == 'X')
{
printhex(*arg, width);
arg += 1;
}
else if (fmt == 'L')
{
printhexx(*(uint64_t*) arg, width);
arg += 2;
}
else if (fmt == 's')
{
printstr(*(char**) arg);
arg += 1;
}
}
else
{
printc(x);
}
}
}
#endif //SIM
#endif //NDEBUG

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
/************************************************************************
*
* Copyright (c) 2013-2015 Intel Corporation.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
***************************************************************************/
#ifndef _MEMINIT_UTILS_H_
#define _MEMINIT_UTILS_H_
// General Definitions:
#ifdef QUICKSIM
#define SAMPLE_SIZE 4 // reduce number of training samples in simulation env
#else
#define SAMPLE_SIZE 6 // must be odd number
#endif
#define EARLY_DB (0x12) // must be less than this number to enable early deadband
#define LATE_DB (0x34) // must be greater than this number to enable late deadband
#define CHX_REGS (11*4)
#define FULL_CLK 128
#define HALF_CLK 64
#define QRTR_CLK 32
#define MCEIL(num,den) ((uint8_t)((num+den-1)/den))
#define MMAX(a,b) ((((int32_t)(a))>((int32_t)(b)))?(a):(b))
#define MCOUNT(a) (sizeof(a)/sizeof(*a))
typedef enum ALGOS_enum {
eRCVN = 0,
eWDQS,
eWDQx,
eRDQS,
eVREF,
eWCMD,
eWCTL,
eWCLK,
eMAX_ALGOS,
} ALGOs_t;
// Prototypes:
void set_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
void set_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
void set_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
void set_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
void set_wcmd(uint8_t channel, uint32_t pi_count);
void set_wclk(uint8_t channel, uint8_t grp, uint32_t pi_count);
void set_wctl(uint8_t channel, uint8_t rank, uint32_t pi_count);
void set_vref(uint8_t channel, uint8_t byte_lane, uint32_t setting);
uint32_t get_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane);
uint32_t get_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane);
uint32_t get_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane);
uint32_t get_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane);
uint32_t get_wcmd(uint8_t channel);
uint32_t get_wclk(uint8_t channel, uint8_t group);
uint32_t get_wctl(uint8_t channel, uint8_t rank);
uint32_t get_vref(uint8_t channel, uint8_t byte_lane);
void clear_pointers(void);
void enable_cache(void);
void disable_cache(void);
void find_rising_edge(MRCParams_t *mrc_params, uint32_t delay[], uint8_t channel, uint8_t rank, bool rcvn);
uint32_t sample_dqs(MRCParams_t *mrc_params, uint8_t channel, uint8_t rank, bool rcvn);
uint32_t get_addr(MRCParams_t *mrc_params, uint8_t channel, uint8_t rank);
uint32_t byte_lane_mask(MRCParams_t *mrc_params);
uint64_t read_tsc(void);
uint32_t get_tsc_freq(void);
void delay_n(uint32_t nanoseconds);
void delay_u(uint32_t microseconds);
void delay_m(uint32_t milliseconds);
void delay_s(uint32_t seconds);
void post_code(uint8_t major, uint8_t minor);
void training_message(uint8_t channel, uint8_t rank, uint8_t byte_lane);
void print_timings(MRCParams_t *mrc_params);
void enable_scrambling(MRCParams_t *mrc_params);
void store_timings(MRCParams_t *mrc_params);
void restore_timings(MRCParams_t *mrc_params);
void default_timings(MRCParams_t *mrc_params);
#ifndef SIM
void *memset(void *d, int c, size_t n);
void *memcpy(void *d, const void *s, size_t n);
#endif
#endif // _MEMINIT_UTILS_H_

View File

@@ -0,0 +1,83 @@
/** @file
Common definitions and compilation switches for MRC
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __MEMORY_OPTIONS_H
#define __MEMORY_OPTIONS_H
#include "core_types.h"
// MRC COMPILE TIME SWITCHES:
// ==========================
//#define MRC_SV // enable some validation opitons
#if defined (SIM) || defined(EMU)
#define QUICKSIM // reduce execution time using shorter rd/wr sequences
#endif
#define CLT // required for Quark project
//#define BACKUP_RCVN // enable STATIC timing settings for RCVN (BACKUP_MODE)
//#define BACKUP_WDQS // enable STATIC timing settings for WDQS (BACKUP_MODE)
//#define BACKUP_RDQS // enable STATIC timing settings for RDQS (BACKUP_MODE)
//#define BACKUP_WDQ // enable STATIC timing settings for WDQ (BACKUP_MODE)
//#define BACKUP_COMPS // enable *COMP overrides (BACKUP_MODE)
//#define RX_EYE_CHECK // enable the RD_TRAIN eye check
#define HMC_TEST // enable Host to Memory Clock Alignment
#define R2R_SHARING // enable multi-rank support via rank2rank sharing
#define FORCE_16BIT_DDRIO // disable signals not used in 16bit mode of DDRIO
//
// Debug support
//
#ifdef NDEBUG
#define DPF if(0) dpf
#else
#define DPF dpf
#endif
void dpf( uint32_t mask, char_t *bla, ...);
uint8_t mgetc(void);
uint8_t mgetch(void);
// Debug print type
#define D_ERROR 0x0001
#define D_INFO 0x0002
#define D_REGRD 0x0004
#define D_REGWR 0x0008
#define D_FCALL 0x0010
#define D_TRN 0x0020
#define D_TIME 0x0040
#define ENTERFN() DPF(D_FCALL, "<%s>\n", __FUNCTION__)
#define LEAVEFN() DPF(D_FCALL, "</%s>\n", __FUNCTION__)
#define REPORTFN() DPF(D_FCALL, "<%s/>\n", __FUNCTION__)
extern uint32_t DpfPrintMask;
#endif

View File

@@ -0,0 +1,46 @@
/************************************************************************
*
* Copyright (c) 2013-2015 Intel Corporation.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
************************************************************************/
#include "mrc.h"
#include "memory_options.h"
#include "meminit.h"
#include "meminit_utils.h"
#include "prememinit.h"
#include "io.h"
// Base address for UART registers
extern uint32_t UartMmioBase;
//
// Memory Reference Code entry point when executing from BIOS
//
void Mrc( MRCParams_t *mrc_params)
{
// configure uart base address assuming code relocated to eSRAM
UartMmioBase = mrc_params->uart_mmio_base;
ENTERFN();
DPF(D_INFO, "MRC Version %04X %s %s\n", MRC_VERSION, __DATE__, __TIME__);
// this will set up the data structures used by MemInit()
PreMemInit(mrc_params);
// this will initialize system memory
MemInit(mrc_params);
LEAVEFN();
return;
}

View File

@@ -0,0 +1,166 @@
/************************************************************************
*
* Copyright (c) 2013-2015 Intel Corporation.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
************************************************************************/
#ifndef _MRC_H_
#define _MRC_H_
#include "core_types.h"
// define the MRC Version
#define MRC_VERSION 0x0112
// architectural definitions
#define NUM_CHANNELS 1 // number of channels
#define NUM_RANKS 2 // number of ranks per channel
#define NUM_BYTE_LANES 4 // number of byte lanes per channel
// software limitations
#define MAX_CHANNELS 1
#define MAX_RANKS 2
#define MAX_BYTE_LANES 4
// only to mock MrcWrapper
#define MAX_SOCKETS 1
#define MAX_SIDES 1
#define MAX_ROWS (MAX_SIDES * MAX_SOCKETS)
// end
// Specify DRAM of nenory channel width
enum {
x8, // DRAM width
x16, // DRAM width & Channel Width
x32 // Channel Width
};
// Specify DRAM speed
enum {
DDRFREQ_800,
DDRFREQ_1066
};
// Specify DRAM type
enum {
DDR3,
DDR3L
};
// Delay configuration for individual signals
// Vref setting
// Scrambler seed
typedef struct MrcTimings_s
{
uint32_t rcvn[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
uint32_t rdqs[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
uint32_t wdqs[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
uint32_t wdq [NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
uint32_t vref[NUM_CHANNELS][NUM_BYTE_LANES];
uint32_t wctl[NUM_CHANNELS][NUM_RANKS];
uint32_t wcmd[NUM_CHANNELS];
uint32_t scrambler_seed;
uint8_t ddr_speed; // need to save for the case of frequency change
} MrcTimings_t;
// DENSITY: 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb
// tCL is DRAM CAS Latency in clocks.
// All other timings are in picoseconds.
// Refer to JEDEC spec (or DRAM datasheet) when changing these values.
typedef struct DRAMParams_s {
uint8_t DENSITY;
uint8_t tCL; // CAS latency in clocks
uint32_t tRAS; // ACT to PRE command period
uint32_t tWTR; // Delay from start of internal write transaction to internal read command
uint32_t tRRD; // ACT to ACT command period (JESD79 specific to page size 1K/2K)
uint32_t tFAW; // Four activate window (JESD79 specific to page size 1K/2K)
} DRAMParams_t;
// Boot mode defined as bit mask (1<<n)
#define bmCold 1 // full training
#define bmFast 2 // restore timing parameters
#define bmS3 4 // resume from S3
#define bmWarm 8
#define bmUnknown 0
// MRC execution status
#define MRC_SUCCESS 0 // initialization ok
#define MRC_E_MEMTEST 1 // memtest failed
//
// Input/output/context parameters for Memory Reference Code
//
typedef struct MRCParams_s
{
//
// Global settings
//
uint32_t boot_mode; // bmCold, bmFast, bmWarm, bmS3
uint32_t uart_mmio_base; // pcie serial port base address (force 0 to disable debug)
uint8_t dram_width; // x8, x16
uint8_t ddr_speed; // DDRFREQ_800, DDRFREQ_1066
uint8_t ddr_type; // DDR3, DDR3L
uint8_t ecc_enables; // 0, 1 (memory size reduced to 7/8)
uint8_t scrambling_enables; // 0, 1
uint32_t rank_enables; // 1, 3 (1'st rank has to be populated if 2'nd rank present)
uint32_t channel_enables; // 1 only
uint32_t channel_width; // x16 only
uint32_t address_mode; // 0, 1, 2 (mode 2 forced if ecc enabled)
// memConfig_t begin
uint8_t refresh_rate; // REFRESH_RATE : 1=1.95us, 2=3.9us, 3=7.8us, others=RESERVED
uint8_t sr_temp_range; // SR_TEMP_RANGE : 0=normal, 1=extended, others=RESERVED
uint8_t ron_value; // RON_VALUE : 0=34ohm, 1=40ohm, others=RESERVED (select MRS1.DIC driver impedance control)
uint8_t rtt_nom_value; // RTT_NOM_VALUE : 0=40ohm, 1=60ohm, 2=120ohm, others=RESERVED
uint8_t rd_odt_value; // RD_ODT_VALUE : 0=off, 1=60ohm, 2=120ohm, 3=180ohm, others=RESERVED
// memConfig_t end
DRAMParams_t params;
//
// Internally used
//
uint32_t board_id; // internally used for board layout (use x8 or x16 memory)
uint32_t hte_setup : 1; // when set hte reconfiguration requested
uint32_t menu_after_mrc : 1;
uint32_t power_down_disable :1;
uint32_t tune_rcvn :1;
uint32_t channel_size[NUM_CHANNELS];
uint32_t column_bits[NUM_CHANNELS];
uint32_t row_bits[NUM_CHANNELS];
uint32_t mrs1; // register content saved during training
//
// Output
//
uint32_t status; // initialization result (non zero specifies error code)
uint32_t mem_size; // total memory size in bytes (excludes ECC banks)
MrcTimings_t timings; // training results (also used on input)
} MRCParams_t;
// Alternative type name for consistent naming convention
#define MRC_PARAMS MRCParams_t
#endif // _MRC_H_

View File

@@ -0,0 +1,192 @@
/** @file
The interface layer for memory controller access.
It is supporting both real hardware platform and simulation environment.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "mrc.h"
#include "memory_options.h"
#include "meminit_utils.h"
#include "io.h"
#ifdef SIM
void SimMmio32Write (
uint32_t be,
uint32_t address,
uint32_t data );
void SimMmio32Read (
uint32_t be,
uint32_t address,
uint32_t *data );
void SimDelayClk (
uint32_t x2clk );
// This is a simple delay function.
// It takes "nanoseconds" as a parameter.
void delay_n(uint32_t nanoseconds)
{
SimDelayClk( 800*nanoseconds/1000);
}
#endif
/****
*
***/
uint32_t Rd32(
uint32_t unit,
uint32_t addr)
{
uint32_t data;
switch (unit)
{
case MEM:
case MMIO:
#ifdef SIM
SimMmio32Read( 1, addr, &data);
#else
data = *PTR32(addr);
#endif
break;
case MCU:
case HOST_BRIDGE:
case MEMORY_MANAGER:
case HTE:
// Handle case addr bigger than 8bit
pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
addr &= 0x00FF;
pciwrite32(0, 0, 0, SB_PACKET_REG,
SB_COMMAND(SB_REG_READ_OPCODE, unit, addr));
data = pciread32(0, 0, 0, SB_DATA_REG);
break;
case DDRPHY:
// Handle case addr bigger than 8bit
pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
addr &= 0x00FF;
pciwrite32(0, 0, 0, SB_PACKET_REG,
SB_COMMAND(SB_DDRIO_REG_READ_OPCODE, unit, addr));
data = pciread32(0, 0, 0, SB_DATA_REG);
break;
default:
DEAD_LOOP()
;
}
if (unit < MEM)
DPF(D_REGRD, "RD32 %03X %08X %08X\n", unit, addr, data);
return data;
}
/****
*
***/
void Wr32(
uint32_t unit,
uint32_t addr,
uint32_t data)
{
if (unit < MEM)
DPF(D_REGWR, "WR32 %03X %08X %08X\n", unit, addr, data);
switch (unit)
{
case MEM:
case MMIO:
#ifdef SIM
SimMmio32Write( 1, addr, data);
#else
*PTR32(addr) = data;
#endif
break;
case MCU:
case HOST_BRIDGE:
case MEMORY_MANAGER:
case HTE:
// Handle case addr bigger than 8bit
pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
addr &= 0x00FF;
pciwrite32(0, 0, 0, SB_DATA_REG, data);
pciwrite32(0, 0, 0, SB_PACKET_REG,
SB_COMMAND(SB_REG_WRITE_OPCODE, unit, addr));
break;
case DDRPHY:
// Handle case addr bigger than 8bit
pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
addr &= 0x00FF;
pciwrite32(0, 0, 0, SB_DATA_REG, data);
pciwrite32(0, 0, 0, SB_PACKET_REG,
SB_COMMAND(SB_DDRIO_REG_WRITE_OPCODE, unit, addr));
break;
case DCMD:
pciwrite32(0, 0, 0, SB_HADR_REG, 0);
pciwrite32(0, 0, 0, SB_DATA_REG, data);
pciwrite32(0, 0, 0, SB_PACKET_REG,
SB_COMMAND(SB_DRAM_CMND_OPCODE, MCU, 0));
break;
default:
DEAD_LOOP()
;
}
}
/****
*
***/
void WrMask32(
uint32_t unit,
uint32_t addr,
uint32_t data,
uint32_t mask)
{
Wr32(unit, addr, ((Rd32(unit, addr) & ~mask) | (data & mask)));
}
/****
*
***/
void pciwrite32(
uint32_t bus,
uint32_t dev,
uint32_t fn,
uint32_t reg,
uint32_t data)
{
Wr32(MMIO, PCIADDR(bus,dev,fn,reg), data);
}
/****
*
***/
uint32_t pciread32(
uint32_t bus,
uint32_t dev,
uint32_t fn,
uint32_t reg)
{
return Rd32(MMIO, PCIADDR(bus,dev,fn,reg));
}

View File

@@ -0,0 +1,193 @@
/************************************************************************
*
* Copyright (c) 2013-2015 Intel Corporation.
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution. The full text of the license may be found at
* http://opensource.org/licenses/bsd-license.php
*
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
************************************************************************/
#include "mrc.h"
#include "memory_options.h"
#include "meminit_utils.h"
#include "prememinit.h"
#include "io.h"
// Read character from serial console
uint8_t mgetc(void);
extern uint32_t DpfPrintMask;
// Adjust configuration parameters before initialisation
// sequence.
void PreMemInit(
MRCParams_t *mrc_params)
{
const DRAMParams_t *dram_params;
uint8_t dram_width;
uint32_t dram_cfg_index;
uint32_t channel_i;
ENTERFN();
#ifdef MRC_SV
{
uint8_t ch;
myloop:
DPF(D_INFO, "- c - continue\n");
DPF(D_INFO, "- f - boot mode [%d]\n", mrc_params->boot_mode);
DPF(D_INFO, "- r - rank enable [%d]\n", mrc_params->rank_enables);
DPF(D_INFO, "- e - ecc switch [%d]\n", mrc_params->ecc_enables);
DPF(D_INFO, "- b - scrambling switch [%d]\n", mrc_params->scrambling_enables);
DPF(D_INFO, "- a - adr mode [%d]\n", mrc_params->address_mode);
DPF(D_INFO, "- m - menu after mrc [%d]\n", mrc_params->menu_after_mrc);
DPF(D_INFO, "- t - tune to rcvn [%d]\n", mrc_params->tune_rcvn);
DPF(D_INFO, "- o - odt switch [%d]\n", mrc_params->rd_odt_value);
DPF(D_INFO, "- d - dram density [%d]\n", mrc_params->params.DENSITY);
DPF(D_INFO, "- p - power down disable [%d]\n", mrc_params->power_down_disable);
DPF(D_INFO, "- l - log switch 0x%x\n", DpfPrintMask);
ch = mgetc();
switch (ch)
{
case 'f':
mrc_params->boot_mode >>= 1;
if(mrc_params->boot_mode == bmUnknown)
{
mrc_params->boot_mode = bmWarm;
}
DPF(D_INFO, "Boot mode %d\n", mrc_params->boot_mode);
break;
case 'p':
mrc_params->power_down_disable ^= 1;
DPF(D_INFO, "Power down disable %d\n", mrc_params->power_down_disable);
break;
case 'r':
mrc_params->rank_enables ^= 2;
DPF(D_INFO, "Rank enable %d\n", mrc_params->rank_enables);
break;
case 'e':
mrc_params->ecc_enables ^= 1;
DPF(D_INFO, "Ecc enable %d\n", mrc_params->ecc_enables);
break;
case 'b':
mrc_params->scrambling_enables ^= 1;
DPF(D_INFO, "Scrambler enable %d\n", mrc_params->scrambling_enables);
break;
case 'a':
mrc_params->address_mode = (mrc_params->address_mode + 1) % 3;
DPF(D_INFO, "Adr mode %d\n", mrc_params->address_mode);
break;
case 'm':
mrc_params->menu_after_mrc ^= 1;
DPF(D_INFO, "Menu after mrc %d\n", mrc_params->menu_after_mrc);
break;
case 't':
mrc_params->tune_rcvn ^= 1;
DPF(D_INFO, "Tune to rcvn %d\n", mrc_params->tune_rcvn);
break;
case 'o':
mrc_params->rd_odt_value = (mrc_params->rd_odt_value + 1) % 4;
DPF(D_INFO, "Rd_odt_value %d\n", mrc_params->rd_odt_value);
break;
case 'd':
mrc_params->params.DENSITY = (mrc_params->params.DENSITY + 1) % 4;
DPF(D_INFO, "Dram density %d\n", mrc_params->params.DENSITY);
break;
case 'l':
DpfPrintMask ^= 0x30;
DPF(D_INFO, "Log mask %x\n", DpfPrintMask);
break;
default:
break;
}
if (ch != 'c')
goto myloop;
}
#endif
// initially expect success
mrc_params->status = MRC_SUCCESS;
// todo!!! Setup board layout (must be reviewed as is selecting static timings)
// 0 == R0 (DDR3 x16), 1 == R1 (DDR3 x16), 2 == DV (DDR3 x8), 3 == SV (DDR3 x8)
if (mrc_params->dram_width == x8)
{
mrc_params->board_id = 2; // select x8 layout
}
else
{
mrc_params->board_id = 0; // select x16 layout
}
// initially no memory
mrc_params->mem_size = 0;
channel_i = 0;
// begin of channel settings
dram_width = mrc_params->dram_width;
dram_params = &mrc_params->params;
dram_cfg_index = 0;
// Determine Column & Row Bits:
// Column:
// 11 for 8Gbx8, else 10
mrc_params->column_bits[channel_i] = ((dram_params[dram_cfg_index].DENSITY == 4) && (dram_width == x8)) ? (11) : (10);
// Row:
// 512Mbx16=12 512Mbx8=13
// 1Gbx16=13 1Gbx8=14
// 2Gbx16=14 2Gbx8=15
// 4Gbx16=15 4Gbx8=16
// 8Gbx16=16 8Gbx8=16
mrc_params->row_bits[channel_i] = 12 + (dram_params[dram_cfg_index].DENSITY)
+ (((dram_params[dram_cfg_index].DENSITY < 4) && (dram_width == x8)) ? (1) : (0));
// Determine Per Channel Memory Size:
// (For 2 RANKs, multiply by 2)
// (For 16 bit data bus, divide by 2)
// DENSITY WIDTH MEM_AVAILABLE
// 512Mb x16 0x008000000 ( 128MB)
// 512Mb x8 0x010000000 ( 256MB)
// 1Gb x16 0x010000000 ( 256MB)
// 1Gb x8 0x020000000 ( 512MB)
// 2Gb x16 0x020000000 ( 512MB)
// 2Gb x8 0x040000000 (1024MB)
// 4Gb x16 0x040000000 (1024MB)
// 4Gb x8 0x080000000 (2048MB)
mrc_params->channel_size[channel_i] = (1 << dram_params[dram_cfg_index].DENSITY);
mrc_params->channel_size[channel_i] *= ((dram_width == x8) ? (2) : (1));
mrc_params->channel_size[channel_i] *= (mrc_params->rank_enables == 0x3) ? (2) : (1);
mrc_params->channel_size[channel_i] *= (mrc_params->channel_width == x16) ? (1) : (2);
// Determine memory size (convert number of 64MB/512Mb units)
mrc_params->mem_size += mrc_params->channel_size[channel_i] << 26;
// end of channel settings
LEAVEFN();
return;
}

View File

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

View File

@@ -0,0 +1,55 @@
/** @file
Common header file shared by all source files.
This file includes package header files, library classes and protocol, PPI & GUID definitions.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __COMMON_HEADER_H_
#define __COMMON_HEADER_H_
//
// The package level header files this module uses
//
#include <PiDxe.h>
#include <IntelQNCDxe.h>
//
// The protocols, PPI and GUID definitions for this module
//
#include <Protocol/PciHostBridgeResourceAllocation.h>
#include <Protocol/LegacyRegion2.h>
#include <Protocol/SmbusHc.h>
#include <Protocol/QncS3Support.h>
//
// The Library classes this module consumes
//
#include <Library/BaseLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/MtrrLib.h>
#include <Library/IoLib.h>
#include <Library/SmbusLib.h>
#include <Library/S3IoLib.h>
#include <Library/S3BootScriptLib.h>
#include <Library/IntelQNCLib.h>
#include <Library/QNCAccessLib.h>
#include <AcpiCpuData.h>
extern EFI_HANDLE gQNCInitImageHandle;
extern QNC_DEVICE_ENABLES mQNCDeviceEnables;
#endif

View File

@@ -0,0 +1,618 @@
/** @file
Implementation for SMBus DXE driver entry point and SMBus Host
Controller protocol.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "CommonHeader.h"
#include "DxeQNCSmbus.h"
//
// Interface defintion of SMBUS Host Controller Protocol.
//
EFI_SMBUS_HC_PROTOCOL mSmbusHc = {
SmbusExecute,
SmbusArpDevice,
SmbusGetArpMap,
SmbusNotify
};
//
// Handle to install SMBus Host Controller protocol.
//
EFI_HANDLE mSmbusHcHandle = NULL;
UINT8 mDeviceMapEntries = 0;
EFI_SMBUS_DEVICE_MAP mDeviceMap[MAX_SMBUS_DEVICES];
UINT8 mPlatformNumRsvd = 0;
UINT8 *mPlatformAddrRsvd = NULL;
//
// These addresses are reserved by the SMBus 2.0 specification
//
UINT8 mReservedAddress[SMBUS_NUM_RESERVED] = {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x18, 0x50, 0x6E, 0xC2,
0xF0, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFC, 0xFE
};
/**
Gets Io port base address of Smbus Host Controller.
This internal function depends on a feature flag named PcdIchSmbusFixedIoPortBaseAddress
to retrieve Smbus Io port base. If that feature flag is true, it will get Smbus Io port base
address from a preset Pcd entry named PcdIchSmbusIoPortBaseAddress; otherwise, it will always
read Pci configuration space to get that value in each Smbus bus transaction.
@return The Io port base address of Smbus host controller.
**/
UINTN
GetSmbusIoPortBaseAddress (
VOID
)
{
UINTN IoPortBaseAddress;
if (FeaturePcdGet (PcdSmbaIoBaseAddressFixed)) {
IoPortBaseAddress = (UINTN) PcdGet16 (PcdSmbaIoBaseAddress);
} else {
IoPortBaseAddress = (UINTN) LpcPciCfg32 (R_QNC_LPC_SMBUS_BASE) & B_QNC_LPC_SMBUS_BASE_MASK;
}
//
// Make sure that the IO port base address has been properly set.
//
ASSERT (IoPortBaseAddress != 0);
return IoPortBaseAddress;
}
VOID
InitializeInternal (
)
{
UINTN IoPortBaseAddress;
IoPortBaseAddress = GetSmbusIoPortBaseAddress ();
//
// Step1: Enable QNC SMBUS I/O space.
//
LpcPciCfg32Or(R_QNC_LPC_SMBUS_BASE, B_QNC_LPC_SMBUS_BASE_EN);
//
// Step2: Clear Status Register before anyone uses the interfaces.
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HSTS, B_QNC_SMBUS_HSTS_ALL);
//
// Step3: Program the correct smbus clock
//
IoWrite8 (IoPortBaseAddress + R_QNC_SMBUS_HCLK, V_QNC_SMBUS_HCLK_100KHZ);
}
BOOLEAN
IsAddressAvailable (
IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress
)
{
UINT8 Index;
//
// See if we have already assigned this address to a device
//
for (Index = 0; Index < mDeviceMapEntries; Index++) {
if (SlaveAddress.SmbusDeviceAddress ==
mDeviceMap[Index].SmbusDeviceAddress.SmbusDeviceAddress) {
return FALSE;
}
}
//
// See if this address is claimed by a platform non-ARP-capable device
//
for (Index = 0; Index < mPlatformNumRsvd; Index++) {
if ((SlaveAddress.SmbusDeviceAddress << 1) == mPlatformAddrRsvd[Index]) {
return FALSE;
}
}
//
// See if this is a reserved address
//
for (Index = 0; Index < SMBUS_NUM_RESERVED; Index++) {
if (SlaveAddress.SmbusDeviceAddress == (UINTN) mReservedAddress[Index]) {
return FALSE;
}
}
return TRUE;
}
EFI_STATUS
GetNextAvailableAddress (
IN EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress
)
{
for (SlaveAddress->SmbusDeviceAddress = 0x03;
SlaveAddress->SmbusDeviceAddress < 0x7F;
SlaveAddress->SmbusDeviceAddress++
) {
if (IsAddressAvailable (*SlaveAddress)) {
return EFI_SUCCESS;
}
}
return EFI_OUT_OF_RESOURCES;
}
EFI_STATUS
SmbusPrepareToArp (
)
{
EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
EFI_STATUS Status;
UINTN Length;
UINT8 Buffer;
SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;
Length = 1;
Buffer = SMBUS_DATA_PREPARE_TO_ARP;
Status = Execute (
SlaveAddress,
0,
EfiSmbusSendByte,
TRUE,
&Length,
&Buffer
);
return Status;
}
EFI_STATUS
SmbusGetUdidGeneral (
IN OUT EFI_SMBUS_DEVICE_MAP *DeviceMap
)
{
EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
EFI_STATUS Status;
UINTN Length;
UINT8 Buffer[SMBUS_GET_UDID_LENGTH];
SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;
Length = SMBUS_GET_UDID_LENGTH;
Status = Execute (
SlaveAddress,
SMBUS_DATA_GET_UDID_GENERAL,
EfiSmbusReadBlock,
TRUE,
&Length,
Buffer
);
if (!EFI_ERROR(Status)) {
if (Length == SMBUS_GET_UDID_LENGTH) {
DeviceMap->SmbusDeviceUdid.DeviceCapabilities = Buffer[0];
DeviceMap->SmbusDeviceUdid.VendorRevision = Buffer[1];
DeviceMap->SmbusDeviceUdid.VendorId = (UINT16)((Buffer[2] << 8) + Buffer[3]);
DeviceMap->SmbusDeviceUdid.DeviceId = (UINT16)((Buffer[4] << 8) + Buffer[5]);
DeviceMap->SmbusDeviceUdid.Interface = (UINT16)((Buffer[6] << 8) + Buffer[7]);
DeviceMap->SmbusDeviceUdid.SubsystemVendorId = (UINT16)((Buffer[8] << 8) + Buffer[9]);
DeviceMap->SmbusDeviceUdid.SubsystemDeviceId = (UINT16)((Buffer[10] << 8) + Buffer[11]);
DeviceMap->SmbusDeviceUdid.VendorSpecificId = (UINT32)((Buffer[12] << 24) + (Buffer[13] << 16) + (Buffer[14] << 8) + Buffer[15]);
DeviceMap->SmbusDeviceAddress.SmbusDeviceAddress = (UINT8)(Buffer[16] >> 1);
} else {
Status = EFI_DEVICE_ERROR;
}
}
return Status;
}
EFI_STATUS
SmbusAssignAddress (
IN OUT EFI_SMBUS_DEVICE_MAP *DeviceMap
)
{
EFI_SMBUS_DEVICE_ADDRESS SlaveAddress;
EFI_STATUS Status;
UINTN Length;
UINT8 Buffer[SMBUS_GET_UDID_LENGTH];
Buffer[0] = DeviceMap->SmbusDeviceUdid.DeviceCapabilities;
Buffer[1] = DeviceMap->SmbusDeviceUdid.VendorRevision;
Buffer[2] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorId >> 8);
Buffer[3] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorId);
Buffer[4] = (UINT8)(DeviceMap->SmbusDeviceUdid.DeviceId >> 8);
Buffer[5] = (UINT8)(DeviceMap->SmbusDeviceUdid.DeviceId);
Buffer[6] = (UINT8)(DeviceMap->SmbusDeviceUdid.Interface >> 8);
Buffer[7] = (UINT8)(DeviceMap->SmbusDeviceUdid.Interface);
Buffer[8] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemVendorId >> 8);
Buffer[9] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemVendorId);
Buffer[10] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemDeviceId >> 8);
Buffer[11] = (UINT8)(DeviceMap->SmbusDeviceUdid.SubsystemDeviceId);
Buffer[12] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 24);
Buffer[13] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 16);
Buffer[14] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId >> 8);
Buffer[15] = (UINT8)(DeviceMap->SmbusDeviceUdid.VendorSpecificId);
Buffer[16] = (UINT8)(DeviceMap->SmbusDeviceAddress.SmbusDeviceAddress << 1);
SlaveAddress.SmbusDeviceAddress = SMBUS_ADDRESS_ARP;
Length = SMBUS_GET_UDID_LENGTH;
Status = Execute (
SlaveAddress,
SMBUS_DATA_ASSIGN_ADDRESS,
EfiSmbusWriteBlock,
TRUE,
&Length,
Buffer
);
return Status;
}
EFI_STATUS
SmbusFullArp (
)
{
EFI_STATUS Status;
EFI_SMBUS_DEVICE_MAP *CurrentDeviceMap;
Status = SmbusPrepareToArp ();
if (EFI_ERROR(Status)) {
if (Status == EFI_DEVICE_ERROR) {
//
// ARP is complete
//
return EFI_SUCCESS;
} else {
return Status;
}
}
//
// Main loop to ARP all ARP-capable devices
//
do {
CurrentDeviceMap = &mDeviceMap[mDeviceMapEntries];
Status = SmbusGetUdidGeneral (CurrentDeviceMap);
if (EFI_ERROR(Status)) {
break;
}
if (CurrentDeviceMap->SmbusDeviceAddress.SmbusDeviceAddress == (0xFF >> 1)) {
//
// If address is unassigned, assign it
//
Status = GetNextAvailableAddress (
&CurrentDeviceMap->SmbusDeviceAddress
);
if (EFI_ERROR(Status)) {
return EFI_OUT_OF_RESOURCES;
}
} else if (((CurrentDeviceMap->SmbusDeviceUdid.DeviceCapabilities) & 0xC0) != 0) {
//
// if address is not fixed, check if the current address is available
//
if (!IsAddressAvailable (
CurrentDeviceMap->SmbusDeviceAddress
)) {
//
// if currently assigned address is already used, get a new one
//
Status = GetNextAvailableAddress (
&CurrentDeviceMap->SmbusDeviceAddress
);
if (EFI_ERROR(Status)) {
return EFI_OUT_OF_RESOURCES;
}
}
}
Status = SmbusAssignAddress (CurrentDeviceMap);
if (EFI_ERROR(Status)) {
//
// If there was a device error, just continue on and try again.
// Other errors should be reported.
//
if (Status != EFI_DEVICE_ERROR) {
return Status;
}
} else {
//
// If there was no error, the address was assigned and we must update our
// records.
//
mDeviceMapEntries++;
}
} while (mDeviceMapEntries < MAX_SMBUS_DEVICES);
return EFI_SUCCESS;
}
EFI_STATUS
SmbusDirectedArp (
IN EFI_SMBUS_UDID *SmbusUdid,
IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress
)
{
EFI_STATUS Status;
EFI_SMBUS_DEVICE_MAP *CurrentDeviceMap;
if (mDeviceMapEntries >= MAX_SMBUS_DEVICES) {
return EFI_OUT_OF_RESOURCES;
}
CurrentDeviceMap = &mDeviceMap[mDeviceMapEntries];
//
// Find an available address to assign
//
Status = GetNextAvailableAddress (
&CurrentDeviceMap->SmbusDeviceAddress
);
if (EFI_ERROR(Status)) {
return EFI_OUT_OF_RESOURCES;
}
CurrentDeviceMap->SmbusDeviceUdid.DeviceCapabilities = SmbusUdid->DeviceCapabilities;
CurrentDeviceMap->SmbusDeviceUdid.DeviceId = SmbusUdid->DeviceId;
CurrentDeviceMap->SmbusDeviceUdid.Interface = SmbusUdid->Interface;
CurrentDeviceMap->SmbusDeviceUdid.SubsystemDeviceId = SmbusUdid->SubsystemDeviceId;
CurrentDeviceMap->SmbusDeviceUdid.SubsystemVendorId = SmbusUdid->SubsystemVendorId;
CurrentDeviceMap->SmbusDeviceUdid.VendorId = SmbusUdid->VendorId;
CurrentDeviceMap->SmbusDeviceUdid.VendorRevision = SmbusUdid->VendorRevision;
CurrentDeviceMap->SmbusDeviceUdid.VendorSpecificId = SmbusUdid->VendorSpecificId;
Status = SmbusAssignAddress (CurrentDeviceMap);
if (EFI_ERROR(Status)) {
return Status;
}
mDeviceMapEntries++;
SlaveAddress->SmbusDeviceAddress = CurrentDeviceMap->SmbusDeviceAddress.SmbusDeviceAddress;
return EFI_SUCCESS;
}
/**
Executes an SMBus operation to an SMBus controller. Returns when either the command has been
executed or an error is encountered in doing the operation.
The Execute() function provides a standard way to execute an operation as defined in the System
Management Bus (SMBus) Specification. The resulting transaction will be either that the SMBus
slave devices accept this transaction or that this function returns with error.
@param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
@param SlaveAddress The SMBus slave address of the device with which to communicate.
@param Command This command is transmitted by the SMBus host controller to the
SMBus slave device and the interpretation is SMBus slave device
specific. It can mean the offset to a list of functions inside an
SMBus slave device. Not all operations or slave devices support
this command's registers.
@param Operation Signifies which particular SMBus hardware protocol instance that
it will use to execute the SMBus transactions. This SMBus
hardware protocol is defined by the SMBus Specification and is
not related to EFI.
@param PecCheck Defines if Packet Error Code (PEC) checking is required for this
operation.
@param Length Signifies the number of bytes that this operation will do. The
maximum number of bytes can be revision specific and operation
specific. This field will contain the actual number of bytes that
are executed for this operation. Not all operations require this
argument.
@param Buffer Contains the value of data to execute to the SMBus slave device.
Not all operations require this argument. The length of this
buffer is identified by Length.
@retval EFI_SUCCESS The last data that was returned from the access matched the poll
exit criteria.
@retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).
@retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is
determined by the SMBus host controller device.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval EFI_DEVICE_ERROR The request was not completed because a failure that was
reflected in the Host Status Register bit. Device errors are a
result of a transaction collision, illegal command field,
unclaimed cycle (host initiated), or bus errors (collisions).
@retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.
@retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead
and EfiSmbusQuickWrite. Length is outside the range of valid
values.
@retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.
@retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.
**/
EFI_STATUS
EFIAPI
SmbusExecute (
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
IN CONST EFI_SMBUS_DEVICE_COMMAND Command,
IN CONST EFI_SMBUS_OPERATION Operation,
IN CONST BOOLEAN PecCheck,
IN OUT UINTN *Length,
IN OUT VOID *Buffer
)
{
InitializeInternal ();
return Execute (
SlaveAddress,
Command,
Operation,
PecCheck,
Length,
Buffer
);
}
/**
Sets the SMBus slave device addresses for the device with a given unique ID or enumerates the
entire bus.
The ArpDevice() function provides a standard way for a device driver to enumerate the entire
SMBus or specific devices on the bus.
@param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
@param ArpAll A Boolean expression that indicates if the host drivers need to
enumerate all the devices or enumerate only the device that is
identified by SmbusUdid. If ArpAll is TRUE, SmbusUdid and
SlaveAddress are optional. If ArpAll is FALSE, ArpDevice will
enumerate SmbusUdid and the address will be at SlaveAddress.
@param SmbusUdid The Unique Device Identifier (UDID) that is associated with this
device.
@param SlaveAddress The SMBus slave address that is associated with an SMBus UDID.
@retval EFI_SUCCESS The last data that was returned from the access matched the poll
exit criteria.
@retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).
@retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is
determined by the SMBus host controller device.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval EFI_DEVICE_ERROR The request was not completed because a failure that was
reflected in the Host Status Register bit. Device errors are a
result of a transaction collision, illegal command field,
unclaimed cycle (host initiated), or bus errors (collisions).
@retval EFI_UNSUPPORTED The corresponding SMBus operation is not supported.
**/
EFI_STATUS
EFIAPI
SmbusArpDevice (
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
IN BOOLEAN ArpAll,
IN EFI_SMBUS_UDID *SmbusUdid, OPTIONAL
IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress OPTIONAL
)
{
InitializeInternal ();
if (ArpAll) {
return SmbusFullArp ();
} else {
if ((SmbusUdid == NULL) || (SlaveAddress == NULL)) {
return EFI_INVALID_PARAMETER;
}
return SmbusDirectedArp ((EFI_SMBUS_UDID *)SmbusUdid, SlaveAddress);
}
}
/**
Returns a pointer to the Address Resolution Protocol (ARP) map that contains the ID/address pair
of the slave devices that were enumerated by the SMBus host controller driver.
The GetArpMap() function returns the mapping of all the SMBus devices that were enumerated by the
SMBus host driver.
@param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
@param Length Size of the buffer that contains the SMBus device map.
@param SmbusDeviceMap The pointer to the device map as enumerated by the SMBus
controller driver.
@retval EFI_SUCCESS The SMBus returned the current device map.
@retval EFI_UNSUPPORTED The corresponding operation is not supported.
**/
EFI_STATUS
EFIAPI
SmbusGetArpMap (
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
IN OUT UINTN *Length,
IN OUT EFI_SMBUS_DEVICE_MAP **SmbusDeviceMap
)
{
*Length = mDeviceMapEntries;
*SmbusDeviceMap = mDeviceMap;
return EFI_SUCCESS;
}
/**
Allows a device driver to register for a callback when the bus driver detects a state that it
needs to propagate to other drivers that are registered for a callback.
The Notify() function registers all the callback functions to allow the bus driver to call these
functions when the SlaveAddress/Data pair happens.
If NotifyFunction is NULL, then ASSERT ().
@param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
@param SlaveAddress The SMBUS hardware address to which the SMBUS device is
preassigned or allocated.
@param Data Data of the SMBus host notify command that the caller wants to be
called.
@param NotifyFunction The function to call when the bus driver detects the SlaveAddress
and Data pair.
@retval EFI_SUCCESS NotifyFunction was registered.
@retval EFI_UNSUPPORTED The corresponding operation is not supported.
**/
EFI_STATUS
EFIAPI
SmbusNotify (
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
IN CONST UINTN Data,
IN CONST EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction
)
{
return EFI_UNSUPPORTED;
}
/**
Entry point to the DXE Driver that produces the SMBus Host Controller Protocol.
@param ImageHandle ImageHandle of the loaded driver.
@param SystemTable Pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point of SMBus DXE driver is executed successfully.
@retval !EFI_SUCESS Some error occurs in the entry point of SMBus DXE driver.
**/
EFI_STATUS
EFIAPI
InitializeQNCSmbus (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
mPlatformNumRsvd = (UINT8)PcdGet32 (PcdPlatformSmbusAddrNum);
mPlatformAddrRsvd = (UINT8 *)(UINTN) PcdGet64 (PcdPlatformSmbusAddrTable);
//
// Install SMBus Host Controller protocol interface.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&mSmbusHcHandle,
&gEfiSmbusHcProtocolGuid,
&mSmbusHc,
NULL
);
ASSERT_EFI_ERROR (Status);
return Status;
}

View File

@@ -0,0 +1,211 @@
/** @file
Header file for the defintions used in SMBus DXE driver.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _DXE_QNC_SMBUS_H_
#define _DXE_QNC_SMBUS_H_
#include "CommonHeader.h"
#include "QNCSmbus.h"
#define MAX_SMBUS_DEVICES 107 // Max number of SMBus devices (7 bit
// address yields 128 combinations but 21
// of those are reserved)
#define MICROSECOND 10
#define MILLISECOND (1000 * MICROSECOND)
#define ONESECOND (1000 * MILLISECOND)
#define STALL_TIME 1000000 // 1,000,000 microseconds = 1 second
#define BUS_TRIES 3 // How many times to retry on Bus Errors
#define SMBUS_NUM_RESERVED 21 // Number of device addresses that are
// reserved by the SMBus spec.
#define SMBUS_ADDRESS_ARP 0xC2 >> 1
#define SMBUS_DATA_PREPARE_TO_ARP 0x01
#define SMBUS_DATA_RESET_DEVICE 0x02
#define SMBUS_DATA_GET_UDID_GENERAL 0x03
#define SMBUS_DATA_ASSIGN_ADDRESS 0x04
#define SMBUS_GET_UDID_LENGTH 17 // 16 byte UDID + 1 byte address
/**
Executes an SMBus operation to an SMBus controller. Returns when either the command has been
executed or an error is encountered in doing the operation.
The Execute() function provides a standard way to execute an operation as defined in the System
Management Bus (SMBus) Specification. The resulting transaction will be either that the SMBus
slave devices accept this transaction or that this function returns with error.
@param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
@param SlaveAddress The SMBus slave address of the device with which to communicate.
@param Command This command is transmitted by the SMBus host controller to the
SMBus slave device and the interpretation is SMBus slave device
specific. It can mean the offset to a list of functions inside an
SMBus slave device. Not all operations or slave devices support
this command's registers.
@param Operation Signifies which particular SMBus hardware protocol instance that
it will use to execute the SMBus transactions. This SMBus
hardware protocol is defined by the SMBus Specification and is
not related to EFI.
@param PecCheck Defines if Packet Error Code (PEC) checking is required for this
operation.
@param Length Signifies the number of bytes that this operation will do. The
maximum number of bytes can be revision specific and operation
specific. This field will contain the actual number of bytes that
are executed for this operation. Not all operations require this
argument.
@param Buffer Contains the value of data to execute to the SMBus slave device.
Not all operations require this argument. The length of this
buffer is identified by Length.
@retval EFI_SUCCESS The last data that was returned from the access matched the poll
exit criteria.
@retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).
@retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is
determined by the SMBus host controller device.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval EFI_DEVICE_ERROR The request was not completed because a failure that was
reflected in the Host Status Register bit. Device errors are a
result of a transaction collision, illegal command field,
unclaimed cycle (host initiated), or bus errors (collisions).
@retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.
@retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead
and EfiSmbusQuickWrite. Length is outside the range of valid
values.
@retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.
@retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.
**/
EFI_STATUS
EFIAPI
SmbusExecute (
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
IN CONST EFI_SMBUS_DEVICE_COMMAND Command,
IN CONST EFI_SMBUS_OPERATION Operation,
IN CONST BOOLEAN PecCheck,
IN OUT UINTN *Length,
IN OUT VOID *Buffer
);
/**
Sets the SMBus slave device addresses for the device with a given unique ID or enumerates the
entire bus.
The ArpDevice() function provides a standard way for a device driver to enumerate the entire
SMBus or specific devices on the bus.
@param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
@param ArpAll A Boolean expression that indicates if the host drivers need to
enumerate all the devices or enumerate only the device that is
identified by SmbusUdid. If ArpAll is TRUE, SmbusUdid and
SlaveAddress are optional. If ArpAll is FALSE, ArpDevice will
enumerate SmbusUdid and the address will be at SlaveAddress.
@param SmbusUdid The Unique Device Identifier (UDID) that is associated with this
device.
@param SlaveAddress The SMBus slave address that is associated with an SMBus UDID.
@retval EFI_SUCCESS The last data that was returned from the access matched the poll
exit criteria.
@retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).
@retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is
determined by the SMBus host controller device.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval EFI_DEVICE_ERROR The request was not completed because a failure that was
reflected in the Host Status Register bit. Device errors are a
result of a transaction collision, illegal command field,
unclaimed cycle (host initiated), or bus errors (collisions).
@retval EFI_UNSUPPORTED The corresponding operation is not supported.
**/
EFI_STATUS
EFIAPI
SmbusArpDevice (
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
IN BOOLEAN ArpAll,
IN EFI_SMBUS_UDID *SmbusUdid, OPTIONAL
IN OUT EFI_SMBUS_DEVICE_ADDRESS *SlaveAddress OPTIONAL
);
/**
Returns a pointer to the Address Resolution Protocol (ARP) map that contains the ID/address pair
of the slave devices that were enumerated by the SMBus host controller driver.
The GetArpMap() function returns the mapping of all the SMBus devices that were enumerated by the
SMBus host driver.
@param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
@param Length Size of the buffer that contains the SMBus device map.
@param SmbusDeviceMap The pointer to the device map as enumerated by the SMBus
controller driver.
@retval EFI_SUCCESS The SMBus returned the current device map.
@retval EFI_UNSUPPORTED The corresponding operation is not supported.
**/
EFI_STATUS
EFIAPI
SmbusGetArpMap (
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
IN OUT UINTN *Length,
IN OUT EFI_SMBUS_DEVICE_MAP **SmbusDeviceMap
);
/**
Allows a device driver to register for a callback when the bus driver detects a state that it
needs to propagate to other drivers that are registered for a callback.
The Notify() function registers all the callback functions to allow the bus driver to call these
functions when the SlaveAddress/Data pair happens.
If NotifyFunction is NULL, then ASSERT ().
@param This A pointer to the EFI_SMBUS_HC_PROTOCOL instance.
@param SlaveAddress The SMBUS hardware address to which the SMBUS device is
preassigned or allocated.
@param Data Data of the SMBus host notify command that the caller wants to be
called.
@param NotifyFunction The function to call when the bus driver detects the SlaveAddress
and Data pair.
@retval EFI_SUCCESS NotifyFunction was registered.
@retval EFI_UNSUPPORTED The corresponding operation is not supported.
**/
EFI_STATUS
EFIAPI
SmbusNotify (
IN CONST EFI_SMBUS_HC_PROTOCOL *This,
IN CONST EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
IN CONST UINTN Data,
IN CONST EFI_SMBUS_NOTIFY_FUNCTION NotifyFunction
);
/**
Entry point to the DXE Driver that produces the SMBus Host Controller Protocol.
@param ImageHandle ImageHandle of the loaded driver.
@param SystemTable Pointer to the EFI System Table.
@retval EFI_SUCCESS The entry point of SMBus DXE driver is executed successfully.
@retval !EFI_SUCESS Some error occurs in the entry point of SMBus DXE driver.
**/
EFI_STATUS
EFIAPI
InitializeQNCSmbus (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
#endif

View File

@@ -0,0 +1,243 @@
/** @file
QNC Legacy Region Driver
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "CommonHeader.h"
#include "LegacyRegion.h"
//
// Handle used to install the Legacy Region Protocol
//
EFI_HANDLE mLegacyRegion2Handle = NULL;
//
// Instance of the Legacy Region Protocol to install into the handle database
//
EFI_LEGACY_REGION2_PROTOCOL mLegacyRegion2 = {
LegacyRegion2Decode,
LegacyRegion2Lock,
LegacyRegion2BootLock,
LegacyRegion2Unlock,
LegacyRegionGetInfo
};
/**
Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
If the On parameter evaluates to TRUE, this function enables memory reads in the address range
Start to (Start + Length - 1).
If the On parameter evaluates to FALSE, this function disables memory reads in the address range
Start to (Start + Length - 1).
@param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
@param Start[in] The beginning of the physical address of the region whose attributes
should be modified.
@param Length[in] The number of bytes of memory whose attributes should be modified.
The actual number of bytes modified may be greater than the number
specified.
@param Granularity[out] The number of bytes in the last region affected. This may be less
than the total number of bytes affected if the starting address
was not aligned to a region's starting address or if the length
was greater than the number of bytes in the first region.
@param On[in] Decode / Non-Decode flag.
@retval EFI_SUCCESS The region's attributes were successfully modified.
@retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
**/
EFI_STATUS
EFIAPI
LegacyRegion2Decode (
IN EFI_LEGACY_REGION2_PROTOCOL *This,
IN UINT32 Start,
IN UINT32 Length,
OUT UINT32 *Granularity,
IN BOOLEAN *On
)
{
return QNCLegacyRegionManipulation (Start, Length, On, NULL, Granularity);
}
/**
Modify the hardware to disallow memory attribute changes in a region.
This function makes the attributes of a region read only. Once a region is boot-locked with this
function, the read and write attributes of that region cannot be changed until a power cycle has
reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.
@param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
@param Start[in] The beginning of the physical address of the region whose
attributes should be modified.
@param Length[in] The number of bytes of memory whose attributes should be modified.
The actual number of bytes modified may be greater than the number
specified.
@param Granularity[out] The number of bytes in the last region affected. This may be less
than the total number of bytes affected if the starting address was
not aligned to a region's starting address or if the length was
greater than the number of bytes in the first region.
@retval EFI_SUCCESS The region's attributes were successfully modified.
@retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
@retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in
a way that will not affect memory regions outside the legacy memory
region.
**/
EFI_STATUS
EFIAPI
LegacyRegion2BootLock (
IN EFI_LEGACY_REGION2_PROTOCOL *This,
IN UINT32 Start,
IN UINT32 Length,
OUT UINT32 *Granularity
)
{
if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) {
return EFI_INVALID_PARAMETER;
}
return EFI_UNSUPPORTED;
}
/**
Modify the hardware to disallow memory writes in a region.
This function changes the attributes of a memory range to not allow writes.
@param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
@param Start[in] The beginning of the physical address of the region whose
attributes should be modified.
@param Length[in] The number of bytes of memory whose attributes should be modified.
The actual number of bytes modified may be greater than the number
specified.
@param Granularity[out] The number of bytes in the last region affected. This may be less
than the total number of bytes affected if the starting address was
not aligned to a region's starting address or if the length was
greater than the number of bytes in the first region.
@retval EFI_SUCCESS The region's attributes were successfully modified.
@retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
**/
EFI_STATUS
EFIAPI
LegacyRegion2Lock (
IN EFI_LEGACY_REGION2_PROTOCOL *This,
IN UINT32 Start,
IN UINT32 Length,
OUT UINT32 *Granularity
)
{
BOOLEAN WriteEnable;
WriteEnable = FALSE;
return QNCLegacyRegionManipulation (Start, Length, NULL, &WriteEnable, Granularity);
}
/**
Modify the hardware to allow memory writes in a region.
This function changes the attributes of a memory range to allow writes.
@param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
@param Start[in] The beginning of the physical address of the region whose
attributes should be modified.
@param Length[in] The number of bytes of memory whose attributes should be modified.
The actual number of bytes modified may be greater than the number
specified.
@param Granularity[out] The number of bytes in the last region affected. This may be less
than the total number of bytes affected if the starting address was
not aligned to a region's starting address or if the length was
greater than the number of bytes in the first region.
@retval EFI_SUCCESS The region's attributes were successfully modified.
@retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
**/
EFI_STATUS
EFIAPI
LegacyRegion2Unlock (
IN EFI_LEGACY_REGION2_PROTOCOL *This,
IN UINT32 Start,
IN UINT32 Length,
OUT UINT32 *Granularity
)
{
BOOLEAN WriteEnable;
WriteEnable = TRUE;
return QNCLegacyRegionManipulation (Start, Length, NULL, &WriteEnable, Granularity);
}
/**
Get region information for the attributes of the Legacy Region.
This function is used to discover the granularity of the attributes for the memory in the legacy
region. Each attribute may have a different granularity and the granularity may not be the same
for all memory ranges in the legacy region.
@param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
@param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor
buffer.
@param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy
region information is deposited. This buffer will contain a list of
DescriptorCount number of region descriptors. This function will
provide the memory for the buffer.
@retval EFI_SUCCESS The region's attributes were successfully modified.
@retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
**/
EFI_STATUS
EFIAPI
LegacyRegionGetInfo (
IN EFI_LEGACY_REGION2_PROTOCOL *This,
OUT UINT32 *DescriptorCount,
OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor
)
{
return EFI_UNSUPPORTED;
}
/**
Entry point to the DXE Driver that produces the Legacy Region Protocol.
@retval EFI_SUCCESS One or more of the drivers returned a success code.
@retval !EFI_SUCESS The return status from the last driver entry point in the list.
**/
EFI_STATUS
LegacyRegionInit (
)
{
EFI_STATUS Status;
//
// Install the Legacy Region Protocol on a new handle
//
Status = gBS->InstallMultipleProtocolInterfaces (
&mLegacyRegion2Handle,
&gEfiLegacyRegion2ProtocolGuid, &mLegacyRegion2,
NULL
);
ASSERT_EFI_ERROR (Status);
return Status;
}

View File

@@ -0,0 +1,204 @@
/** @file
The header file legacy region initialization in QNC DXE component.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _LEGACY_REGION_H_
#define _LEGACY_REGION_H_
#include "CommonHeader.h"
#include <IndustryStandard/Pci.h>
#define LEGACY_REGION_INSTANCE_SIGNATURE SIGNATURE_32('R','E','G','N')
typedef struct {
UINT32 Signature;
EFI_HANDLE Handle;
EFI_LEGACY_REGION2_PROTOCOL LegacyRegion2;
EFI_HANDLE ImageHandle;
//
// Protocol for PAM register access
//
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
} LEGACY_REGION_INSTANCE;
#define LEGACY_REGION_INSTANCE_FROM_THIS(this) \
CR(this, LEGACY_REGION_INSTANCE, LegacyRegion2, LEGACY_REGION_INSTANCE_SIGNATURE)
EFI_STATUS
LegacyRegionManipluateRegion (
IN LEGACY_REGION_INSTANCE *Private
);
EFI_STATUS
LegacyRegionInit (
VOID
);
/**
Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.
If the On parameter evaluates to TRUE, this function enables memory reads in the address range
Start to (Start + Length - 1).
If the On parameter evaluates to FALSE, this function disables memory reads in the address range
Start to (Start + Length - 1).
@param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
@param Start[in] The beginning of the physical address of the region whose attributes
should be modified.
@param Length[in] The number of bytes of memory whose attributes should be modified.
The actual number of bytes modified may be greater than the number
specified.
@param Granularity[out] The number of bytes in the last region affected. This may be less
than the total number of bytes affected if the starting address
was not aligned to a region's starting address or if the length
was greater than the number of bytes in the first region.
@param On[in] Decode / Non-Decode flag.
@retval EFI_SUCCESS The region's attributes were successfully modified.
@retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
**/
EFI_STATUS
EFIAPI
LegacyRegion2Decode (
IN EFI_LEGACY_REGION2_PROTOCOL *This,
IN UINT32 Start,
IN UINT32 Length,
OUT UINT32 *Granularity,
IN BOOLEAN *On
);
/**
Modify the hardware to disallow memory writes in a region.
This function changes the attributes of a memory range to not allow writes.
@param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
@param Start[in] The beginning of the physical address of the region whose
attributes should be modified.
@param Length[in] The number of bytes of memory whose attributes should be modified.
The actual number of bytes modified may be greater than the number
specified.
@param Granularity[out] The number of bytes in the last region affected. This may be less
than the total number of bytes affected if the starting address was
not aligned to a region's starting address or if the length was
greater than the number of bytes in the first region.
@retval EFI_SUCCESS The region's attributes were successfully modified.
@retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
**/
EFI_STATUS
EFIAPI
LegacyRegion2Lock (
IN EFI_LEGACY_REGION2_PROTOCOL *This,
IN UINT32 Start,
IN UINT32 Length,
OUT UINT32 *Granularity
);
/**
Modify the hardware to disallow memory attribute changes in a region.
This function makes the attributes of a region read only. Once a region is boot-locked with this
function, the read and write attributes of that region cannot be changed until a power cycle has
reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.
@param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
@param Start[in] The beginning of the physical address of the region whose
attributes should be modified.
@param Length[in] The number of bytes of memory whose attributes should be modified.
The actual number of bytes modified may be greater than the number
specified.
@param Granularity[out] The number of bytes in the last region affected. This may be less
than the total number of bytes affected if the starting address was
not aligned to a region's starting address or if the length was
greater than the number of bytes in the first region.
@retval EFI_SUCCESS The region's attributes were successfully modified.
@retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
@retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in
a way that will not affect memory regions outside the legacy memory
region.
**/
EFI_STATUS
EFIAPI
LegacyRegion2BootLock (
IN EFI_LEGACY_REGION2_PROTOCOL *This,
IN UINT32 Start,
IN UINT32 Length,
OUT UINT32 *Granularity
);
/**
Modify the hardware to allow memory writes in a region.
This function changes the attributes of a memory range to allow writes.
@param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
@param Start[in] The beginning of the physical address of the region whose
attributes should be modified.
@param Length[in] The number of bytes of memory whose attributes should be modified.
The actual number of bytes modified may be greater than the number
specified.
@param Granularity[out] The number of bytes in the last region affected. This may be less
than the total number of bytes affected if the starting address was
not aligned to a region's starting address or if the length was
greater than the number of bytes in the first region.
@retval EFI_SUCCESS The region's attributes were successfully modified.
@retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
**/
EFI_STATUS
EFIAPI
LegacyRegion2Unlock (
IN EFI_LEGACY_REGION2_PROTOCOL *This,
IN UINT32 Start,
IN UINT32 Length,
OUT UINT32 *Granularity
);
/**
Get region information for the attributes of the Legacy Region.
This function is used to discover the granularity of the attributes for the memory in the legacy
region. Each attribute may have a different granularity and the granularity may not be the same
for all memory ranges in the legacy region.
@param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.
@param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor
buffer.
@param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy
region information is deposited. This buffer will contain a list of
DescriptorCount number of region descriptors. This function will
provide the memory for the buffer.
@retval EFI_SUCCESS The region's attributes were successfully modified.
@retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.
**/
EFI_STATUS
EFIAPI
LegacyRegionGetInfo (
IN EFI_LEGACY_REGION2_PROTOCOL *This,
OUT UINT32 *DescriptorCount,
OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor
);
#endif //_QNC_LEGACY_REGION_H_

View File

@@ -0,0 +1,527 @@
/** @file
QuarkNcSocId module initialization module
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "CommonHeader.h"
#include "LegacyRegion.h"
#include "DxeQNCSmbus.h"
#include "QNCInit.h"
//
// Definitions
//
#define QNC_RESERVED_ITEM_IO 0
#define QNC_RESERVED_ITEM_MEMORYIO 1
#define DXE_DEVICE_DISABLED 0
#define DXE_DEVICE_ENABLED 1
typedef struct _QNC_SPACE_TABLE_ITEM {
UINTN IoOrMemory;
UINTN Type;
EFI_PHYSICAL_ADDRESS BaseAddress;
UINT64 Length;
UINTN Alignment;
BOOLEAN RuntimeOrNot;
} QNC_SPACE_TABLE_ITEM;
typedef struct {
ACPI_CPU_DATA AcpuCpuData;
MTRR_SETTINGS MtrrTable;
IA32_DESCRIPTOR GdtrProfile;
IA32_DESCRIPTOR IdtrProfile;
CPU_REGISTER_TABLE RegisterTable;
CPU_REGISTER_TABLE PreSmmInitRegisterTable;
} ACPI_CPU_DATA_EX;
//
// Spaces to be reserved in GCD
// Expand it to add more
//
const QNC_SPACE_TABLE_ITEM mQNCReservedSpaceTable[] = {
{
QNC_RESERVED_ITEM_MEMORYIO,
EfiGcdMemoryTypeMemoryMappedIo,
FixedPcdGet64 (PcdIoApicBaseAddress),
FixedPcdGet64 (PcdIoApicSize),
0,
FALSE
},
{
QNC_RESERVED_ITEM_MEMORYIO,
EfiGcdMemoryTypeMemoryMappedIo,
FixedPcdGet64 (PcdHpetBaseAddress),
FixedPcdGet64 (PcdHpetSize),
0,
FALSE
}
};
//
// Global variable for ImageHandle of QNCInit driver
//
EFI_HANDLE gQNCInitImageHandle;
QNC_DEVICE_ENABLES mQNCDeviceEnables;
VOID
QNCInitializeResource (
VOID
);
EFI_STATUS
InitializeQNCPolicy (
VOID
);
/**
Allocate EfiACPIMemoryNVS below 4G memory address.
This function allocates EfiACPIMemoryNVS below 4G memory address.
@param Size Size of memory to allocate.
@return Allocated address for output.
**/
VOID *
AllocateAcpiNvsMemoryBelow4G (
IN UINTN Size
)
{
UINTN Pages;
EFI_PHYSICAL_ADDRESS Address;
EFI_STATUS Status;
VOID* Buffer;
Pages = EFI_SIZE_TO_PAGES (Size);
Address = 0xffffffff;
Status = gBS->AllocatePages (
AllocateMaxAddress,
EfiACPIMemoryNVS,
Pages,
&Address
);
if (EFI_ERROR (Status)) {
return NULL;
}
Buffer = (VOID *) (UINTN) Address;
ZeroMem (Buffer, Size);
return Buffer;
}
/**
Prepare ACPI NVS memory below 4G memory for use of S3 resume.
This function allocates ACPI NVS memory below 4G memory for use of S3 resume,
and saves data into the memory region.
**/
VOID
SaveCpuS3Data (
VOID
)
{
EFI_STATUS Status;
ACPI_CPU_DATA_EX *AcpiCpuDataEx;
ACPI_CPU_DATA *AcpiCpuData;
UINTN GdtSize;
UINTN IdtSize;
VOID *Gdt;
VOID *Idt;
//
// Allocate ACPI NVS memory below 4G memory for use of S3 resume.
//
AcpiCpuDataEx = AllocateAcpiNvsMemoryBelow4G (sizeof (ACPI_CPU_DATA_EX));
AcpiCpuData = &AcpiCpuDataEx->AcpuCpuData;
//
//
//
AcpiCpuData->NumberOfCpus = 1;
AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize);
AcpiCpuData->ApMachineCheckHandlerBase = 0;
AcpiCpuData->ApMachineCheckHandlerSize = 0;
AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->GdtrProfile;
AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->IdtrProfile;
AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->MtrrTable;
AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->RegisterTable;
AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->PreSmmInitRegisterTable;
//
// Allocate stack space for all CPUs
//
AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateAcpiNvsMemoryBelow4G (AcpiCpuData->NumberOfCpus * AcpiCpuData->StackSize);
//
// Get MTRR settings from currently executing CPU
//
MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);
//
// Get the BSP's data of GDT and IDT
//
AsmReadGdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->GdtrProfile);
AsmReadIdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->IdtrProfile);
//
// Allocate GDT and IDT in ACPI NVS and copy in current GDT and IDT contents
//
GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;
IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;
Gdt = AllocateAcpiNvsMemoryBelow4G (GdtSize + IdtSize);
Idt = (VOID *)((UINTN)Gdt + GdtSize);
CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);
CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);
AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;
AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;
//
// No RegisterTable entries
//
AcpiCpuDataEx->RegisterTable.TableLength = 0;
//
// No PreSmmInitRegisterTable entries
//
AcpiCpuDataEx->PreSmmInitRegisterTable.TableLength = 0;
//
// Set the base address of CPU S3 data to PcdCpuS3DataAddress
//
Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);
ASSERT_EFI_ERROR (Status);
}
/**
The entry function for QNCInit driver.
This function just call initialization function for PciHostBridge,
LegacyRegion and QNCSmmAccess module.
@param ImageHandle The driver image handle for GmchInit driver
@param SystemTable The pointer to System Table
@retval EFI_SUCCESS Success to initialize every module for GMCH driver.
@return EFI_STATUS The status of initialization work.
**/
EFI_STATUS
EFIAPI
QNCInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
S3BootScriptSaveInformationAsciiString (
"QNCInitDxeEntryBegin"
);
gQNCInitImageHandle = ImageHandle;
mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables);
//
// Initialize PCIE root ports
//
Status = QncInitRootPorts ();
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "QNC Root Port initialization is failed!\n"));
return Status;
}
Status = LegacyRegionInit ();
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "QNC LegacyRegion initialization is failed!\n"));
return Status;
}
Status = InitializeQNCPolicy ();
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "QNC Policy initialization is failed!\n"));
return Status;
}
Status = InitializeQNCSmbus (ImageHandle,SystemTable);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "QNC Smbus driver is failed!\n"));
return Status;
}
QNCInitializeResource ();
SaveCpuS3Data ();
S3BootScriptSaveInformationAsciiString (
"QNCInitDxeEntryEnd"
);
return EFI_SUCCESS;
}
/**
Reserve I/O or memory space in GCD
@param IoOrMemory Switch of I/O or memory.
@param GcdType Type of the space.
@param BaseAddress Base address of the space.
@param Length Length of the space.
@param Alignment Align with 2^Alignment
@param RuntimeOrNot For runtime usage or not
@param ImageHandle Handle for the image of this driver.
@retval EFI_SUCCESS Reserve successful
**/
EFI_STATUS
QNCReserveSpaceInGcd(
IN UINTN IoOrMemory,
IN UINTN GcdType,
IN EFI_PHYSICAL_ADDRESS BaseAddress,
IN UINT64 Length,
IN UINTN Alignment,
IN BOOLEAN RuntimeOrNot,
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
if (IoOrMemory == QNC_RESERVED_ITEM_MEMORYIO) {
Status = gDS->AddMemorySpace (
GcdType,
BaseAddress,
Length,
EFI_MEMORY_UC
);
if (EFI_ERROR (Status)) {
DEBUG ((
EFI_D_ERROR,
"Failed to add memory space :0x%x 0x%x\n",
BaseAddress,
Length
));
}
ASSERT_EFI_ERROR (Status);
Status = gDS->AllocateMemorySpace (
EfiGcdAllocateAddress,
GcdType,
Alignment,
Length,
&BaseAddress,
ImageHandle,
NULL
);
ASSERT_EFI_ERROR (Status);
if (RuntimeOrNot) {
Status = gDS->SetMemorySpaceAttributes (
BaseAddress,
Length,
EFI_MEMORY_RUNTIME | EFI_MEMORY_UC
);
ASSERT_EFI_ERROR (Status);
}
} else {
Status = gDS->AddIoSpace (
GcdType,
BaseAddress,
Length
);
ASSERT_EFI_ERROR (Status);
Status = gDS->AllocateIoSpace (
EfiGcdAllocateAddress,
GcdType,
Alignment,
Length,
&BaseAddress,
ImageHandle,
NULL
);
ASSERT_EFI_ERROR (Status);
}
return Status;
}
/**
Initialize the memory and io resource which belong to QNC.
1) Report and allocate all BAR's memory to GCD.
2) Report PCI memory and I/O space to GCD.
3) Set memory attribute for <1M memory space.
**/
VOID
QNCInitializeResource (
)
{
EFI_PHYSICAL_ADDRESS BaseAddress;
EFI_STATUS Status;
UINT64 ExtraRegionLength;
EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
UINTN Index;
// Report TSEG range
// This range maybe has been reportted in PEI phase via Resource Hob.
//
QNCGetTSEGMemoryRange (&BaseAddress, &ExtraRegionLength);
if (ExtraRegionLength != 0) {
Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &Descriptor);
if (Status == EFI_NOT_FOUND) {
Status = gDS->AddMemorySpace (
EfiGcdMemoryTypeReserved,
BaseAddress,
ExtraRegionLength,
EFI_MEMORY_UC
);
}
}
//
// < 1M resource setting. The memory ranges <1M has been added into GCD via
// resource hob produced by PEI phase. Here will set memory attribute of these
// ranges for DXE phase.
//
//
// Dos Area (0 ~ 0x9FFFFh)
//
Status = gDS->GetMemorySpaceDescriptor (0, &Descriptor);
DEBUG ((
EFI_D_INFO,
"DOS Area Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n",
Descriptor.BaseAddress,
Descriptor.Length,
Descriptor.Attributes
));
ASSERT_EFI_ERROR (Status);
Status = gDS->SetMemorySpaceAttributes(
0,
0xA0000,
EFI_MEMORY_WB
);
ASSERT_EFI_ERROR (Status);
//
// Default SMRAM UnCachable until SMBASE relocated.
//
Status = gDS->SetMemorySpaceAttributes(
0x30000,
0x10000,
EFI_MEMORY_UC
);
ASSERT_EFI_ERROR (Status);
//
// Default SMM ABSEG area. (0xA0000 ~ 0xBFFFF)
//
Status = gDS->GetMemorySpaceDescriptor (0xA0000, &Descriptor);
DEBUG ((
EFI_D_INFO,
"ABSEG Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n",
Descriptor.BaseAddress,
Descriptor.Length,
Descriptor.Attributes
));
ASSERT_EFI_ERROR (Status);
Status = gDS->SetMemorySpaceAttributes(
0xA0000,
0x20000,
EFI_MEMORY_UC
);
ASSERT_EFI_ERROR (Status);
//
// Expansion BIOS area.
//
Status = gDS->GetMemorySpaceDescriptor (0xC0000, &Descriptor);
DEBUG ((
EFI_D_INFO,
"Memory base = 0x%x, length = 0x%x, attribute = 0x%x\n",
Descriptor.BaseAddress,
Descriptor.Length,
Descriptor.Attributes
));
ASSERT_EFI_ERROR (Status);
Status = gDS->SetMemorySpaceAttributes(
0xC0000,
0x30000,
EFI_MEMORY_UC
);
ASSERT_EFI_ERROR (Status);
//
// Report other IO resources from mQNCReservedSpaceTable in GCD
//
for (Index = 0; Index < sizeof (mQNCReservedSpaceTable) / sizeof (QNC_SPACE_TABLE_ITEM); Index++) {
Status = QNCReserveSpaceInGcd (
mQNCReservedSpaceTable[Index].IoOrMemory,
mQNCReservedSpaceTable[Index].Type,
mQNCReservedSpaceTable[Index].BaseAddress,
mQNCReservedSpaceTable[Index].Length,
mQNCReservedSpaceTable[Index].Alignment,
mQNCReservedSpaceTable[Index].RuntimeOrNot,
gQNCInitImageHandle
);
ASSERT_EFI_ERROR (Status);
}
//
// Report unused PCIe config space as reserved.
//
if (PcdGet64 (PcdPciExpressSize) < SIZE_256MB) {
Status = QNCReserveSpaceInGcd (
QNC_RESERVED_ITEM_MEMORYIO,
EfiGcdMemoryTypeMemoryMappedIo,
(PcdGet64(PcdPciExpressBaseAddress) + PcdGet64(PcdPciExpressSize)),
(SIZE_256MB - PcdGet64(PcdPciExpressSize)),
0,
FALSE,
gQNCInitImageHandle
);
ASSERT_EFI_ERROR (Status);
}
}
/**
Use the platform PCD to initialize devices in the QNC
@param ImageHandle Handle for the image of this driver.
@retval EFI_SUCCESS Initialize successful
**/
EFI_STATUS
InitializeQNCPolicy (
)
{
UINT8 RevisionID;
UINT32 PciD31F0RegBase; // LPC
RevisionID = LpcPciCfg8(R_QNC_LPC_REV_ID);
PciD31F0RegBase = PciDeviceMmBase (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC);
//
// Disable for smbus
//
if (mQNCDeviceEnables.Bits.Smbus == DXE_DEVICE_DISABLED) {
S3MmioAnd32 (PciD31F0RegBase + R_QNC_LPC_SMBUS_BASE, (~B_QNC_LPC_SMBUS_BASE_EN));
}
return EFI_SUCCESS;
}

View File

@@ -0,0 +1,55 @@
/** @file
Header file for QNC Initialization Driver.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _QNC_INITIALIZATION_DRIVER_H_
#define _QNC_INITIALIZATION_DRIVER_H_
EFI_STATUS
QncInitRootPorts (
)
/*++
Routine Description:
Perform Initialization of the Downstream Root Ports.
Arguments:
Returns:
EFI_STATUS
--*/
;
EFI_STATUS
SetInitRootPortDownstreamS3Item (
)
/*++
Routine Description:
Set an Init Root Port Downstream devices S3 dispatch item, this function may assert if any error happend
Arguments:
Returns:
EFI_SUCCESS The function completed successfully
--*/
;
#endif

View File

@@ -0,0 +1,98 @@
## @file
# Component description file for QNCInit driver.
#
# QNCInit driver implement QuarkNcSocId related drivers, includes:
# PciHostBridge, PciExpress, SmmAccess driver and LegacyRegion driver.
#
# This driver mainly do full initialization for the QNC chipet includes:
# 1. Initialize the PCI Express device.
# 2. Initialize the PciHostBridge, and allocate the I/O and memory space from GCD service.
# 3. Initialize the SmmAccess module and install EFI_SMM_ACCESS_PROTOCOL
# 4. Initialize the LegacyRegion module, install EFI_LEGACY_REGION_PROTOCOL and set below 1M
# memory attribute from MTRR.
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = QNCInitDxe
FILE_GUID = 74D3B506-EE9C-47ed-B749-41261401DA78
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = QNCInit
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
LegacyRegion.h
LegacyRegion.c
DxeQNCSmbus.c
DxeQNCSmbus.h
QNCSmbusExec.c
QNCSmbus.h
QNCInit.c
QNCInit.h
CommonHeader.h
QNCRootPorts.c
[Packages]
MdePkg/MdePkg.dec
UefiCpuPkg/UefiCpuPkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
UefiDriverEntryPoint
BaseLib
UefiBootServicesTableLib
DxeServicesTableLib
BaseMemoryLib
DebugLib
PcdLib
MtrrLib
IoLib
SmbusLib
S3IoLib
S3BootScriptLib
IntelQNCLib
QNCAccessLib
[Protocols]
gEfiLegacyRegion2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
gEfiSmbusHcProtocolGuid # PROTOCOL ALWAYS_PRODUCED
gEfiQncS3SupportProtocolGuid # PROTOCOL ALWAYS_CONSUMED
[FeaturePcd]
gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddressFixed
[FixedPcd]
gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdIoApicSize
gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdHpetSize
[Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress|0x0|UINT64|0x60000010 ## PRODUCES
gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## CONSUMES
gEfiQuarkNcSocIdTokenSpaceGuid.PcdPciExpressSize ## CONSUMES
gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmbaIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdDeviceEnables
gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrNum
gEfiQuarkNcSocIdTokenSpaceGuid.PcdPlatformSmbusAddrTable
[Depex]
gEfiPlatformPolicyProtocolGuid AND gEfiQncS3SupportProtocolGuid

View File

@@ -0,0 +1,82 @@
/** @file
PciHostBridge driver module, part of QNC module.
Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "CommonHeader.h"
#include "QNCInit.h"
UINT32 mS3ParameterRootPortDownstream = 0;
EFI_QNC_S3_DISPATCH_ITEM mS3DispatchItem = {
QncS3ItemTypeInitPcieRootPortDownstream,
&mS3ParameterRootPortDownstream
};
EFI_STATUS
QncInitRootPorts (
)
/*++
Routine Description:
Perform Initialization of the Downstream Root Ports
Arguments:
Returns:
EFI_SUCCESS The function completed successfully
--*/
{
EFI_STATUS Status;
EFI_QNC_S3_SUPPORT_PROTOCOL *QncS3Support;
VOID *Context;
VOID *S3DispatchEntryPoint;
Status = PciExpressInit ();
ASSERT_EFI_ERROR (Status);
//
// Get the QNC S3 Support Protocol
//
Status = gBS->LocateProtocol (
&gEfiQncS3SupportProtocolGuid,
NULL,
(VOID **) &QncS3Support
);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get the QNC S3 Support Protocol
//
Status = QncS3Support->SetDispatchItem (
QncS3Support,
&mS3DispatchItem,
&S3DispatchEntryPoint,
&Context
);
ASSERT_EFI_ERROR (Status);
//
// Save the script dispatch item in the Boot Script
//
Status = S3BootScriptSaveDispatch2 (S3DispatchEntryPoint, Context);
ASSERT_EFI_ERROR (Status);
return Status;
}

View File

@@ -0,0 +1,86 @@
/** @file
Common definitons for SMBus PEIM/DXE driver. Smbus PEI and DXE
modules share the same version of this file.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _QNC_SMBUS_H_
#define _QNC_SMBUS_H_
#include "CommonHeader.h"
//
// Minimum and maximum length for SMBus bus block protocols defined in SMBus spec 2.0.
//
#define MIN_SMBUS_BLOCK_LEN 1
#define MAX_SMBUS_BLOCK_LEN 32
#define ADD_LENGTH(SmbusAddress, Length) ((SmbusAddress) + SMBUS_LIB_ADDRESS (0, 0, (Length), FALSE))
/**
Executes an SMBus operation to an SMBus controller. Returns when either the command has been
executed or an error is encountered in doing the operation.
The internal worker function provides a standard way to execute an operation as defined in the
System Management Bus (SMBus) Specification. The resulting transaction will be either that the
SMBus slave devices accept this transaction or that this function returns with error.
@param SlaveAddress The SMBus slave address of the device with which to communicate.
@param Command This command is transmitted by the SMBus host controller to the
SMBus slave device and the interpretation is SMBus slave device
specific. It can mean the offset to a list of functions inside an
SMBus slave device. Not all operations or slave devices support
this command's registers.
@param Operation Signifies which particular SMBus hardware protocol instance that
it will use to execute the SMBus transactions. This SMBus
hardware protocol is defined by the SMBus Specification and is
not related to EFI.
@param PecCheck Defines if Packet Error Code (PEC) checking is required for this
operation.
@param Length Signifies the number of bytes that this operation will do. The
maximum number of bytes can be revision specific and operation
specific. This field will contain the actual number of bytes that
are executed for this operation. Not all operations require this
argument.
@param Buffer Contains the value of data to execute to the SMBus slave device.
Not all operations require this argument. The length of this
buffer is identified by Length.
@retval EFI_SUCCESS The last data that was returned from the access matched the poll
exit criteria.
@retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).
@retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is
determined by the SMBus host controller device.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval EFI_DEVICE_ERROR The request was not completed because a failure that was
reflected in the Host Status Register bit. Device errors are a
result of a transaction collision, illegal command field,
unclaimed cycle (host initiated), or bus errors (collisions).
@retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.
@retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead
and EfiSmbusQuickWrite. Length is outside the range of valid
values.
@retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.
@retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.
**/
EFI_STATUS
Execute (
IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
IN EFI_SMBUS_DEVICE_COMMAND Command,
IN EFI_SMBUS_OPERATION Operation,
IN BOOLEAN PecCheck,
IN OUT UINTN *Length,
IN OUT VOID *Buffer
);
#endif

View File

@@ -0,0 +1,252 @@
/** @file
Common code to implement SMBus bus protocols. Smbus PEI and DXE modules
share the same version of this file.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "CommonHeader.h"
#include "QNCSmbus.h"
/**
Checks the parameter of SmbusExecute().
This function checks the input parameters of SmbusExecute(). If the input parameters are valid
for certain SMBus bus protocol, it will return EFI_SUCCESS; otherwise, it will return certain
error code based on the input SMBus bus protocol.
@param SlaveAddress The SMBus slave address of the device with which to communicate.
@param Command This command is transmitted by the SMBus host controller to the
SMBus slave device and the interpretation is SMBus slave device
specific. It can mean the offset to a list of functions inside an
SMBus slave device. Not all operations or slave devices support
this command's registers.
@param Operation Signifies which particular SMBus hardware protocol instance that
it will use to execute the SMBus transactions. This SMBus
hardware protocol is defined by the SMBus Specification and is
not related to EFI.
@param PecCheck Defines if Packet Error Code (PEC) checking is required for this
operation.
@param Length Signifies the number of bytes that this operation will do. The
maximum number of bytes can be revision specific and operation
specific. This field will contain the actual number of bytes that
are executed for this operation. Not all operations require this
argument.
@param Buffer Contains the value of data to execute to the SMBus slave device.
Not all operations require this argument. The length of this
buffer is identified by Length.
@retval EFI_SUCCESS All the parameters are valid for the corresponding SMBus bus
protocol.
@retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.
@retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead
and EfiSmbusQuickWrite. Length is outside the range of valid
values.
@retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.
@retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.
**/
EFI_STATUS
QncSmbusExecCheckParameters (
IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
IN EFI_SMBUS_DEVICE_COMMAND Command,
IN EFI_SMBUS_OPERATION Operation,
IN BOOLEAN PecCheck,
IN OUT UINTN *Length,
IN OUT VOID *Buffer
)
{
EFI_STATUS Status;
UINTN RequiredLen;
//
// Set default value to be 2:
// for SmbusReadWord, SmbusWriteWord and SmbusProcessCall.
//
RequiredLen = 2;
Status = EFI_SUCCESS;
switch (Operation) {
case EfiSmbusQuickRead:
case EfiSmbusQuickWrite:
if (PecCheck || Command != 0) {
return EFI_UNSUPPORTED;
}
break;
case EfiSmbusReceiveByte:
case EfiSmbusSendByte:
if (Command != 0) {
return EFI_UNSUPPORTED;
}
//
// Cascade to check length parameter.
//
case EfiSmbusReadByte:
case EfiSmbusWriteByte:
RequiredLen = 1;
//
// Cascade to check length parameter.
//
case EfiSmbusReadWord:
case EfiSmbusWriteWord:
case EfiSmbusProcessCall:
if (Buffer == NULL || Length == NULL) {
return EFI_INVALID_PARAMETER;
} else if (*Length < RequiredLen) {
Status = EFI_BUFFER_TOO_SMALL;
}
*Length = RequiredLen;
break;
case EfiSmbusReadBlock:
case EfiSmbusWriteBlock:
if ((Buffer == NULL) ||
(Length == NULL) ||
(*Length < MIN_SMBUS_BLOCK_LEN) ||
(*Length > MAX_SMBUS_BLOCK_LEN)) {
return EFI_INVALID_PARAMETER;
}
break;
case EfiSmbusBWBRProcessCall:
return EFI_UNSUPPORTED;
default:
return EFI_INVALID_PARAMETER;
}
return Status;
}
/**
Executes an SMBus operation to an SMBus controller. Returns when either the command has been
executed or an error is encountered in doing the operation.
The internal worker function provides a standard way to execute an operation as defined in the
System Management Bus (SMBus) Specification. The resulting transaction will be either that the
SMBus slave devices accept this transaction or that this function returns with error.
@param SlaveAddress The SMBus slave address of the device with which to communicate.
@param Command This command is transmitted by the SMBus host controller to the
SMBus slave device and the interpretation is SMBus slave device
specific. It can mean the offset to a list of functions inside an
SMBus slave device. Not all operations or slave devices support
this command's registers.
@param Operation Signifies which particular SMBus hardware protocol instance that
it will use to execute the SMBus transactions. This SMBus
hardware protocol is defined by the SMBus Specification and is
not related to EFI.
@param PecCheck Defines if Packet Error Code (PEC) checking is required for this
operation.
@param Length Signifies the number of bytes that this operation will do. The
maximum number of bytes can be revision specific and operation
specific. This field will contain the actual number of bytes that
are executed for this operation. Not all operations require this
argument.
@param Buffer Contains the value of data to execute to the SMBus slave device.
Not all operations require this argument. The length of this
buffer is identified by Length.
@retval EFI_SUCCESS The last data that was returned from the access matched the poll
exit criteria.
@retval EFI_CRC_ERROR Checksum is not correct (PEC is incorrect).
@retval EFI_TIMEOUT Timeout expired before the operation was completed. Timeout is
determined by the SMBus host controller device.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
@retval EFI_DEVICE_ERROR The request was not completed because a failure that was
reflected in the Host Status Register bit. Device errors are a
result of a transaction collision, illegal command field,
unclaimed cycle (host initiated), or bus errors (collisions).
@retval EFI_INVALID_PARAMETER Operation is not defined in EFI_SMBUS_OPERATION.
@retval EFI_INVALID_PARAMETER Length/Buffer is NULL for operations except for EfiSmbusQuickRead
and EfiSmbusQuickWrite. Length is outside the range of valid
values.
@retval EFI_UNSUPPORTED The SMBus operation or PEC is not supported.
@retval EFI_BUFFER_TOO_SMALL Buffer is not sufficient for this operation.
**/
EFI_STATUS
Execute (
IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress,
IN EFI_SMBUS_DEVICE_COMMAND Command,
IN EFI_SMBUS_OPERATION Operation,
IN BOOLEAN PecCheck,
IN OUT UINTN *Length,
IN OUT VOID *Buffer
)
{
EFI_STATUS Status;
UINTN SmbusAddress;
UINTN WorkBufferLen;
UINT8 WorkBuffer[MAX_SMBUS_BLOCK_LEN];
Status = QncSmbusExecCheckParameters (
SlaveAddress,
Command,
Operation,
PecCheck,
Length,
Buffer);
if (EFI_ERROR (Status)) {
return Status;
}
SmbusAddress = SMBUS_LIB_ADDRESS (SlaveAddress.SmbusDeviceAddress, Command, *Length, PecCheck);
switch (Operation) {
case EfiSmbusQuickRead:
SmBusQuickRead (SmbusAddress, &Status);
break;
case EfiSmbusQuickWrite:
SmBusQuickWrite (SmbusAddress, &Status);
break;
case EfiSmbusReceiveByte:
*(UINT8 *) Buffer = SmBusReceiveByte (SmbusAddress, &Status);
break;
case EfiSmbusSendByte:
SmBusSendByte (SmbusAddress, *(UINT8 *) Buffer, &Status);
break;
case EfiSmbusReadByte:
*(UINT8 *) Buffer = SmBusReadDataByte (SmbusAddress, &Status);
break;
case EfiSmbusWriteByte:
SmBusWriteDataByte (SmbusAddress, *(UINT8 *) Buffer, &Status);
break;
case EfiSmbusReadWord:
*(UINT16 *) Buffer = SmBusReadDataWord (SmbusAddress, &Status);
break;
case EfiSmbusWriteWord:
SmBusWriteDataWord (SmbusAddress, *(UINT16 *) Buffer, &Status);
break;
case EfiSmbusProcessCall:
*(UINT16 *) Buffer = SmBusProcessCall (SmbusAddress, *(UINT16 *) Buffer, &Status);
break;
case EfiSmbusReadBlock:
WorkBufferLen = SmBusReadBlock (SmbusAddress, WorkBuffer, &Status);
if (!EFI_ERROR (Status)) {
//
// Read block transaction is complete successfully, and then
// check whether the output buffer is large enough.
//
if (*Length >= WorkBufferLen) {
CopyMem (Buffer, WorkBuffer, WorkBufferLen);
} else {
Status = EFI_BUFFER_TOO_SMALL;
}
*Length = WorkBufferLen;
}
break;
case EfiSmbusWriteBlock:
SmBusWriteBlock (ADD_LENGTH (SmbusAddress, *Length), Buffer, &Status);
break;
default:
break;
}
return Status;
}

View File

@@ -0,0 +1,423 @@
/** @file
This is the driver that implements the QNC S3 Support protocol
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "QncS3Support.h"
//
// Global Variables
//
EFI_QNC_S3_SUPPORT_PROTOCOL mQncS3SupportProtocol;
QNC_S3_PARAMETER_HEADER *mS3Parameter;
UINT32 mQncS3ImageEntryPoint;
VOID *mQncS3ImageAddress;
UINTN mQncS3ImageSize;
extern EFI_GUID gQncS3CodeInLockBoxGuid;
extern EFI_GUID gQncS3ContextInLockBoxGuid;
/**
Create a buffer that is used to store context information for use with
dispatch functions.
@retval EFI_SUCCESS - Buffer allocated and initialized.
**/
EFI_STATUS
CreateContextBuffer (
VOID
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS Address;
UINT32 ContextStoreSize;
ContextStoreSize = EFI_PAGE_SIZE;
//
// Allcoate <4G EfiReservedMemory
//
Address = 0xFFFFFFFF;
Status = gBS->AllocatePages (AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (ContextStoreSize), &Address);
if (EFI_ERROR (Status)) {
return Status;
}
mS3Parameter = (QNC_S3_PARAMETER_HEADER *) (UINTN) Address;
//
// Determine the maximum number of context entries that can be stored in this
// table.
//
mS3Parameter->MaxContexts = ((ContextStoreSize - sizeof(QNC_S3_PARAMETER_HEADER)) / sizeof(EFI_DISPATCH_CONTEXT_UNION)) + 1;
mS3Parameter->StorePosition = 0;
return Status;
}
//
// Functions
//
EFI_STATUS
EFIAPI
QncS3SupportEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
QNC S3 support driver entry point
Arguments:
ImageHandle - Handle for the image of this driver
SystemTable - Pointer to the EFI System Table
Returns:
EFI_STATUS
--*/
{
EFI_STATUS Status;
VOID *TmpPtr;
EFI_EVENT Event;
//
// If the protocol is found execution is happening in ACPI NVS memory. If it
// is not found copy the driver into ACPI NVS memory and pass control to it.
//
Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &TmpPtr);
//
// Load the QNC S3 image
//
if (EFI_ERROR (Status)) {
Status = LoadQncS3Image (SystemTable);
ASSERT_EFI_ERROR (Status);
} else {
DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - Begin\n"));
//
// Allocate and initialize context buffer.
//
Status = CreateContextBuffer ();
if (EFI_ERROR (Status)) {
return Status;
}
//
// Install the QNC S3 Support protocol
//
mQncS3SupportProtocol.SetDispatchItem = QncS3SetDispatchItem;
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gEfiQncS3SupportProtocolGuid,
&mQncS3SupportProtocol,
NULL
);
mQncS3ImageAddress = (VOID *)(UINTN)PcdGet64(PcdQncS3CodeInLockBoxAddress);
mQncS3ImageSize = (UINTN)PcdGet64(PcdQncS3CodeInLockBoxSize);
DEBUG ((DEBUG_INFO, "QncS3SupportEntry Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize));
DEBUG ((DEBUG_INFO, "QncS3SupportEntry Contex = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE));
ASSERT (mQncS3ImageAddress != 0);
//
// Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
QncS3BootEvent,
NULL,
&gEfiEndOfDxeEventGroupGuid,
&Event
);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INFO, "QncS3SupportEntryPoint() in reserved memory - End\n"));
}
return Status;
}
EFI_STATUS
EFIAPI
QncS3SetDispatchItem (
IN EFI_QNC_S3_SUPPORT_PROTOCOL *This,
IN EFI_QNC_S3_DISPATCH_ITEM *DispatchItem,
OUT VOID **S3DispatchEntryPoint,
OUT VOID **Context
)
/*++
Routine Description:
Set an item to be dispatched at S3 resume time. At the same time, the entry point
of the QNC S3 support image is returned to be used in subsequent boot script save
call
Arguments:
This - Pointer to the protocol instance.
DispatchItem - The item to be dispatched.
S3DispatchEntryPoint - The entry point of the QNC S3 support image.
Returns:
EFI_STATUS - Successfully completed.
EFI_OUT_OF_RESOURCES - Out of resources.
--*/
{
DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() Start\n"));
//
// Set default values.
//
*S3DispatchEntryPoint = NULL;
*Context = NULL;
//
// Determine if this entry will fit.
//
if (mS3Parameter->StorePosition >= mS3Parameter->MaxContexts) {
DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem exceeds max length - 0x%08x\n", (UINTN)mS3Parameter->MaxContexts));
return EFI_OUT_OF_RESOURCES;
}
//
// Calculate the size required;
// ** Always round up to be 8 byte aligned
//
switch (DispatchItem->Type) {
case QncS3ItemTypeInitPcieRootPortDownstream:
*S3DispatchEntryPoint = (VOID*) (UINTN)QncS3InitPcieRootPortDownstream;
*Context = &mS3Parameter->Contexts[mS3Parameter->StorePosition];
CopyMem (&mS3Parameter->Contexts[mS3Parameter->StorePosition], DispatchItem->Parameter, sizeof(UINT32));
DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream @ 0x%08x - context 0x%08x\n", (UINTN)*S3DispatchEntryPoint, (UINTN)*Context));
break;
default:
return EFI_UNSUPPORTED;
}
mS3Parameter->StorePosition ++;
DEBUG ((DEBUG_INFO, "QncS3SetDispatchItem() End\n"));
return EFI_SUCCESS;
}
EFI_STATUS
LoadQncS3Image (
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Load the QNC S3 Image into Efi Reserved Memory below 4G.
Arguments:
ImageEntryPoint the ImageEntryPoint after success loading
Returns:
EFI_STATUS
--*/
{
EFI_STATUS Status;
UINT8 *Buffer;
UINTN BufferSize;
VOID *FfsBuffer;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
EFI_HANDLE NewImageHandle;
//
// Install NULL protocol on module file handle to indicate that the entry point
// has been called for the first time.
//
NewImageHandle = NULL;
Status = gBS->InstallProtocolInterface (
&NewImageHandle,
&gEfiCallerIdGuid,
EFI_NATIVE_INTERFACE,
NULL
);
//
// Find this module so it can be loaded again.
//
Status = GetSectionFromAnyFv (
&gEfiCallerIdGuid,
EFI_SECTION_PE32,
0,
(VOID**) &Buffer,
&BufferSize
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get information about the image being loaded.
//
ImageContext.Handle = Buffer;
ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
//
// Get information about the image being loaded
//
Status = PeCoffLoaderGetImageInfo (&ImageContext);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->AllocatePool (
EfiReservedMemoryType,
BufferSize + ImageContext.SectionAlignment,
&FfsBuffer
);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for no enough space! \n"));
return EFI_OUT_OF_RESOURCES;
}
mQncS3ImageAddress = FfsBuffer;
mQncS3ImageSize = BufferSize + ImageContext.SectionAlignment;
Status = PcdSet64S (PcdQncS3CodeInLockBoxAddress, (UINT64)(UINTN)mQncS3ImageAddress);
ASSERT_EFI_ERROR (Status);
Status = PcdSet64S (PcdQncS3CodeInLockBoxSize, (UINT64)mQncS3ImageSize);
ASSERT_EFI_ERROR (Status);
//
// Align buffer on section boundry
//
ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer;
if (ImageContext.SectionAlignment != 0) {
ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
}
//
// Load the image to our new buffer
//
Status = PeCoffLoaderLoadImage (&ImageContext);
if (EFI_ERROR (Status)) {
gBS->FreePool (FfsBuffer);
DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderLoadImage failure! \n"));
return Status;
}
//
// Relocate the image in our new buffer
//
Status = PeCoffLoaderRelocateImage (&ImageContext);
if (EFI_ERROR (Status)) {
PeCoffLoaderUnloadImage (&ImageContext);
gBS->FreePool (FfsBuffer);
DEBUG ((DEBUG_INFO, "LoadQncS3Image failed for PeCoffLoaderRelocateImage failure! \n"));
return Status;
}
//
// Invalidate instruction cache and pass control to the image. This will perform
// the initialization of the module and publish the supporting protocols.
//
InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);
if (EFI_ERROR (Status)) {
gBS->FreePool (FfsBuffer);
return Status;
}
return EFI_SUCCESS;
}
EFI_STATUS
QncS3InitPcieRootPortDownstream (
IN EFI_HANDLE ImageHandle,
IN VOID *Context
)
/*++
Routine Description:
Perform Init Root Port Downstream devices on S3 resume
Arguments:
Parameter Parameters passed in from DXE
Returns:
EFI_STATUS
--*/
{
EFI_STATUS Status;
DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() Begin\n"));
//
// Initialize the device behind the root port.
//
Status = PciExpressInit ();
//
// Not checking the error status here - downstream device not present does not
// mean an error of this root port. Our return status of EFI_SUCCESS means this
// port is enabled and outer function depends on this return status to do
// subsequent initializations.
//
if (Status != EFI_SUCCESS){
DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() failed\n"));
}
DEBUG ((DEBUG_INFO, "QncS3InitPcieRootPortDownstream() End\n"));
return Status;
}
VOID
EFIAPI
QncS3BootEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
//
// These 2 boxes will be restored by RestoreAllLockBoxInPlace in S3Resume automatically
//
DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Code = %08x, Size = %08x\n", (UINTN)mQncS3ImageAddress, mQncS3ImageSize));
SaveLockBox(&gQncS3CodeInLockBoxGuid, mQncS3ImageAddress, mQncS3ImageSize);
Status = SetLockBoxAttributes (&gQncS3CodeInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INFO, "SaveLockBox QncS3Context = %08x, Size = %08x\n", (UINTN)mS3Parameter, EFI_PAGE_SIZE));
SaveLockBox(&gQncS3ContextInLockBoxGuid, (VOID *)mS3Parameter, EFI_PAGE_SIZE);
Status = SetLockBoxAttributes (&gQncS3ContextInLockBoxGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
ASSERT_EFI_ERROR (Status);
}

View File

@@ -0,0 +1,123 @@
/** @file
Header file for QNC S3 Support driver
This file includes package header files, library classes and protocol, PPI & GUID definitions.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _QNC_S3_SUPPORT_H_
#define _QNC_S3_SUPPORT_H_
//
// External include files do NOT need to be explicitly specified in real EDKII
// environment
//
//
// Driver Consumed Protocol Prototypes
//
#include <Protocol/FirmwareVolume2.h>
#include <Library/UefiLib.h>
#include <Library/IoLib.h>
#include <Library/DebugLib.h>
#include <Library/DxeServicesLib.h>
#include <Library/S3BootScriptLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/PeCoffLib.h>
#include <Library/LockBoxLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
//
// Driver Produced Protocol Prototypes
//
#include <Protocol/LoadedImage.h>
#include <Protocol/QncS3Support.h>
#include <Library/CacheMaintenanceLib.h>
#include <Library/IntelQNCLib.h>
//
// Define the header of the context region.
//
typedef struct {
UINT32 MaxContexts;
UINT32 StorePosition;
EFI_DISPATCH_CONTEXT_UNION Contexts[1];
} QNC_S3_PARAMETER_HEADER;
//
// Function prototypes
//
EFI_STATUS
EFIAPI
QncS3SetDispatchItem (
IN EFI_QNC_S3_SUPPORT_PROTOCOL *This,
IN EFI_QNC_S3_DISPATCH_ITEM *DispatchItem,
OUT VOID **S3DispatchEntryPoint,
OUT VOID **Context
)
/*++
Routine Description:
Set an item to be dispatched at S3 resume time. At the same time, the entry point
of the QNC S3 support image is returned to be used in subsequent boot script save
call
Arguments:
This - Pointer to the protocol instance.
DispatchItem - The item to be dispatched.
S3DispatchEntryPoint - The entry point of the QNC S3 support image.
Returns:
EFI_STATUS - Successfully completed.
EFI_OUT_OF_RESOURCES - Out of resources.
--*/
;
EFI_STATUS
LoadQncS3Image (
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Load the QNC S3 Image into Efi Reserved Memory below 4G.
Arguments:
ImageEntryPoint the ImageEntryPoint after success loading
Returns:
EFI_STATUS
--*/
;
EFI_STATUS
QncS3InitPcieRootPortDownstream (
IN EFI_HANDLE ImageHandle,
IN VOID *Context
);
VOID
EFIAPI
QncS3BootEvent (
IN EFI_EVENT Event,
IN VOID *Context
);
#endif

View File

@@ -0,0 +1,70 @@
## @file
# Component description file for Qnc Initialization driver
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = QncS3Support
FILE_GUID = C7EA9787-CA0A-43b4-B1E5-25EF87391F8D
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = QncS3SupportEntryPoint
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
QncS3Support.h
QncS3Support.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
IoLib
DebugLib
DxeServicesLib
BaseMemoryLib
UefiDriverEntryPoint
PeCoffLib
LockBoxLib
S3BootScriptLib
UefiBootServicesTableLib
UefiRuntimeServicesTableLib
CacheMaintenanceLib
IntelQNCLib
[Protocols]
gEfiQncS3SupportProtocolGuid ## PRODUCES
gEfiLoadPeImageProtocolGuid ## CONSUMES
gEfiFirmwareVolume2ProtocolGuid ## CONSUMES
[Guids]
gQncS3CodeInLockBoxGuid
gQncS3ContextInLockBoxGuid
gEfiEndOfDxeEventGroupGuid
[Pcd]
gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdQncS3CodeInLockBoxSize
[Depex]
gEfiFirmwareVolume2ProtocolGuid AND
gEfiVariableArchProtocolGuid AND
gEfiVariableWriteArchProtocolGuid

View File

@@ -0,0 +1,54 @@
## @file
# Component description file for SmmAccess module
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = SmmAccess
FILE_GUID = 274F0C8F-9E57-41d8-9966-29CCD48D31C2
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = SmmAccessDriverEntryPoint
[Sources]
SmmAccessDriver.h
SmmAccessDriver.c
[Packages]
MdePkg/MdePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
HobLib
DebugLib
UefiLib
BaseLib
BaseMemoryLib
S3BootScriptLib
UefiDriverEntryPoint
UefiBootServicesTableLib
PcdLib
SmmLib
[Protocols]
gEfiPciRootBridgeIoProtocolGuid
gEfiSmmAccess2ProtocolGuid
[Guids]
gEfiSmmPeiSmramMemoryReserveGuid
[Depex]
gEfiPciRootBridgeIoProtocolGuid

View File

@@ -0,0 +1,395 @@
/** @file
This is the driver that publishes the SMM Access Protocol
instance for the Tylersburg chipset.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "SmmAccessDriver.h"
SMM_ACCESS_PRIVATE_DATA mSmmAccess;
VOID
SmmAccessOnBoot (
IN EFI_EVENT Event,
IN VOID *Context
);
EFI_STATUS
EFIAPI
SmmAccessDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Installs an SMM Access Protocol.
Arguments:
ImageHandle - Handle for the image of this driver.
SystemTable - Pointer to the EFI System Table.
Returns:
EFI_SUCCESS - Protocol successfully started and installed.
EFI_UNSUPPORTED - Protocol can't be started.
EFI_NOT_FOUND - Protocol not found.
--*/
{
EFI_STATUS Status;
EFI_EVENT BootEvent;
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
UINTN Index;
EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;
EFI_HOB_GUID_TYPE *GuidHob;
//
// Initialize private data
//
ZeroMem (&mSmmAccess, sizeof (mSmmAccess));
Status = gBS->LocateProtocol (
&gEfiPciRootBridgeIoProtocolGuid,
NULL,
(VOID **) &PciRootBridgeIo
);
ASSERT_EFI_ERROR (Status);
//
// Build SMM related information
//
mSmmAccess.Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE;
mSmmAccess.Handle = NULL;
mSmmAccess.PciRootBridgeIo = PciRootBridgeIo;
//
// Get Hob list
//
GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
ASSERT (DescriptorBlock);
//
// Get CPU Max bus number
//
mSmmAccess.MaxBusNumber = PCI_BUS_NUMBER_QNC;
for (Index = 0; Index < MAX_CPU_SOCKET; Index++) {
mSmmAccess.SocketPopulated[Index] = TRUE;
}
//
// Use the hob to publish SMRAM capabilities
//
ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES);
for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {
mSmmAccess.SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart;
mSmmAccess.SmramDesc[Index].CpuStart = DescriptorBlock->Descriptor[Index].CpuStart;
mSmmAccess.SmramDesc[Index].PhysicalSize = DescriptorBlock->Descriptor[Index].PhysicalSize;
mSmmAccess.SmramDesc[Index].RegionState = DescriptorBlock->Descriptor[Index].RegionState;
DEBUG ((EFI_D_INFO, "SM RAM index[%d] startaddr:%08X Size :%08X\n", Index, mSmmAccess.SmramDesc[Index].CpuStart,
mSmmAccess.SmramDesc[Index].PhysicalSize));
}
mSmmAccess.NumberRegions = Index;
mSmmAccess.SmmAccess.Open = Open;
mSmmAccess.SmmAccess.Close = Close;
mSmmAccess.SmmAccess.Lock = Lock;
mSmmAccess.SmmAccess.GetCapabilities = GetCapabilities;
mSmmAccess.SmmAccess.LockState = FALSE;
mSmmAccess.SmmAccess.OpenState = FALSE;
mSmmAccess.SMMRegionState = EFI_SMRAM_CLOSED;
//
// Install our protocol interfaces on the device's handle
//
Status = gBS->InstallMultipleProtocolInterfaces (
&mSmmAccess.Handle,
&gEfiSmmAccess2ProtocolGuid,
&mSmmAccess.SmmAccess,
NULL
);
ASSERT_EFI_ERROR (Status);
DEBUG ((EFI_D_INFO, "SMM Base: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalStart)));
DEBUG ((EFI_D_INFO, "SMM Size: %08X\n", (UINT32)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize)));
mSmmAccess.TsegSize = (UINT8)(mSmmAccess.SmramDesc[mSmmAccess.NumberRegions-1].PhysicalSize);
//
// T Seg setting done in QPI RC
//
//
// Prior ReadyToBoot, lock CSEG
//
Status = EfiCreateEventReadyToBootEx(
TPL_NOTIFY,
SmmAccessOnBoot,
NULL,
&BootEvent );
ASSERT (!EFI_ERROR (Status));
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
Open (
IN EFI_SMM_ACCESS2_PROTOCOL *This
)
/*++
Routine Description:
This routine accepts a request to "open" a region of SMRAM. The
region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
The use of "open" means that the memory is visible from all boot-service
and SMM agents.
Arguments:
This - Pointer to the SMM Access Interface.
DescriptorIndex - Region of SMRAM to Open.
Returns:
EFI_SUCCESS - The region was successfully opened.
EFI_DEVICE_ERROR - The region could not be opened because locked by
chipset.
EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
--*/
{
SMM_ACCESS_PRIVATE_DATA *SmmAccess;
SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {
DEBUG ((EFI_D_ERROR, "Cannot open a locked SMRAM region\n"));
return EFI_DEVICE_ERROR;
}
//
// Open TSEG
//
if (!QNCOpenSmramRegion ()) {
mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
return EFI_DEVICE_ERROR;
}
mSmmAccess.SMMRegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED);
SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~(EFI_SMRAM_CLOSED | EFI_ALLOCATED)));
mSmmAccess.SMMRegionState |= EFI_SMRAM_OPEN;
SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_OPEN);
SmmAccess->SmmAccess.OpenState = TRUE;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
Close (
IN EFI_SMM_ACCESS2_PROTOCOL *This
)
/*++
Routine Description:
This routine accepts a request to "close" a region of SMRAM. This is valid for
compatible SMRAM region.
Arguments:
This - Pointer to the SMM Access Interface.
DescriptorIndex - Region of SMRAM to Close.
Returns:
EFI_SUCCESS - The region was successfully closed.
EFI_DEVICE_ERROR - The region could not be closed because locked by
chipset.
EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
--*/
{
SMM_ACCESS_PRIVATE_DATA *SmmAccess;
BOOLEAN OpenState;
UINTN Index;
SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
if (mSmmAccess.SMMRegionState & EFI_SMRAM_LOCKED) {
//
// Cannot close a "locked" region
//
DEBUG ((EFI_D_WARN, "Cannot close the locked SMRAM Region\n"));
return EFI_DEVICE_ERROR;
}
if (mSmmAccess.SMMRegionState & EFI_SMRAM_CLOSED) {
return EFI_DEVICE_ERROR;
}
//
// Close TSEG
//
if (!QNCCloseSmramRegion ()) {
mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
return EFI_DEVICE_ERROR;
}
mSmmAccess.SMMRegionState &= ~EFI_SMRAM_OPEN;
SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~EFI_SMRAM_OPEN));
mSmmAccess.SMMRegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED);
SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_CLOSED | EFI_ALLOCATED);
//
// Find out if any regions are still open
//
OpenState = FALSE;
for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {
if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) {
OpenState = TRUE;
}
}
SmmAccess->SmmAccess.OpenState = OpenState;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
Lock (
IN EFI_SMM_ACCESS2_PROTOCOL *This
)
/*++
Routine Description:
This routine accepts a request to "lock" SMRAM. The
region could be legacy AB or TSEG near top of physical memory.
The use of "lock" means that the memory can no longer be opened
to BS state..
Arguments:
This - Pointer to the SMM Access Interface.
DescriptorIndex - Region of SMRAM to Lock.
Returns:
EFI_SUCCESS - The region was successfully locked.
EFI_DEVICE_ERROR - The region could not be locked because at least
one range is still open.
EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
--*/
{
SMM_ACCESS_PRIVATE_DATA *SmmAccess;
SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
if (SmmAccess->SmmAccess.OpenState) {
return EFI_DEVICE_ERROR;
}
mSmmAccess.SMMRegionState |= EFI_SMRAM_LOCKED;
SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_LOCKED);
SmmAccess->SmmAccess.LockState = TRUE;
//
// Lock TSEG
//
QNCLockSmramRegion ();
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GetCapabilities (
IN CONST EFI_SMM_ACCESS2_PROTOCOL *This,
IN OUT UINTN *SmramMapSize,
IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap
)
/*++
Routine Description:
This routine services a user request to discover the SMRAM
capabilities of this platform. This will report the possible
ranges that are possible for SMRAM access, based upon the
memory controller capabilities.
Arguments:
This - Pointer to the SMRAM Access Interface.
SmramMapSize - Pointer to the variable containing size of the
buffer to contain the description information.
SmramMap - Buffer containing the data describing the Smram
region descriptors.
Returns:
EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer.
EFI_SUCCESS - The user provided a sufficiently-sized buffer.
--*/
{
EFI_STATUS Status;
SMM_ACCESS_PRIVATE_DATA *SmmAccess;
UINTN BufferSize;
SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
BufferSize = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR);
if (*SmramMapSize < BufferSize) {
Status = EFI_BUFFER_TOO_SMALL;
} else {
CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize);
Status = EFI_SUCCESS;
}
*SmramMapSize = BufferSize;
return Status;
}
VOID
SmmAccessOnBoot (
IN EFI_EVENT Event,
IN VOID *Context
)
{
}
VOID
SyncRegionState2SmramDesc(
IN BOOLEAN OrAnd,
IN UINT64 Value
)
{
UINT32 Index;
for (Index = 0; Index < mSmmAccess.NumberRegions; Index++) {
if (OrAnd) {
mSmmAccess.SmramDesc[Index].RegionState |= Value;
} else {
mSmmAccess.SmramDesc[Index].RegionState &= Value;
}
}
}

View File

@@ -0,0 +1,235 @@
/** @file
Header file for SMM Access Driver.
This file includes package header files, library classes and protocol, PPI & GUID definitions.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef _SMM_ACCESS_DRIVER_H
#define _SMM_ACCESS_DRIVER_H
#include <PiDxe.h>
#include <IndustryStandard/Pci.h>
#include <Library/HobLib.h>
#include <Library/BaseLib.h>
#include <Library/UefiLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/PcdLib.h>
//
// Driver Consumed Protocol Prototypes
//
#include <Protocol/PciRootBridgeIo.h>
//
// Driver Consumed GUID Prototypes
//
#include <Guid/SmramMemoryReserve.h>
//
// Driver produced protocol
//
#include <Protocol/SmmAccess2.h>
#include <Library/QNCSmmLib.h>
#include <QNCAccess.h>
#define MAX_CPU_SOCKET 1
#define MAX_SMRAM_RANGES 4
//
// Private data structure
//
#define SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', 's', 'm', 'a')
typedef struct {
UINTN Signature;
EFI_HANDLE Handle;
EFI_SMM_ACCESS2_PROTOCOL SmmAccess;
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
UINTN NumberRegions;
EFI_SMRAM_DESCRIPTOR SmramDesc[MAX_SMRAM_RANGES];
UINT8 TsegSize;
UINT8 MaxBusNumber;
UINT8 SocketPopulated[MAX_CPU_SOCKET];
UINT64 SMMRegionState;
UINT8 ActualNLIioBusNumber;
} SMM_ACCESS_PRIVATE_DATA;
#define SMM_ACCESS_PRIVATE_DATA_FROM_THIS(a) \
CR ( \
a, \
SMM_ACCESS_PRIVATE_DATA, \
SmmAccess, \
SMM_ACCESS_PRIVATE_DATA_SIGNATURE \
)
//
// Prototypes
// Driver model protocol interface
//
EFI_STATUS
EFIAPI
SmmAccessDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
This is the standard EFI driver point that detects
whether there is an proper chipset in the system
and if so, installs an SMM Access Protocol.
Arguments:
ImageHandle - Handle for the image of this driver.
SystemTable - Pointer to the EFI System Table.
Returns:
EFI_SUCCESS - Protocol successfully started and installed.
EFI_UNSUPPORTED - Protocol can't be started.
--*/
;
EFI_STATUS
EFIAPI
Open (
IN EFI_SMM_ACCESS2_PROTOCOL *This
)
/*++
Routine Description:
This routine accepts a request to "open" a region of SMRAM. The
region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
The use of "open" means that the memory is visible from all boot-service
and SMM agents.
Arguments:
This - Pointer to the SMM Access Interface.
DescriptorIndex - Region of SMRAM to Open.
Returns:
EFI_SUCCESS - The region was successfully opened.
EFI_DEVICE_ERROR - The region could not be opened because locked by
chipset.
EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
--*/
;
EFI_STATUS
EFIAPI
Close (
IN EFI_SMM_ACCESS2_PROTOCOL *This
)
/*++
Routine Description:
This routine accepts a request to "close" a region of SMRAM. This is valid for
compatible SMRAM region.
Arguments:
This - Pointer to the SMM Access Interface.
DescriptorIndex - Region of SMRAM to Close.
Returns:
EFI_SUCCESS - The region was successfully closed.
EFI_DEVICE_ERROR - The region could not be closed because locked by
chipset.
EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
--*/
;
EFI_STATUS
EFIAPI
Lock (
IN EFI_SMM_ACCESS2_PROTOCOL *This
)
/*++
Routine Description:
This routine accepts a request to "lock" SMRAM. The
region could be legacy AB or TSEG near top of physical memory.
The use of "lock" means that the memory can no longer be opened
to BS state..
Arguments:
This - Pointer to the SMM Access Interface.
DescriptorIndex - Region of SMRAM to Lock.
Returns:
EFI_SUCCESS - The region was successfully locked.
EFI_DEVICE_ERROR - The region could not be locked because at least
one range is still open.
EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
--*/
;
EFI_STATUS
EFIAPI
GetCapabilities (
IN CONST EFI_SMM_ACCESS2_PROTOCOL *This,
IN OUT UINTN *SmramMapSize,
IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap
)
/*++
Routine Description:
This routine services a user request to discover the SMRAM
capabilities of this platform. This will report the possible
ranges that are possible for SMRAM access, based upon the
memory controller capabilities.
Arguments:
This - Pointer to the SMRAM Access Interface.
SmramMapSize - Pointer to the variable containing size of the
buffer to contain the description information.
SmramMap - Buffer containing the data describing the Smram
region descriptors.
Returns:
EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer.
EFI_SUCCESS - The user provided a sufficiently-sized buffer.
--*/
;
VOID
SyncRegionState2SmramDesc(
IN BOOLEAN OrAnd,
IN UINT64 Value
);
#endif

View File

@@ -0,0 +1,366 @@
/** @file
This module produces the SMM COntrol2 Protocol for QNC
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiDxe.h>
#include <Protocol/SmmControl2.h>
#include <IndustryStandard/Pci.h>
#include <Library/DebugLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/PcdLib.h>
#include <Library/IoLib.h>
#include <Library/PciLib.h>
#include <IntelQNCDxe.h>
#include <Library/QNCAccessLib.h>
#include <Uefi/UefiBaseType.h>
#define EFI_INTERNAL_POINTER 0x00000004
extern EFI_GUID gEfiEventVirtualAddressChangeGuid;
/**
Generates an SMI using the parameters passed in.
@param This A pointer to an instance of
EFI_SMM_CONTROL2_PROTOCOL
@param ArgumentBuffer The argument buffer
@param ArgumentBufferSize The size of the argument buffer
@param Periodic TRUE to indicate a periodical SMI
@param ActivationInterval Interval of the periodical SMI
@retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
@return Return value from SmmTrigger().
**/
EFI_STATUS
EFIAPI
Activate (
IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
IN OUT UINT8 *CommandPort OPTIONAL,
IN OUT UINT8 *DataPort OPTIONAL,
IN BOOLEAN Periodic OPTIONAL,
IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
);
/**
Clears an SMI.
@param This Pointer to an instance of EFI_SMM_CONTROL2_PROTOCOL
@param Periodic TRUE to indicate a periodical SMI
@return Return value from SmmClear()
**/
EFI_STATUS
EFIAPI
Deactivate (
IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
IN BOOLEAN Periodic OPTIONAL
);
///
/// Handle for the SMM Control2 Protocol
///
EFI_HANDLE mSmmControl2Handle = NULL;
///
/// SMM COntrol2 Protocol instance
///
EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {
Activate,
Deactivate,
0
};
VOID
EFIAPI
SmmControlVirtualddressChangeEvent (
IN EFI_EVENT Event,
IN VOID *Context
)
/*++
Routine Description:
Fixup internal data pointers so that the services can be called in virtual mode.
Arguments:
Event The event registered.
Context Event context.
Returns:
None.
--*/
{
gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Trigger));
gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID *) &(mSmmControl2.Clear));
}
/**
Clear SMI related chipset status and re-enable SMI by setting the EOS bit.
@retval EFI_SUCCESS The requested operation has been carried out successfully
@retval EFI_DEVICE_ERROR The EOS bit could not be set.
**/
EFI_STATUS
SmmClear (
VOID
)
{
UINT16 PM1BLK_Base;
UINT16 GPE0BLK_Base;
//
// Get PM1BLK_Base & GPE0BLK_Base
//
PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
//
// Clear the Power Button Override Status Bit, it gates EOS from being set.
// In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.
//
//
// Clear the APM SMI Status Bit
//
IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
//
// Set the EOS Bit
//
IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
return EFI_SUCCESS;
}
/**
Generates an SMI using the parameters passed in.
@param This A pointer to an instance of
EFI_SMM_CONTROL_PROTOCOL
@param ArgumentBuffer The argument buffer
@param ArgumentBufferSize The size of the argument buffer
@param Periodic TRUE to indicate a periodical SMI
@param ActivationInterval Interval of the periodical SMI
@retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
@retval EFI_SUCCESS SMI generated
**/
EFI_STATUS
EFIAPI
Activate (
IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
IN OUT UINT8 *CommandPort OPTIONAL,
IN OUT UINT8 *DataPort OPTIONAL,
IN BOOLEAN Periodic OPTIONAL,
IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
)
{
UINT16 GPE0BLK_Base;
UINT32 NewValue;
//
// Get GPE0BLK_Base
//
GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
if (Periodic) {
return EFI_INVALID_PARAMETER;
}
//
// Clear any pending the APM SMI
//
if (EFI_ERROR (SmmClear())) {
return EFI_DEVICE_ERROR;
}
//
// Enable the APMC SMI
//
IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);
//
// Enable SMI globally
//
NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
NewValue |= SMI_EN;
QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
//
// Set APMC_STS
//
if (DataPort == NULL) {
IoWrite8 (PcdGet16 (PcdSmmDataPort), 0xFF);
} else {
IoWrite8 (PcdGet16 (PcdSmmDataPort), *DataPort);
}
//
// Generate the APMC SMI
//
if (CommandPort == NULL) {
IoWrite8 (PcdGet16 (PcdSmmActivationPort), 0xFF);
} else {
IoWrite8 (PcdGet16 (PcdSmmActivationPort), *CommandPort);
}
return EFI_SUCCESS;
}
/**
Clears an SMI.
@param This Pointer to an instance of EFI_SMM_CONTROL_PROTOCOL
@param Periodic TRUE to indicate a periodical SMI
@return Return value from SmmClear()
**/
EFI_STATUS
EFIAPI
Deactivate (
IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
IN BOOLEAN Periodic
)
{
if (Periodic) {
return EFI_INVALID_PARAMETER;
}
return SmmClear();
}
/**
This is the constructor for the SMM Control protocol.
This function installs EFI_SMM_CONTROL2_PROTOCOL.
@param ImageHandle Handle for the image of this driver
@param SystemTable Pointer to the EFI System Table
@retval EFI_UNSUPPORTED There's no Intel ICH on this platform
@return The status returned from InstallProtocolInterface().
--*/
EFI_STATUS
SmmControl2Init (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_EVENT Event;
UINT16 PM1BLK_Base;
UINT16 GPE0BLK_Base;
BOOLEAN SciEn;
UINT32 NewValue;
//
// Get PM1BLK_Base & GPE0BLK_Base
//
PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
//
// Install our protocol interfaces on the device's handle
//
Status = gBS->InstallMultipleProtocolInterfaces (
&mSmmControl2Handle,
&gEfiSmmControl2ProtocolGuid, &mSmmControl2,
NULL
);
ASSERT_EFI_ERROR (Status);
//
// Determine whether an ACPI OS is present (via the SCI_EN bit)
//
SciEn = (BOOLEAN)((IoRead16 (PM1BLK_Base + R_QNC_PM1BLK_PM1C) & B_QNC_PM1BLK_PM1C_SCIEN) != 0);
if (!SciEn) {
//
// Clear any SMIs that double as SCIs (when SCI_EN==0)
//
IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1S), B_QNC_PM1BLK_PM1S_ALL);
IoWrite16 ((PM1BLK_Base + R_QNC_PM1BLK_PM1E), 0x00000000);
IoWrite32 ((PM1BLK_Base + R_QNC_PM1BLK_PM1C), 0x00000000);
IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0S), B_QNC_GPE0BLK_GPE0S_ALL);
IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_GPE0E), 0x00000000);
}
//
// Clear and disable all SMIs that are unaffected by SCI_EN
// Set EOS
//
IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIE), 0x00000000);
IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), (B_QNC_GPE0BLK_SMIS_EOS + B_QNC_GPE0BLK_SMIS_ALL));
//
// Enable SMI globally
//
NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
NewValue |= SMI_EN;
QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
//
// Make sure to write this register last -- EOS re-enables SMIs for the QNC
//
IoAndThenOr32 (
GPE0BLK_Base + R_QNC_GPE0BLK_SMIE,
(UINT32)(~B_QNC_GPE0BLK_SMIE_ALL),
B_QNC_GPE0BLK_SMIE_APM
);
//
// Make sure EOS bit cleared
//
DEBUG_CODE_BEGIN ();
if (IoRead32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIS) & B_QNC_GPE0BLK_SMIS_EOS) {
DEBUG ((
EFI_D_ERROR,
"******************************************************************************\n"
"BIG ERROR: SmmControl constructor couldn't properly initialize the ACPI table.\n"
" SmmControl->Clear will probably hang. \n"
" NOTE: SCI_EN = %d \n"
"******************************************************************************\n",
SciEn
));
//
// If we want the system to stop, then keep the ASSERT(FALSE).
// Otherwise, comment it out.
//
ASSERT (FALSE);
}
DEBUG_CODE_END ();
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
SmmControlVirtualddressChangeEvent,
NULL,
&gEfiEventVirtualAddressChangeGuid,
&Event
);
ASSERT_EFI_ERROR (Status);
return Status;
}

View File

@@ -0,0 +1,61 @@
## @file
# QNC SmmControl driver to install EFI_SMM_CONTROL_PROTOCOL.
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = SmmControlDxe
FILE_GUID = A03A9429-C570-4ef9-9E00-C7A673976E5F
MODULE_TYPE = DXE_RUNTIME_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = SmmControl2Init
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
SmmControlDriver.c
[Packages]
MdePkg/MdePkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
UefiDriverEntryPoint
DebugLib
UefiBootServicesTableLib
UefiRuntimeServicesTableLib
PcdLib
IoLib
PciLib
QNCAccessLib
[Protocols]
gEfiSmmControl2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
[Pcd]
gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmDataPort
gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort
gEfiQuarkNcSocIdTokenSpaceGuid.PcdGbaIoBaseAddress
[Guids]
gEfiEventVirtualAddressChangeGuid
[Depex]
TRUE

View File

@@ -0,0 +1,51 @@
/** @file
Common header file shared by all source files.
This file includes package header files, library classes and protocol, PPI & GUID definitions.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __COMMON_HEADER_H_
#define __COMMON_HEADER_H_
#include <PiSmm.h>
#include <IntelQNCDxe.h>
#include <Protocol/SmmUsbDispatch2.h>
#include <Protocol/SmmPeriodicTimerDispatch2.h>
#include <Protocol/SmmIchnDispatch2.h>
#include <Protocol/SmmPowerButtonDispatch2.h>
#include <Protocol/SmmGpiDispatch2.h>
#include <Protocol/SmmSxDispatch2.h>
#include <Protocol/SmmSwDispatch2.h>
#include <Protocol/SmmIoTrapDispatch2.h>
#include <Protocol/SmmCpu.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/SmmServicesTableLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/PcdLib.h>
#include <Library/PciLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/IoLib.h>
#include <Library/DevicePathLib.h>
#include <Library/S3IoLib.h>
#include <Library/QNCAccessLib.h>
#include <Uefi/UefiBaseType.h>
#endif

View File

@@ -0,0 +1,38 @@
/** @file
File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "QNCSmmHelpers.h"
CONST QNC_SMM_SOURCE_DESC GPI_SOURCE_DESC = {
QNC_SMM_NO_FLAGS,
{
{
{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_GPIO
},
NULL_BIT_DESC_INITIALIZER
},
{
{
{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_GPIO
}
}
};

View File

@@ -0,0 +1,555 @@
/** @file
This driver is responsible for the registration of child drivers
and the abstraction of the QNC SMI sources.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "QNCSmmHelpers.h"
//
// Help handle porting bit shifts to IA-64.
//
#define BIT_ZERO 0x00000001
VOID
QNCSmmPublishDispatchProtocols(
VOID
)
{
UINTN Index;
EFI_STATUS Status;
//
// Install protocol interfaces.
//
for (Index = 0; Index < NUM_PROTOCOLS; Index++) {
Status = gSmst->SmmInstallProtocolInterface (
&mPrivateData.InstallMultProtHandle,
mPrivateData.Protocols[Index].Guid,
EFI_NATIVE_INTERFACE,
&mPrivateData.Protocols[Index].Protocols.Generic
);
ASSERT_EFI_ERROR (Status);
}
}
EFI_STATUS
QNCSmmInitHardware(
VOID
)
/*++
Routine Description:
Initialize bits that aren't necessarily related to an SMI source.
Dependencies:
gSmst - SMM System Table; contains an entry for SMM CPU IO
Returns:
EFI_SUCCESS. Asserts, otherwise.
--*/
{
EFI_STATUS Status;
//
// Clear all SMIs
//
QNCSmmClearSmi();
Status = QNCSmmEnableGlobalSmiBit ();
ASSERT_EFI_ERROR (Status);
//
// Be *really* sure to clear all SMIs
//
QNCSmmClearSmi ();
return EFI_SUCCESS;
}
EFI_STATUS
QNCSmmEnableGlobalSmiBit (
VOID
)
/*++
Routine Description:
Enables the QNC to generate SMIs. Note that no SMIs will be generated
if no SMI sources are enabled. Conversely, no enabled SMI source will
generate SMIs if SMIs are not globally enabled. This is the main
switchbox for SMI generation.
Arguments:
None
Returns:
EFI_SUCCESS.
Asserts, otherwise.
--*/
{
UINT32 NewValue;
//
// Enable SMI globally
//
NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
NewValue |= SMI_EN;
QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
return EFI_SUCCESS;
}
EFI_STATUS
QNCSmmClearSmi(
VOID
)
/*++
Routine Description:
Clears the SMI after all SMI source have been processed.
Note that this function will not work correctly (as it is
written) unless all SMI sources have been processed.
A revision of this function could manually clear all SMI
status bits to guarantee success.
Returns:
EFI_SUCCESS.
Asserts, otherwise.
--*/
{
BOOLEAN EosSet;
BOOLEAN SciEn;
UINT32 Pm1Cnt = 0;
UINT16 Pm1Sts = 0;
UINT32 Gpe0Sts = 0;
UINT32 SmiSts = 0;
//
// Determine whether an ACPI OS is present (via the SCI_EN bit)
//
Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);
if (SciEn == FALSE) {
//
// Clear any SMIs that double as SCIs (when SCI_EN==0)
//
Pm1Sts = (B_QNC_PM1BLK_PM1S_WAKE | B_QNC_PM1BLK_PM1S_PCIEWSTS | B_QNC_PM1BLK_PM1S_RTC | B_QNC_PM1BLK_PM1S_GLOB | B_QNC_PM1BLK_PM1S_TO);
Gpe0Sts = B_QNC_GPE0BLK_GPE0S_ALL;
IoOr16((PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1S), Pm1Sts);
IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_GPE0S), Gpe0Sts);
}
//
// Clear all SMIs that are unaffected by SCI_EN
//
SmiSts = IoRead32((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS);
SmiSts |= B_QNC_GPE0BLK_SMIS_ALL;
IoWrite32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), SmiSts);
//
// Try to clear the EOS bit. ASSERT on an error
//
EosSet = QNCSmmSetAndCheckEos();
ASSERT (EosSet);
return EFI_SUCCESS;
}
BOOLEAN
QNCSmmSetAndCheckEos(
VOID
)
{
//
// Reset the QNC to generate subsequent SMIs
//
IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
return TRUE;
}
BOOLEAN
QNCSmmGetSciEn(
)
{
BOOLEAN SciEn;
UINT32 Pm1Cnt;
//
// Determine whether an ACPI OS is present (via the SCI_EN bit)
//
Pm1Cnt = IoRead32(PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
SciEn = (BOOLEAN)((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == B_QNC_PM1BLK_PM1C_SCIEN);
return SciEn;
}
//
// These may or may not need to change w/ the QNC version; they're highly IA-32 dependent, though.
//
BOOLEAN
ReadBitDesc (
CONST QNC_SMM_BIT_DESC *BitDesc
)
{
UINT64 Register;
UINT32 PciBus;
UINT32 PciDev;
UINT32 PciFun;
UINT32 PciReg;
BOOLEAN BitWasOne;
ASSERT (BitDesc != NULL );
ASSERT (!IS_BIT_DESC_NULL( *BitDesc ) );
Register = 0;
BitWasOne = FALSE;
switch (BitDesc->Reg.Type) {
case ACPI_ADDR_TYPE:
//
// Double check that we correctly read in the acpi base address
//
ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1) );
switch (BitDesc->SizeInBytes) {
case 0:
//
// Chances are that this field didn't get initialized.
// Check your assignments to bit descriptions.
//
ASSERT (FALSE );
break;
case 1:
Register = (UINT64) IoRead8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
break;
case 2:
Register = (UINT64) IoRead16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
break;
case 4:
Register = (UINT64) IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi);
break;
default:
//
// Unsupported or invalid register size
//
ASSERT (FALSE );
break;
};
if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
BitWasOne = TRUE;
} else {
BitWasOne = FALSE;
}
break;
case GPE_ADDR_TYPE:
//
// Double check that we correctly read in the gpe base address
//
ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1) );
switch (BitDesc->SizeInBytes) {
case 0:
//
// Chances are that this field didn't get initialized.
// Check your assignments to bit descriptions.
//
ASSERT (FALSE );
break;
case 1:
Register = (UINT64) IoRead8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
break;
case 2:
Register = (UINT64) IoRead16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
break;
case 4:
Register = (UINT64) IoRead32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe);
break;
default:
//
// Unsupported or invalid register size
//
ASSERT (FALSE );
break;
};
if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
BitWasOne = TRUE;
} else {
BitWasOne = FALSE;
}
break;
case MEMORY_MAPPED_IO_ADDRESS_TYPE:
//
// Read the register, and it with the bit to read
//
//
// This code does not support reads greater then 64 bits
//
ASSERT (BitDesc->SizeInBytes <= 8);
CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);
Register &= LShiftU64 (BIT0, BitDesc->Bit);
if (Register) {
BitWasOne = TRUE;
} else {
BitWasOne = FALSE;
}
break;
case PCI_ADDR_TYPE:
PciBus = BitDesc->Reg.Data.pci.Fields.Bus;
PciDev = BitDesc->Reg.Data.pci.Fields.Dev;
PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;
PciReg = BitDesc->Reg.Data.pci.Fields.Reg;
switch (BitDesc->SizeInBytes) {
case 0:
//
// Chances are that this field didn't get initialized.
// Check your assignments to bit descriptions.
ASSERT (FALSE );
break;
case 1:
Register = (UINT64) PciRead8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
break;
case 2:
Register = (UINT64) PciRead16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
break;
case 4:
Register = (UINT64) PciRead32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg));
break;
default:
//
// Unsupported or invalid register size
//
ASSERT (FALSE );
break;
};
if ((Register & LShiftU64 (BIT_ZERO, BitDesc->Bit)) != 0) {
BitWasOne = TRUE;
} else {
BitWasOne = FALSE;
}
break;
default:
//
// This address type is not yet implemented
//
ASSERT (FALSE );
break;
};
return BitWasOne;
}
VOID
WriteBitDesc (
CONST QNC_SMM_BIT_DESC *BitDesc,
CONST BOOLEAN ValueToWrite
)
{
UINT64 Register;
UINT64 AndVal;
UINT64 OrVal;
UINT32 PciBus;
UINT32 PciDev;
UINT32 PciFun;
UINT32 PciReg;
ASSERT (BitDesc != NULL);
ASSERT (!IS_BIT_DESC_NULL(*BitDesc));
AndVal = ~(BIT_ZERO << (BitDesc->Bit));
OrVal = ((UINT32)ValueToWrite) << (BitDesc->Bit);
switch (BitDesc->Reg.Type) {
case ACPI_ADDR_TYPE:
//
// Double check that we correctly read in the acpi base address
//
ASSERT ((PcdGet16 (PcdPm1blkIoBaseAddress) != 0x0) && ((PcdGet16 (PcdPm1blkIoBaseAddress) & 0x1) != 0x1));
switch (BitDesc->SizeInBytes) {
case 0:
//
// Chances are that this field didn't get initialized.
// Check your assignments to bit descriptions.
//
ASSERT (FALSE );
break;
case 1:
IoAndThenOr8 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT8)AndVal, (UINT8)OrVal);
break;
case 2:
IoAndThenOr16 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT16)AndVal, (UINT16)OrVal);
break;
case 4:
IoAndThenOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + BitDesc->Reg.Data.acpi, (UINT32)AndVal, (UINT32)OrVal);
break;
default:
//
// Unsupported or invalid register size
//
ASSERT (FALSE );
break;
};
break;
case GPE_ADDR_TYPE:
//
// Double check that we correctly read in the gpe base address
//
ASSERT (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) != 0x0) && (((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) & 0x1) != 0x1));
switch (BitDesc->SizeInBytes) {
case 0:
//
// Chances are that this field didn't get initialized.
// Check your assignments to bit descriptions.
//
ASSERT (FALSE );
break;
case 1:
IoAndThenOr8 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT8)AndVal, (UINT8)OrVal);
break;
case 2:
IoAndThenOr16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT16)AndVal, (UINT16)OrVal);
break;
case 4:
IoAndThenOr32 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + BitDesc->Reg.Data.gpe, (UINT32)AndVal, (UINT32)OrVal);
break;
default:
//
// Unsupported or invalid register size
//
ASSERT (FALSE );
break;
};
break;
case MEMORY_MAPPED_IO_ADDRESS_TYPE:
//
// Read the register, or it with the bit to set, then write it back.
//
//
// This code does not support writes greater then 64 bits
//
ASSERT (BitDesc->SizeInBytes <= 8);
CopyMem (&Register, BitDesc->Reg.Data.Mmio, BitDesc->SizeInBytes);
Register &= AndVal;
Register |= OrVal;
CopyMem (BitDesc->Reg.Data.Mmio, &Register, BitDesc->SizeInBytes);
break;
case PCI_ADDR_TYPE:
PciBus = BitDesc->Reg.Data.pci.Fields.Bus;
PciDev = BitDesc->Reg.Data.pci.Fields.Dev;
PciFun = BitDesc->Reg.Data.pci.Fields.Fnc;
PciReg = BitDesc->Reg.Data.pci.Fields.Reg;
switch (BitDesc->SizeInBytes) {
case 0:
//
// Chances are that this field didn't get initialized -- check your assignments
// to bit descriptions.
//
ASSERT (FALSE );
break;
case 1:
PciAndThenOr8 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT8) AndVal, (UINT8) OrVal);
break;
case 2:
PciAndThenOr16 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT16) AndVal, (UINT16) OrVal);
break;
case 4:
PciAndThenOr32 (PCI_LIB_ADDRESS (PciBus, PciDev, PciFun, PciReg), (UINT32) AndVal, (UINT32) OrVal);
break;
default:
//
// Unsupported or invalid register size
//
ASSERT (FALSE );
break;
};
break;
default:
//
// This address type is not yet implemented
//
ASSERT (FALSE );
break;
};
}

View File

@@ -0,0 +1,430 @@
/** @file
File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "QNCSmmHelpers.h"
typedef enum {
PERIODIC_TIMER = 0,
NUM_TIMERS
} SUPPORTED_TIMER;
typedef struct _TIMER_INTERVAL
{
UINT64 Interval;
UINT8 AssociatedTimer;
} TIMER_INTERVAL;
//
// Time constants, in 100 nano-second units
//
#define TIME_64s 640000000 /* 64 s */
#define TIME_32s 320000000 /* 32 s */
#define TIME_16s 160000000 /* 16 s */
#define TIME_8s 80000000 /* 8 s */
#define TIME_64ms 640000 /* 64 ms */
#define TIME_32ms 320000 /* 32 ms */
#define TIME_16ms 160000 /* 16 ms */
#define TIME_1_5ms 15000 /* 1.5 ms */
// PMCW (GPE+28h) [2:0] Periodic SMI Rate selection
// 000 1.5ms
// 001 16ms
// 010 32ms
// 011 64ms
// 100 8s
// 101 16s
// 110 32s
// 111 64s
typedef enum {
INDEX_TIME_1_5ms = 0,
INDEX_TIME_16ms,
INDEX_TIME_32ms,
INDEX_TIME_64ms,
INDEX_TIME_8s,
INDEX_TIME_16s,
INDEX_TIME_32s,
INDEX_TIME_64s,
INDEX_TIME_MAX
} TIMER_INTERVAL_INDEX;
TIMER_INTERVAL mSmmPeriodicTimerIntervals[INDEX_TIME_MAX] = {
{TIME_1_5ms, PERIODIC_TIMER},
{TIME_16ms, PERIODIC_TIMER},
{TIME_32ms, PERIODIC_TIMER},
{TIME_64ms, PERIODIC_TIMER},
{ TIME_8s, PERIODIC_TIMER },
{TIME_16s, PERIODIC_TIMER},
{TIME_32s, PERIODIC_TIMER},
{TIME_64s, PERIODIC_TIMER}
};
typedef struct _TIMER_INFO {
UINTN NumChildren; // number of children using this timer
UINT64 MinReqInterval; // minimum interval required by children
UINTN CurrentSetting; // interval this timer is set at right now (index into interval table)
} TIMER_INFO;
TIMER_INFO mTimers[NUM_TIMERS];
QNC_SMM_SOURCE_DESC mTIMER_SOURCE_DESCS[NUM_TIMERS] = {
{
QNC_SMM_NO_FLAGS,
{
{{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SWT},
NULL_BIT_DESC_INITIALIZER
},
{
{{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SWT}
}
}
};
VOID
QNCSmmPeriodicTimerProgramTimers(
VOID
);
TIMER_INTERVAL *
ContextToTimerInterval (
IN QNC_SMM_CONTEXT *RegisterContext
)
{
UINTN loopvar;
//
// Determine which timer this child is using
//
for (loopvar = 0; loopvar < INDEX_TIME_MAX; loopvar++) {
if (((RegisterContext->PeriodicTimer.SmiTickInterval == 0) && (RegisterContext->PeriodicTimer.Period >= mSmmPeriodicTimerIntervals[loopvar].Interval)) ||
(RegisterContext->PeriodicTimer.SmiTickInterval == mSmmPeriodicTimerIntervals[loopvar].Interval)
) {
return &mSmmPeriodicTimerIntervals[loopvar];
}
}
//
// If this assertion fires, then either:
// (1) the context contains an invalid interval
// (2) the timer interval table is corrupt
//
// ASSERT (FALSE);
return NULL;
}
EFI_STATUS
MapPeriodicTimerToSrcDesc (
IN QNC_SMM_CONTEXT *RegisterContext,
OUT QNC_SMM_SOURCE_DESC *SrcDesc
)
{
TIMER_INTERVAL *TimerInterval;
//
// Figure out which timer the child is requesting and
// send back the source description
//
TimerInterval = ContextToTimerInterval (RegisterContext);
if (TimerInterval == NULL) {
return EFI_INVALID_PARAMETER;
}
CopyMem (SrcDesc, &mTIMER_SOURCE_DESCS[TimerInterval->AssociatedTimer], sizeof (QNC_SMM_SOURCE_DESC));;
//
// Program the value of the interval into hardware
//
QNCSmmPeriodicTimerProgramTimers ();
return EFI_SUCCESS;
}
VOID
PeriodicTimerGetContext (
IN DATABASE_RECORD *Record,
OUT QNC_SMM_CONTEXT *HwContext
)
{
TIMER_INTERVAL *TimerInterval;
ASSERT (Record->ProtocolType == PeriodicTimerType);
TimerInterval = ContextToTimerInterval (&Record->ChildContext);
if (TimerInterval != NULL) {
//
// Ignore the hardware context. It's not required for this protocol.
// Instead, just increment the child's context.
// Update the elapsed time w/ the data from our tables
//
Record->CommBuffer.PeriodicTimer.ElapsedTime += TimerInterval->Interval;
*HwContext = Record->ChildContext;
}
}
BOOLEAN
PeriodicTimerCmpContext (
IN QNC_SMM_CONTEXT *HwContext,
IN QNC_SMM_CONTEXT *ChildContext
)
{
DATABASE_RECORD *Record;
Record = DATABASE_RECORD_FROM_CONTEXT (ChildContext);
if (Record->CommBuffer.PeriodicTimer.ElapsedTime >= ChildContext->PeriodicTimer.Period) {
//
// This child should be dispatched
// The timer will be restarted on the "ClearSource" call.
//
return TRUE;
} else {
return FALSE;
}
}
VOID
PeriodicTimerGetBuffer (
IN DATABASE_RECORD * Record
)
{
//
// CommBuffer has been updated by PeriodicTimerGetContext, so return directly
//
return;
}
VOID
QNCSmmPeriodicTimerProgramTimers (
VOID
)
{
UINT32 GpePmcwValue;
SUPPORTED_TIMER Timer;
DATABASE_RECORD *RecordInDb;
LIST_ENTRY *LinkInDb;
TIMER_INTERVAL *TimerInterval;
//
// Find the minimum required interval for each timer
//
for (Timer = (SUPPORTED_TIMER)0; Timer < NUM_TIMERS; Timer++) {
mTimers[Timer].MinReqInterval = ~(UINT64)0x0;
mTimers[Timer].NumChildren = 0;
}
LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
if (RecordInDb->ProtocolType == PeriodicTimerType) {
//
// This child is registerd with the PeriodicTimer protocol
//
TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext);
if(TimerInterval != NULL) {
Timer = (SUPPORTED_TIMER)((TIMER_INTERVAL *) (TimerInterval))->AssociatedTimer;
ASSERT (Timer >= 0 && Timer < NUM_TIMERS);
if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) {
mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval;
}
mTimers[Timer].NumChildren++;
}
}
LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
}
//
// Program the hardware
//
GpePmcwValue = 0;
if (mTimers[PERIODIC_TIMER].NumChildren > 0) {
switch (mTimers[PERIODIC_TIMER].MinReqInterval) {
case TIME_64s:
GpePmcwValue = INDEX_TIME_64s;
mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s;
break;
case TIME_32s:
GpePmcwValue = INDEX_TIME_32s;
mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s;
break;
case TIME_16s:
GpePmcwValue = INDEX_TIME_16s;
mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s;
break;
case TIME_8s:
GpePmcwValue = INDEX_TIME_8s;
mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s;
break;
case TIME_64ms:
GpePmcwValue = INDEX_TIME_64ms;
mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64ms;
break;
case TIME_32ms:
GpePmcwValue = INDEX_TIME_32ms;
mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32ms;
break;
case TIME_16ms:
GpePmcwValue = INDEX_TIME_16ms;
mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16ms;
break;
case TIME_1_5ms:
GpePmcwValue = INDEX_TIME_1_5ms;
mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_1_5ms;
break;
default:
ASSERT (FALSE);
break;
};
GpePmcwValue |= B_QNC_GPE0BLK_PMCW_PSE;
IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMCW), GpePmcwValue);
//
// Restart the timer here, just need to clear the SMI
//
QNCSmmClearSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);
} else {
QNCSmmDisableSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);
}
}
EFI_STATUS
QNCSmmPeriodicTimerDispatchGetNextShorterInterval (
IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,
IN OUT UINT64 **SmiTickInterval
)
/*++
Routine Description:
This services returns the next SMI tick period that is supported by the chipset.
The order returned is from longest to shortest interval period.
Arguments:
This - Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance.
SmiTickInterval - Pointer to pointer of the next shorter SMI interval period that is supported by the child.
Returns:
EFI_SUCCESS - The service returned successfully.
EFI_INVALID_PARAMETER - The parameter SmiTickInterval is invalid.
--*/
{
TIMER_INTERVAL *IntervalPointer;
ASSERT (SmiTickInterval != NULL);
IntervalPointer = (TIMER_INTERVAL*)*SmiTickInterval;
if (IntervalPointer == NULL) {
//
// The first time child requesting an interval
//
IntervalPointer = &mSmmPeriodicTimerIntervals[0];
} else if (IntervalPointer == &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1]) {
//
// At end of the list
//
IntervalPointer = NULL;
} else {
if ((IntervalPointer >= &mSmmPeriodicTimerIntervals[0]) &&
(IntervalPointer < &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1])) {
//
// Get the next interval in the list
//
IntervalPointer++;
} else {
//
// Input is out of range
//
return EFI_INVALID_PARAMETER;
}
}
if (IntervalPointer != NULL) {
*SmiTickInterval = &IntervalPointer->Interval;
} else {
*SmiTickInterval = NULL;
}
return EFI_SUCCESS;
}
VOID
QNCSmmPeriodicTimerClearSource (
IN QNC_SMM_SOURCE_DESC *SrcDesc
)
/*++
Routine Description:
This function is responsible for calculating and enabling any timers that are required
to dispatch messages to children. The SrcDesc argument isn't acutally used.
Arguments:
SrcDesc - Pointer to the QNC_SMM_SOURCE_DESC instance.
Returns:
None.
--*/
{
DATABASE_RECORD *RecordInDb;
LIST_ENTRY *LinkInDb;
QNCSmmPeriodicTimerProgramTimers ();
//
// Reset Elapsed time
//
LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
if (RecordInDb->ProtocolType == PeriodicTimerType) {
//
// This child is registerd with the PeriodicTimer protocol and Callback
// has been invoked, so reset the ElapsedTime to 0
//
if (RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime >= RecordInDb->ChildContext.PeriodicTimer.Period) {
RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime = 0;
}
}
LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
}
}

View File

@@ -0,0 +1,217 @@
/** @file
File to contain all the hardware specific stuff for the Smm QNCn dispatch protocol.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "QNCSmmHelpers.h"
QNC_SMM_SOURCE_DESC QNCN_SOURCE_DESCS[NUM_ICHN_TYPES] = {
// QNCnMch (0)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnPme (1)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnRtcAlarm (2)
{
QNC_SMM_NO_FLAGS,
{
{{ACPI_ADDR_TYPE, {R_QNC_PM1BLK_PM1E}}, S_QNC_PM1BLK_PM1E, N_QNC_PM1BLK_PM1E_RTC},
NULL_BIT_DESC_INITIALIZER
},
{
{{ACPI_ADDR_TYPE, {R_QNC_PM1BLK_PM1S}}, S_QNC_PM1BLK_PM1S, N_QNC_PM1BLK_PM1S_RTC}
}
},
// QNCnRingIndicate (3)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnAc97Wake (4)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnSerialIrq (5)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnY2KRollover (6)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnTcoTimeout (7)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnOsTco (8)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnNmi (9)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnIntruderDetect (10)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnBiosWp (11)
{
QNC_SMM_CLEAR_WITH_ZERO,
{
{
{
PCI_ADDR_TYPE,
{
(
(PCI_BUS_NUMBER_QNC << 24) |
(PCI_DEVICE_NUMBER_QNC_LPC << 16) |
(PCI_FUNCTION_NUMBER_QNC_LPC << 8) |
R_QNC_LPC_BIOS_CNTL
)
}
},
S_QNC_LPC_BIOS_CNTL,
N_QNC_LPC_BIOS_CNTL_BLE
},
NULL_BIT_DESC_INITIALIZER
},
{
{
{
PCI_ADDR_TYPE,
{
(
(PCI_BUS_NUMBER_QNC << 24) |
(PCI_DEVICE_NUMBER_QNC_LPC << 16) |
(PCI_FUNCTION_NUMBER_QNC_LPC << 8) |
R_QNC_LPC_BIOS_CNTL
)
}
},
S_QNC_LPC_BIOS_CNTL,
N_QNC_LPC_BIOS_CNTL_BIOSWE
}
}
},
// QNCnMcSmi (12)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnPmeB0 (13)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnThrmSts (14)
{
QNC_SMM_SCI_EN_DEPENDENT,
{
{{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_GPE0E}}, S_QNC_GPE0BLK_GPE0E, N_QNC_GPE0BLK_GPE0E_THRM},
NULL_BIT_DESC_INITIALIZER
},
{
{{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_GPE0S}}, S_QNC_GPE0BLK_GPE0S, N_QNC_GPE0BLK_GPE0S_THRM}
}
},
// QNCnSmBus (15)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnIntelUsb2 (16)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnMonSmi7 (17)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnMonSmi6 (18)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnMonSmi5 (19)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnMonSmi4 (20)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap13 (21)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap12 (22)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap11 (23)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap10 (24)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap9 (25)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap8 (26)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap7 (27)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap6 (28)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap5 (29)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap3 (30)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap2 (31)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap1 (32)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnDevTrap0 (33)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnIoTrap3 (34)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnIoTrap2 (35)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnIoTrap1 (36)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnIoTrap0 (37)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnPciExpress (38)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnMonitor (39)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnSpi (40)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnQRT (41)
NULL_SOURCE_DESC_INITIALIZER,
// QNCnGpioUnlock (42)
NULL_SOURCE_DESC_INITIALIZER
};
VOID
QNCSmmQNCnClearSource(
QNC_SMM_SOURCE_DESC *SrcDesc
)
{
QNCSmmClearSource (SrcDesc);
}

View File

@@ -0,0 +1,96 @@
/** @file
File to contain all the hardware specific stuff for the Smm Sw dispatch protocol.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "QNCSmmHelpers.h"
EFI_SMM_CPU_PROTOCOL *mSmmCpu = NULL;
CONST QNC_SMM_SOURCE_DESC SW_SOURCE_DESC = {
QNC_SMM_NO_FLAGS,
{
{
{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_APM
},
NULL_BIT_DESC_INITIALIZER
},
{
{
{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_APM
}
}
};
VOID
SwGetContext(
IN DATABASE_RECORD *Record,
OUT QNC_SMM_CONTEXT *Context
)
{
Context->Sw.SwSmiInputValue = IoRead8 (R_APM_CNT);
}
BOOLEAN
SwCmpContext (
IN QNC_SMM_CONTEXT *Context1,
IN QNC_SMM_CONTEXT *Context2
)
{
return (BOOLEAN)( Context1->Sw.SwSmiInputValue == Context2->Sw.SwSmiInputValue );
}
VOID
SwGetBuffer (
IN DATABASE_RECORD * Record
)
{
EFI_STATUS Status;
UINTN Index;
UINTN CpuIndex;
EFI_SMM_SAVE_STATE_IO_INFO IoState;
//
// Locate SMM CPU protocol to retrieve the CPU save state
//
if (mSmmCpu == NULL) {
Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);
ASSERT_EFI_ERROR (Status);
}
//
// Find the CPU which generated the software SMI
//
CpuIndex = 0;
for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
Status = mSmmCpu->ReadSaveState (
mSmmCpu,
sizeof (EFI_SMM_SAVE_STATE_IO_INFO),
EFI_SMM_SAVE_STATE_REGISTER_IO,
Index,
&IoState
);
if (!EFI_ERROR (Status) && (IoState.IoPort == R_APM_CNT)) {
CpuIndex = Index;
break;
}
}
Record->CommBuffer.Sw.SwSmiCpuIndex = CpuIndex;
}

View File

@@ -0,0 +1,153 @@
/** @file
File to contain all the hardware specific stuff for the Smm Sx dispatch protocol.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "QNCSmmHelpers.h"
CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC = {
QNC_SMM_NO_FLAGS,
{
{
{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SLP
},
NULL_BIT_DESC_INITIALIZER
},
{
{
{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SLP
}
}
};
VOID
SxGetContext(
IN DATABASE_RECORD *Record,
OUT QNC_SMM_CONTEXT *Context
)
{
UINT32 Pm1Cnt;
Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
//
// By design, the context phase will always be ENTRY
//
Context->Sx.Phase = SxEntry;
//
// Map the PM1_CNT register's SLP_TYP bits to the context type
//
switch (Pm1Cnt & B_QNC_PM1BLK_PM1C_SLPTP) {
case V_S0:
Context->Sx.Type = SxS0;
break;
case V_S3:
Context->Sx.Type = SxS3;
break;
case V_S4:
Context->Sx.Type = SxS4;
break;
case V_S5:
Context->Sx.Type = SxS5;
break;
default:
ASSERT (FALSE);
break;
};
}
BOOLEAN
SxCmpContext (
IN QNC_SMM_CONTEXT *Context1,
IN QNC_SMM_CONTEXT *Context2
)
{
return (BOOLEAN)(Context1->Sx.Type == Context2->Sx.Type);
}
VOID
QNCSmmSxGoToSleep(
VOID
)
/*++
Routine Description:
When we get an SMI that indicates that we are transitioning to a sleep state,
we need to actually transition to that state. We do this by disabling the
"SMI on sleep enable" feature, which generates an SMI when the operating system
tries to put the system to sleep, and then physically putting the system to sleep.
Returns:
None.
--*/
{
UINT32 Pm1Cnt;
//
// Flush cache into memory before we go to sleep. It is necessary for S3 sleep
// because we may update memory in SMM Sx sleep handlers -- the updates are in cache now
//
AsmWbinvd();
//
// Disable SMIs
//
QNCSmmClearSource (&SX_SOURCE_DESC );
QNCSmmDisableSource (&SX_SOURCE_DESC);
//
// Clear Sleep Type Enable
//
IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIE, (UINT16)(~B_QNC_GPE0BLK_SMIE_SLP));
// clear sleep SMI status
IoAnd16 ((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_SMIS, (UINT16)(S_QNC_GPE0BLK_SMIS));
//
// Now that SMIs are disabled, write to the SLP_EN bit again to trigger the sleep
//
Pm1Cnt = IoOr32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, B_QNC_PM1BLK_PM1C_SLPEN);
//
// The system just went to sleep. If the sleep state was S1, then code execution will resume
// here when the system wakes up.
//
Pm1Cnt = IoRead32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C);
if ((Pm1Cnt & B_QNC_PM1BLK_PM1C_SCIEN) == 0) {
//
// An ACPI OS isn't present, clear the sleep information
//
Pm1Cnt &= ~B_QNC_PM1BLK_PM1C_SLPTP;
Pm1Cnt |= V_S0;
IoWrite32 (PcdGet16 (PcdPm1blkIoBaseAddress) + R_QNC_PM1BLK_PM1C, Pm1Cnt);
}
QNCSmmClearSource (&SX_SOURCE_DESC);
QNCSmmEnableSource (&SX_SOURCE_DESC);
}

View File

@@ -0,0 +1,871 @@
/** @file
Prototypes and defines for the QNC SMM Dispatcher.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef QNC_SMM_H
#define QNC_SMM_H
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "QNCSmmRegisters.h"
extern EFI_HANDLE mQNCSmmDispatcherImageHandle;
//
// /////////////////////////////////////////////////////////////////////////////
// SUPPORTED PROTOCOLS
//
//
// Define an enumeration for all the supported protocols
//
typedef enum {
// UsbType, DELETE:on QuarkNcSocId, there is no usb smi supported
SxType,
SwType,
GpiType,
QNCnType,
PowerButtonType,
PeriodicTimerType,
NUM_PROTOCOLS
} QNC_SMM_PROTOCOL_TYPE;
//
// /////////////////////////////////////////////////////////////////////////////
// SPECIFYING A REGISTER
// We want a general way of referring to addresses. For this case, we'll only
// need addresses in the ACPI table (and the TCO entries within the ACPI table).
// However, it's interesting to consider what it would take to support other types
// of addresses. To address Will's concern, I think it prudent to accommodate it
// early on in the design.
//
// Addresses we need to consider:
//
// Type: Required:
// I/O Yes
// ACPI (special case of I/O) Only if we want to
// TCO (special case of ACPI) Only if we want to
// Memory (or Memory Mapped I/O) Only if we want to
// PCI Yes, for BiosWp
//
typedef enum {
//
// IO_ADDR_TYPE, // unimplemented
//
ACPI_ADDR_TYPE,
GPE_ADDR_TYPE,
//
// MEMORY_ADDR_TYPE, // unimplemented
//
MEMORY_MAPPED_IO_ADDRESS_TYPE,
PCI_ADDR_TYPE,
NUM_ADDR_TYPES, // count of items in this enum
QNC_SMM_ADDR_TYPE_NULL = -1 // sentinel to indicate NULL or to signal end of arrays
} ADDR_TYPE;
//
// Assumption: 32-bits -- enum's evaluate to integer
// Assumption: This code will only run on IA-32. Justification: IA-64 doesn't have SMIs.
// We don't have to worry about 64-bit addresses.
// Typedef the size of addresses in case the numbers I'm using are wrong or in case
// this changes. This is a good idea because PCI_ADDR will change, for example, when
// we add support for PciExpress.
//
typedef UINT16 IO_ADDR;
typedef IO_ADDR ACPI_ADDR; // can omit
typedef IO_ADDR GPE_ADDR; // can omit
typedef IO_ADDR TCO_ADDR; // can omit
typedef VOID *MEM_ADDR;
typedef MEM_ADDR MEMORY_MAPPED_IO_ADDRESS;
typedef union {
UINT32 Raw;
struct {
UINT8 Reg;
UINT8 Fnc;
UINT8 Dev;
UINT8 Bus;
} Fields;
} PCI_ADDR;
typedef struct {
ADDR_TYPE Type;
union {
//
// used to initialize during declaration/definition
//
UINTN raw;
//
// used to access useful data
//
IO_ADDR io;
ACPI_ADDR acpi;
GPE_ADDR gpe;
TCO_ADDR tco;
MEM_ADDR mem;
MEMORY_MAPPED_IO_ADDRESS Mmio;
PCI_ADDR pci;
} Data;
} QNC_SMM_ADDRESS;
//
// Assumption: total size is 64 bits (32 for type and 32 for data) or 8 bytes
//
#define EFI_PCI_ADDRESS_PORT 0xcf8
#define EFI_PCI_DATA_PORT 0xcfc
//
// /////////////////////////////////////////////////////////////////////////////
// SPECIFYING BITS WITHIN A REGISTER
// Here's a struct that helps us specify a source or enable bit.
//
typedef struct {
QNC_SMM_ADDRESS Reg;
UINT8 SizeInBytes; // of the register
UINT8 Bit;
} QNC_SMM_BIT_DESC;
//
// Sometimes, we'll have bit descriptions that are unused. It'd be great to have a
// way to easily identify them:
//
#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type == QNC_SMM_ADDR_TYPE_NULL) // "returns" true when BitDesc is NULL
#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = QNC_SMM_ADDR_TYPE_NULL) // will "return" an integer w/ value of 0
#define NULL_BIT_DESC_INITIALIZER \
{ \
{ \
QNC_SMM_ADDR_TYPE_NULL, \
{ \
0 \
} \
}, \
0, 0 \
}
//
// I'd like a type to specify the callback's Sts & En bits because they'll
// be commonly used together:
//
#define NUM_EN_BITS 2
#define NUM_STS_BITS 1
//
// Flags
//
typedef UINT8 QNC_SMM_SOURCE_FLAGS;
//
// Flags required today
//
#define QNC_SMM_NO_FLAGS 0
#define QNC_SMM_SCI_EN_DEPENDENT (BIT0)
#define QNC_SMM_CLEAR_WITH_ZERO (BIT6)
//
// Flags that might be required tomorrow
// #define QNC_SMM_CLEAR_WITH_ONE 2 // may need to support bits that clear by writing 0
// #define QNC_SMM_MULTIBIT_FIELD 3 // may need to support status/enable fields 2 bits wide
//
typedef struct {
QNC_SMM_SOURCE_FLAGS Flags;
QNC_SMM_BIT_DESC En[NUM_EN_BITS];
QNC_SMM_BIT_DESC Sts[NUM_STS_BITS];
} QNC_SMM_SOURCE_DESC;
//
// 31 bytes, I think
//
#define NULL_SOURCE_DESC_INITIALIZER \
{ \
QNC_SMM_NO_FLAGS, \
{ \
NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \
}, \
{ \
NULL_BIT_DESC_INITIALIZER \
} \
}
//
// /////////////////////////////////////////////////////////////////////////////
// CHILD CONTEXTS
// To keep consistent w/ the architecture, we'll need to provide the context
// to the child when we call its callback function. After talking with Will,
// we agreed that we'll need functions to "dig" the context out of the hardware
// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those
// contexts to prevent unnecessary dispatches. I'd like a general type for these
// "GetContext" functions, so I'll need a union of all the protocol contexts for
// our internal use:
//
typedef union {
//
// (in no particular order)
//
EFI_SMM_ICHN_REGISTER_CONTEXT QNCn;
EFI_SMM_SX_REGISTER_CONTEXT Sx;
EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer;
EFI_SMM_SW_REGISTER_CONTEXT Sw;
EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton;
// EFI_SMM_USB_REGISTER_CONTEXT Usb; DELETE:on QuarkNcSocId, there is no usb smi supported
EFI_SMM_GPI_REGISTER_CONTEXT Gpi;
} QNC_SMM_CONTEXT;
typedef union {
//
// (in no particular order)
//
EFI_SMM_SW_CONTEXT Sw;
EFI_SMM_PERIODIC_TIMER_CONTEXT PeriodicTimer;
} QNC_SMM_BUFFER;
//
// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes
//
typedef struct _DATABASE_RECORD DATABASE_RECORD;
typedef
VOID
(EFIAPI *GET_CONTEXT) (
IN DATABASE_RECORD * Record,
OUT QNC_SMM_CONTEXT * Context
);
//
// Assumption: the GET_CONTEXT function will be as small and simple as possible.
// Assumption: We don't need to pass in an enumeration for the protocol because each
// GET_CONTEXT function is written for only one protocol.
// We also need a function to compare contexts to see if the child should be dispatched
//
typedef
BOOLEAN
(EFIAPI *CMP_CONTEXT) (
IN QNC_SMM_CONTEXT * Context1,
IN QNC_SMM_CONTEXT * Context2
);
/*
Returns: True when contexts are equivalent; False otherwise
*/
//
// This function is used to get the content of CommBuffer that will be passed
// to Callback function
//
typedef
VOID
(EFIAPI *GET_BUFFER) (
IN DATABASE_RECORD * Record
);
//
// Finally, every protocol will require a "Get Context", "Compare Context"
// and "Get CommBuffer" call, so we may as well wrap that up in a table, too.
//
typedef struct {
GET_CONTEXT GetContext;
CMP_CONTEXT CmpContext;
GET_BUFFER GetBuffer;
} CONTEXT_FUNCTIONS;
extern CONTEXT_FUNCTIONS ContextFunctions[NUM_PROTOCOLS];
//
// /////////////////////////////////////////////////////////////////////////////
// MAPPING CONTEXT TO BIT DESCRIPTIONS
// I'd like to have a general approach to mapping contexts to bit descriptions.
// Sometimes, we'll find that we can use table lookups or CONSTant assignments;
// other times, we'll find that we'll need to use a function to perform the mapping.
// If we define a macro to mask that process, we'll never have to change the code.
// I don't know if this is desirable or not -- if it isn't, then we can get rid
// of the macros and just use function calls or variable assignments. Doesn't matter
// to me.
// Mapping complex contexts requires a function
//
// DELETE:on QuarkNcSocId, there is no usb smi supported
//EFI_STATUS
//EFIAPI
//MapUsbToSrcDesc (
// IN QNC_SMM_CONTEXT *RegisterContext,
// OUT QNC_SMM_SOURCE_DESC *SrcDesc
// )
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
RegisterContext - GC_TODO: add argument description
SrcDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
EFI_STATUS
MapPeriodicTimerToSrcDesc (
IN QNC_SMM_CONTEXT *RegisterContext,
OUT QNC_SMM_SOURCE_DESC *SrcDesc
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
RegisterContext - GC_TODO: add argument description
SrcDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
//
// Mapping simple contexts can be done by assignment or lookup table
//
extern CONST QNC_SMM_SOURCE_DESC SW_SOURCE_DESC;
extern CONST QNC_SMM_SOURCE_DESC SX_SOURCE_DESC;
//
// With the changes we've made to the protocols, we can now use table
// lookups for the following protocols:
//
extern CONST QNC_SMM_SOURCE_DESC GPI_SOURCE_DESC;
extern QNC_SMM_SOURCE_DESC QNCN_SOURCE_DESCS[NUM_ICHN_TYPES];
//
// For QNCx, APMC is UINT8 port, so the MAX SWI Value is 0xFF.
//
#define MAXIMUM_SWI_VALUE 0xFF
//
// Open: Need to make sure this kind of type cast will actually work.
// May need an intermediate form w/ two VOID* arguments. I'll figure
// that out when I start compiling.
///////////////////////////////////////////////////////////////////////////////
//
typedef
VOID
(EFIAPI *QNC_SMM_CLEAR_SOURCE) (
QNC_SMM_SOURCE_DESC * SrcDesc
);
//
// /////////////////////////////////////////////////////////////////////////////
// "DATABASE" RECORD
// Linked list data structures
//
#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C')
struct _DATABASE_RECORD {
UINT32 Signature;
LIST_ENTRY Link;
//
// Status and Enable bit description
//
QNC_SMM_SOURCE_DESC SrcDesc;
//
// Callback function
//
EFI_SMM_HANDLER_ENTRY_POINT2 Callback;
QNC_SMM_CONTEXT ChildContext;
QNC_SMM_BUFFER CommBuffer;
UINTN BufferSize;
//
// Special handling hooks -- init them to NULL if unused/unneeded
//
QNC_SMM_CLEAR_SOURCE ClearSource; // needed for SWSMI timer
// Functions required to make callback code general
//
CONTEXT_FUNCTIONS ContextFunctions;
//
// The protocol that this record dispatches
//
QNC_SMM_PROTOCOL_TYPE ProtocolType;
};
#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE)
#define DATABASE_RECORD_FROM_CONTEXT(_record) CR (_record, DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE)
//
// /////////////////////////////////////////////////////////////////////////////
// HOOKING INTO THE ARCHITECTURE
//
typedef
EFI_STATUS
(EFIAPI *QNC_SMM_GENERIC_REGISTER) (
IN VOID **This,
IN VOID *DispatchFunction,
IN VOID *RegisterContext,
OUT EFI_HANDLE * DispatchHandle
);
typedef
EFI_STATUS
(EFIAPI *QNC_SMM_GENERIC_UNREGISTER) (
IN VOID **This,
IN EFI_HANDLE DispatchHandle
);
//
// Define a memory "stamp" equivalent in size and function to most of the protocols
//
typedef struct {
QNC_SMM_GENERIC_REGISTER Register;
QNC_SMM_GENERIC_UNREGISTER Unregister;
UINTN Extra1;
UINTN Extra2; // may not need this one
} QNC_SMM_GENERIC_PROTOCOL;
EFI_STATUS
QNCSmmCoreRegister (
IN QNC_SMM_GENERIC_PROTOCOL *This,
IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
IN QNC_SMM_CONTEXT *RegisterContext,
OUT EFI_HANDLE *DispatchHandle
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
This - GC_TODO: add argument description
DispatchFunction - GC_TODO: add argument description
RegisterContext - GC_TODO: add argument description
DispatchHandle - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
EFI_STATUS
QNCSmmCoreUnRegister (
IN QNC_SMM_GENERIC_PROTOCOL *This,
IN EFI_HANDLE DispatchHandle
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
This - GC_TODO: add argument description
DispatchHandle - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
typedef union {
QNC_SMM_GENERIC_PROTOCOL Generic;
// EFI_SMM_USB_DISPATCH2_PROTOCOL Usb; DELETE:on QuarkNcSocId, there is no usb smi supported
EFI_SMM_SX_DISPATCH2_PROTOCOL Sx;
EFI_SMM_SW_DISPATCH2_PROTOCOL Sw;
EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi;
EFI_SMM_ICHN_DISPATCH2_PROTOCOL QNCn;
EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton;
EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer;
} QNC_SMM_PROTOCOL;
//
// Define a structure to help us identify the generic protocol
//
#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T')
typedef struct {
UINTN Signature;
QNC_SMM_PROTOCOL_TYPE Type;
EFI_GUID *Guid;
QNC_SMM_PROTOCOL Protocols;
} QNC_SMM_QUALIFIED_PROTOCOL;
#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \
CR (_generic, \
QNC_SMM_QUALIFIED_PROTOCOL, \
Protocols, \
PROTOCOL_SIGNATURE \
)
//
// Create private data for the protocols that we'll publish
//
typedef struct {
LIST_ENTRY CallbackDataBase;
EFI_HANDLE SmiHandle;
EFI_HANDLE InstallMultProtHandle;
QNC_SMM_QUALIFIED_PROTOCOL Protocols[NUM_PROTOCOLS];
} PRIVATE_DATA;
extern PRIVATE_DATA mPrivateData;
//
// /////////////////////////////////////////////////////////////////////////////
//
VOID
EFIAPI
SwGetContext (
IN DATABASE_RECORD *Record,
OUT QNC_SMM_CONTEXT *Context
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Record - GC_TODO: add argument description
Context - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
BOOLEAN
EFIAPI
SwCmpContext (
IN QNC_SMM_CONTEXT *Context1,
IN QNC_SMM_CONTEXT *Context2
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Context1 - GC_TODO: add argument description
Context2 - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
VOID
SwGetBuffer (
IN DATABASE_RECORD * Record
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Record - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
VOID
EFIAPI
SxGetContext (
IN DATABASE_RECORD *Record,
OUT QNC_SMM_CONTEXT *Context
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Record - GC_TODO: add argument description
Context - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
BOOLEAN
EFIAPI
SxCmpContext (
IN QNC_SMM_CONTEXT *Context1,
IN QNC_SMM_CONTEXT *Context2
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Context1 - GC_TODO: add argument description
Context2 - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
VOID
EFIAPI
PeriodicTimerGetContext (
IN DATABASE_RECORD *Record,
OUT QNC_SMM_CONTEXT *Context
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Record - GC_TODO: add argument description
Context - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
BOOLEAN
EFIAPI
PeriodicTimerCmpContext (
IN QNC_SMM_CONTEXT *Context1,
IN QNC_SMM_CONTEXT *Context2
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Context1 - GC_TODO: add argument description
Context2 - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
VOID
PeriodicTimerGetBuffer (
IN DATABASE_RECORD * Record
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Record - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
VOID
EFIAPI
PowerButtonGetContext (
IN DATABASE_RECORD *Record,
OUT QNC_SMM_CONTEXT *Context
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Record - GC_TODO: add argument description
Context - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
BOOLEAN
EFIAPI
PowerButtonCmpContext (
IN QNC_SMM_CONTEXT *Context1,
IN QNC_SMM_CONTEXT *Context2
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Context1 - GC_TODO: add argument description
Context2 - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
//
// /////////////////////////////////////////////////////////////////////////////
//
VOID
EFIAPI
QNCSmmPeriodicTimerClearSource (
QNC_SMM_SOURCE_DESC *SrcDesc
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
SrcDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
EFI_STATUS
QNCSmmPeriodicTimerDispatchGetNextShorterInterval (
IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,
IN OUT UINT64 **SmiTickInterval
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
This - GC_TODO: add argument description
SmiTickInterval - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
VOID
QNCSmmSxGoToSleep (
VOID
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
None
Returns:
GC_TODO: add return values
--*/
;
VOID
EFIAPI
QNCSmmQNCnClearSource (
QNC_SMM_SOURCE_DESC *SrcDesc
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
SrcDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
#endif

View File

@@ -0,0 +1,800 @@
/** @file
This driver is responsible for the registration of child drivers
and the abstraction of the QNC SMI sources.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "QNCSmm.h"
#include "QNCSmmHelpers.h"
//
// /////////////////////////////////////////////////////////////////////////////
// MODULE / GLOBAL DATA
//
// Module variables used by the both the main dispatcher and the source dispatchers
// Declared in QNCSmmSources.h
//
UINT32 mPciData;
UINT32 mPciAddress;
PRIVATE_DATA mPrivateData = { // for the structure
{
NULL
}, // CallbackDataBase linked list head
NULL, // Handler returned whan calling SmiHandlerRegister
NULL, // EFI handle returned when calling InstallMultipleProtocolInterfaces
{ // protocol arrays
// elements within the array
//
{
PROTOCOL_SIGNATURE,
SxType,
&gEfiSmmSxDispatch2ProtocolGuid,
{
{
(QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
(QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister
}
}
},
{
PROTOCOL_SIGNATURE,
SwType,
&gEfiSmmSwDispatch2ProtocolGuid,
{
{
(QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
(QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,
(UINTN) MAXIMUM_SWI_VALUE
}
}
},
{
PROTOCOL_SIGNATURE,
GpiType,
&gEfiSmmGpiDispatch2ProtocolGuid,
{
{
(QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
(QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,
(UINTN) 1
}
}
},
{
PROTOCOL_SIGNATURE,
QNCnType,
&gEfiSmmIchnDispatch2ProtocolGuid,
{
{
(QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
(QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister
}
}
},
{
PROTOCOL_SIGNATURE,
PowerButtonType,
&gEfiSmmPowerButtonDispatch2ProtocolGuid,
{
{
(QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
(QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister
}
}
},
{
PROTOCOL_SIGNATURE,
PeriodicTimerType,
&gEfiSmmPeriodicTimerDispatch2ProtocolGuid,
{
{
(QNC_SMM_GENERIC_REGISTER) QNCSmmCoreRegister,
(QNC_SMM_GENERIC_UNREGISTER) QNCSmmCoreUnRegister,
(UINTN) QNCSmmPeriodicTimerDispatchGetNextShorterInterval
}
}
},
}
};
CONTEXT_FUNCTIONS mContextFunctions[NUM_PROTOCOLS] = {
{
SxGetContext,
SxCmpContext,
NULL
},
{
SwGetContext,
SwCmpContext,
SwGetBuffer
},
{
NULL,
NULL,
NULL
},
{
NULL,
NULL,
NULL
},
{
NULL,
NULL,
NULL
},
{
PeriodicTimerGetContext,
PeriodicTimerCmpContext,
PeriodicTimerGetBuffer,
},
};
//
// /////////////////////////////////////////////////////////////////////////////
// PROTOTYPES
//
// Functions use only in this file
//
EFI_STATUS
QNCSmmCoreDispatcher (
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *Context, OPTIONAL
IN OUT VOID *CommBuffer, OPTIONAL
IN OUT UINTN *CommBufferSize OPTIONAL
);
UINTN
DevicePathSize (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
);
//
// /////////////////////////////////////////////////////////////////////////////
// FUNCTIONS
//
// Driver entry point
//
EFI_STATUS
EFIAPI
InitializeQNCSmmDispatcher (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Initializes the QNC SMM Dispatcher
Arguments:
ImageHandle - Pointer to the loaded image protocol for this driver
SystemTable - Pointer to the EFI System Table
Returns:
Status - EFI_SUCCESS
--*/
{
EFI_STATUS Status;
QNCSmmPublishDispatchProtocols ();
//
// Register a callback function to handle subsequent SMIs. This callback
// will be called by SmmCoreDispatcher.
//
Status = gSmst->SmiHandlerRegister (QNCSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle);
ASSERT_EFI_ERROR (Status);
//
// Initialize Callback DataBase
//
InitializeListHead (&mPrivateData.CallbackDataBase);
//
// Enable SMIs on the QNC now that we have a callback
//
QNCSmmInitHardware ();
return EFI_SUCCESS;
}
EFI_STATUS
SaveState (
VOID
)
/*++
Routine Description:
Save Index registers to avoid corrupting the foreground environment
Arguments:
None
Returns:
Status - EFI_SUCCESS
--*/
{
mPciAddress = IoRead32 (EFI_PCI_ADDRESS_PORT);
return EFI_SUCCESS;
}
EFI_STATUS
RestoreState (
VOID
)
/*++
Routine Description:
Restore Index registers to avoid corrupting the foreground environment
Arguments:
None
Returns:
Status - EFI_SUCCESS
--*/
{
IoWrite32 (EFI_PCI_ADDRESS_PORT, mPciAddress);
return EFI_SUCCESS;
}
EFI_STATUS
SmiInputValueDuplicateCheck (
UINTN FedSwSmiInputValue
)
/*++
Routine Description:
Check the Fed SwSmiInputValue to see if there is a duplicated one in the database
Arguments:
None
Returns:
Status - EFI_SUCCESS, EFI_INVALID_PARAMETER
--*/
// GC_TODO: FedSwSmiInputValue - add argument and description to function comment
{
DATABASE_RECORD *RecordInDb;
LIST_ENTRY *LinkInDb;
LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
if (RecordInDb->ProtocolType == SwType) {
if (RecordInDb->ChildContext.Sw.SwSmiInputValue == FedSwSmiInputValue) {
return EFI_INVALID_PARAMETER;
}
}
LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
}
return EFI_SUCCESS;
}
EFI_STATUS
QNCSmmCoreRegister (
IN QNC_SMM_GENERIC_PROTOCOL *This,
IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
IN QNC_SMM_CONTEXT *RegisterContext,
OUT EFI_HANDLE *DispatchHandle
)
/*++
Routine Description:
Arguments:
Returns:
--*/
// GC_TODO: This - add argument and description to function comment
// GC_TODO: DispatchFunction - add argument and description to function comment
// GC_TODO: RegisterContext - add argument and description to function comment
// GC_TODO: DispatchHandle - add argument and description to function comment
// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment
// GC_TODO: EFI_SUCCESS - add return value to function comment
// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment
{
EFI_STATUS Status;
DATABASE_RECORD *Record;
QNC_SMM_QUALIFIED_PROTOCOL *Qualified;
INTN Index;
//
// Check for invalid parameter
//
if (This == NULL || RegisterContext == NULL || DispatchHandle == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Create database record and add to database
//
Record = (DATABASE_RECORD *) AllocateZeroPool (sizeof (DATABASE_RECORD));
if (Record == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Gather information about the registration request
//
Record->Callback = DispatchFunction;
Record->ChildContext = *RegisterContext;
Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This);
Record->ProtocolType = Qualified->Type;
CopyMem (&Record->ContextFunctions, &mContextFunctions[Qualified->Type], sizeof (Record->ContextFunctions));
//
// Perform linked list housekeeping
//
Record->Signature = DATABASE_RECORD_SIGNATURE;
switch (Qualified->Type) {
//
// By the end of this switch statement, we'll know the
// source description the child is registering for
//
case SxType:
//
// Check the validity of Context Type and Phase
//
if ((Record->ChildContext.Sx.Type < SxS0) ||
(Record->ChildContext.Sx.Type >= EfiMaximumSleepType) ||
(Record->ChildContext.Sx.Phase < SxEntry) ||
(Record->ChildContext.Sx.Phase >= EfiMaximumPhase)
) {
goto Error;
}
InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
CopyMem (&Record->SrcDesc, &SX_SOURCE_DESC, sizeof (Record->SrcDesc));
//
// use default clear source function
//
break;
case SwType:
if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {
//
// If SwSmiInputValue is set to (UINTN) -1 then a unique value will be assigned and returned in the structure.
//
Status = EFI_NOT_FOUND;
for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {
Status = SmiInputValueDuplicateCheck (Index);
if (!EFI_ERROR (Status)) {
RegisterContext->Sw.SwSmiInputValue = Index;
break;
}
}
if (RegisterContext->Sw.SwSmiInputValue == (UINTN)-1) {
Status = gSmst->SmmFreePool (Record);
return EFI_OUT_OF_RESOURCES;
}
//
// Update ChildContext again as SwSmiInputValue has been changed
//
Record->ChildContext = *RegisterContext;
}
//
// Check the validity of Context Value
//
if (Record->ChildContext.Sw.SwSmiInputValue > MAXIMUM_SWI_VALUE) {
goto Error;
}
if (EFI_ERROR (SmiInputValueDuplicateCheck (Record->ChildContext.Sw.SwSmiInputValue))) {
goto Error;
}
InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
CopyMem (&Record->SrcDesc, &SW_SOURCE_DESC, sizeof (Record->SrcDesc));
Record->BufferSize = sizeof (EFI_SMM_SW_REGISTER_CONTEXT);
//
// use default clear source function
//
break;
case GpiType:
InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
CopyMem (&Record->SrcDesc, &GPI_SOURCE_DESC, sizeof (Record->SrcDesc));
//
// use default clear source function
//
break;
case QNCnType:
//
// Check the validity of Context Type
//
if ((Record->ChildContext.QNCn.Type < IchnMch) || (Record->ChildContext.QNCn.Type >= NUM_ICHN_TYPES)) {
goto Error;
}
InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
CopyMem (&Record->SrcDesc, &QNCN_SOURCE_DESCS[Record->ChildContext.QNCn.Type], sizeof (Record->SrcDesc));
Record->ClearSource = QNCSmmQNCnClearSource;
break;
case PeriodicTimerType:
Status = MapPeriodicTimerToSrcDesc (RegisterContext, &(Record->SrcDesc));
if (EFI_ERROR (Status)) {
goto Error;
}
InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
Record->BufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);
Record->ClearSource = QNCSmmPeriodicTimerClearSource;
break;
default:
goto Error;
break;
};
if (Record->ClearSource == NULL) {
//
// Clear the SMI associated w/ the source using the default function
//
QNCSmmClearSource (&Record->SrcDesc);
} else {
//
// This source requires special handling to clear
//
Record->ClearSource (&Record->SrcDesc);
}
QNCSmmEnableSource (&Record->SrcDesc);
//
// Child's handle will be the address linked list link in the record
//
*DispatchHandle = (EFI_HANDLE) (&Record->Link);
return EFI_SUCCESS;
Error:
FreePool (Record);
//
// DEBUG((EFI_D_ERROR,"Free pool status %d\n", Status ));
//
return EFI_INVALID_PARAMETER;
}
EFI_STATUS
QNCSmmCoreUnRegister (
IN QNC_SMM_GENERIC_PROTOCOL *This,
IN EFI_HANDLE DispatchHandle
)
/*++
Routine Description:
Arguments:
Returns:
--*/
// GC_TODO: This - add argument and description to function comment
// GC_TODO: DispatchHandle - add argument and description to function comment
// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment
// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment
// GC_TODO: EFI_SUCCESS - add return value to function comment
{
BOOLEAN SafeToDisable;
DATABASE_RECORD *RecordToDelete;
DATABASE_RECORD *RecordInDb;
LIST_ENTRY *LinkInDb;
if (DispatchHandle == NULL) {
return EFI_INVALID_PARAMETER;
}
if (BASE_CR (DispatchHandle, DATABASE_RECORD, Link)->Signature != DATABASE_RECORD_SIGNATURE) {
return EFI_INVALID_PARAMETER;
}
RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
RemoveEntryList (&RecordToDelete->Link);
RecordToDelete->Signature = 0;
//
// See if we can disable the source, reserved for future use since this might
// not be the only criteria to disable
//
SafeToDisable = TRUE;
LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) {
SafeToDisable = FALSE;
break;
}
LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
}
if (SafeToDisable) {
QNCSmmDisableSource( &RecordToDelete->SrcDesc );
}
FreePool (RecordToDelete);
return EFI_SUCCESS;
}
/**
This function is the main entry point for an SMM handler dispatch
or communicate-based callback.
@param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
@param RegisterContext Points to an optional handler context which was specified when the handler was registered.
@param CommBuffer A pointer to a collection of data in memory that will
be conveyed from a non-SMM environment into an SMM environment.
@param CommBufferSize The size of the CommBuffer.
@return Status Code
**/
EFI_STATUS
QNCSmmCoreDispatcher (
IN EFI_HANDLE DispatchHandle,
IN CONST VOID *RegisterContext,
IN OUT VOID *CommBuffer,
IN OUT UINTN *CommBufferSize
)
{
//
// Used to prevent infinite loops
//
UINTN EscapeCount;
BOOLEAN ContextsMatch;
BOOLEAN ResetListSearch;
BOOLEAN EosSet;
BOOLEAN SxChildWasDispatched;
BOOLEAN ChildWasDispatched;
DATABASE_RECORD *RecordInDb;
LIST_ENTRY *LinkInDb;
DATABASE_RECORD *RecordToExhaust;
LIST_ENTRY *LinkToExhaust;
QNC_SMM_CONTEXT Context;
VOID *CommunicationBuffer;
UINTN BufferSize;
EFI_STATUS Status;
UINT32 NewValue;
QNC_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER;
EscapeCount = 100;
ContextsMatch = FALSE;
ResetListSearch = FALSE;
EosSet = FALSE;
SxChildWasDispatched = FALSE;
Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;
ChildWasDispatched = FALSE;
//
// Preserve Index registers
//
SaveState ();
if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {
//
// We have children registered w/ us -- continue
//
while ((!EosSet) && (EscapeCount > 0)) {
EscapeCount--;
//
// Reset this flag in order to be able to process multiple SMI Sources in one loop.
//
ResetListSearch = FALSE;
LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
while ((!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) && (ResetListSearch == FALSE)) {
RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
//
// look for the first active source
//
if (!SourceIsActive (&RecordInDb->SrcDesc)) {
//
// Didn't find the source yet, keep looking
//
LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);
} else {
//
// We found a source. If this is a sleep type, we have to go to
// appropriate sleep state anyway.No matter there is sleep child or not
//
if (RecordInDb->ProtocolType == SxType) {
SxChildWasDispatched = TRUE;
}
//
// "cache" the source description and don't query I/O anymore
//
CopyMem (&ActiveSource, &RecordInDb->SrcDesc, sizeof (ActiveSource));
LinkToExhaust = LinkInDb;
//
// exhaust the rest of the queue looking for the same source
//
while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {
RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust);
if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {
//
// These source descriptions are equal, so this callback should be
// dispatched.
//
if (RecordToExhaust->ContextFunctions.GetContext != NULL) {
//
// This child requires that we get a calling context from
// hardware and compare that context to the one supplied
// by the child.
//
ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL);
//
// Make sure contexts match before dispatching event to child
//
RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context);
ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext);
} else {
//
// This child doesn't require any more calling context beyond what
// it supplied in registration. Simply pass back what it gave us.
//
ASSERT (RecordToExhaust->Callback != NULL);
Context = RecordToExhaust->ChildContext;
ContextsMatch = TRUE;
}
if (ContextsMatch) {
if (RecordToExhaust->BufferSize != 0) {
ASSERT (RecordToExhaust->ContextFunctions.GetBuffer != NULL);
RecordToExhaust->ContextFunctions.GetBuffer (RecordToExhaust);
CommunicationBuffer = &RecordToExhaust->CommBuffer;
BufferSize = RecordToExhaust->BufferSize;
} else {
CommunicationBuffer = NULL;
BufferSize = 0;
}
ASSERT (RecordToExhaust->Callback != NULL);
RecordToExhaust->Callback (
(EFI_HANDLE) & RecordToExhaust->Link,
&Context,
CommunicationBuffer,
&BufferSize
);
ChildWasDispatched = TRUE;
if (RecordToExhaust->ProtocolType == SxType) {
SxChildWasDispatched = TRUE;
}
}
}
//
// Get next record in DB
//
LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, &RecordToExhaust->Link);
}
if (RecordInDb->ClearSource == NULL) {
//
// Clear the SMI associated w/ the source using the default function
//
QNCSmmClearSource (&ActiveSource);
} else {
//
// This source requires special handling to clear
//
RecordInDb->ClearSource (&ActiveSource);
}
if (ChildWasDispatched) {
//
// The interrupt was handled and quiesced
//
Status = EFI_SUCCESS;
} else {
//
// The interrupt was not handled but quiesced
//
Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
}
//
// Queue is empty, reset the search
//
ResetListSearch = TRUE;
}
}
EosSet = QNCSmmSetAndCheckEos ();
}
}
//
// If you arrive here, there are two possible reasons:
// (1) you've got problems with clearing the SMI status bits in the
// ACPI table. If you don't properly clear the SMI bits, then you won't be able to set the
// EOS bit. If this happens too many times, the loop exits.
// (2) there was a SMM communicate for callback messages that was received prior
// to this driver.
// If there is an asynchronous SMI that occurs while processing the Callback, let
// all of the drivers (including this one) have an opportunity to scan for the SMI
// and handle it.
// If not, we don't want to exit and have the foreground app. clear EOS without letting
// these other sources get serviced.
//
ASSERT (EscapeCount > 0);
//
// Restore Index registers
//
RestoreState ();
if (SxChildWasDispatched) {
//
// A child of the SmmSxDispatch protocol was dispatched during this call;
// put the system to sleep.
//
QNCSmmSxGoToSleep ();
}
//
// Ensure that SMI signal pin indicator is clear at the end of SMM handling.
//
NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG);
NewValue &= ~(HLEGACY_SMI_PIN_VALUE);
QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QUARK_NC_HOST_BRIDGE_HLEGACY_REG, NewValue);
return Status;
}

View File

@@ -0,0 +1,87 @@
## @file
# Component description file for QuarkNcSocId SmmDispatcher module.
#
# This driver is responsible for the registration of child drivers
# and the abstraction of the ICH SMI sources.
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = QNCSmmDispatcher
FILE_GUID = 2480271C-09C6-4f36-AD75-5E1390BD9929
MODULE_TYPE = DXE_SMM_DRIVER
VERSION_STRING = 1.0
PI_SPECIFICATION_VERSION = 0x0001000A
ENTRY_POINT = InitializeQNCSmmDispatcher
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
QNC/QNCSmmPeriodicTimer.c
QNC/QNCSmmQncn.c
QNC/QNCSmmSx.c
QNC/QNCSmmSw.c
QNC/QNCSmmGpi.c
QNC/QNCSmmHelpers.c
QNCSmmHelpers.c
QNCSmmCore.c
QNCSmmHelpers.h
QNCxSmmHelpers.h
QNCSmmRegisters.h
QNCSmm.h
CommonHeader.h
[Packages]
MdePkg/MdePkg.dec
QuarkSocPkg/QuarkSocPkg.dec
MdeModulePkg/MdeModulePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
[LibraryClasses]
UefiDriverEntryPoint
SmmServicesTableLib
UefiBootServicesTableLib
DxeServicesTableLib
MemoryAllocationLib
PciLib
PcdLib
BaseMemoryLib
DebugLib
BaseLib
IoLib
DevicePathLib
S3IoLib
QNCAccessLib
[Protocols]
gEfiSmmCpuProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiSmmReadyToLockProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiSmmPeriodicTimerDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
gEfiSmmPowerButtonDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
gEfiSmmIchnDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
gEfiSmmGpiDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
gEfiSmmSwDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
gEfiSmmSxDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
gEfiSmmUsbDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
gEfiSmmIoTrapDispatch2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED
[Pcd]
gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
[Depex]
gEfiSmmCpuProtocolGuid AND gEfiPciRootBridgeIoProtocolGuid

View File

@@ -0,0 +1,373 @@
/** @file
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "QNCSmm.h"
#include "QNCSmmHelpers.h"
//
// #define BIT_ZERO 0x00000001
//
CONST UINT32 BIT_ZERO = 0x00000001;
//
// /////////////////////////////////////////////////////////////////////////////
// SUPPORT / HELPER FUNCTIONS (QNC version-independent)
//
BOOLEAN
CompareEnables (
CONST IN QNC_SMM_SOURCE_DESC *Src1,
CONST IN QNC_SMM_SOURCE_DESC *Src2
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Src1 - GC_TODO: add argument description
Src2 - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
{
BOOLEAN IsEqual;
UINTN loopvar;
IsEqual = TRUE;
for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
//
// It's okay to compare a NULL bit description to a non-NULL bit description.
// They are unequal and these tests will generate the correct result.
//
if (Src1->En[loopvar].Bit != Src2->En[loopvar].Bit ||
Src1->En[loopvar].Reg.Type != Src2->En[loopvar].Reg.Type ||
Src1->En[loopvar].Reg.Data.raw != Src2->En[loopvar].Reg.Data.raw
) {
IsEqual = FALSE;
break;
//
// out of for loop
//
}
}
return IsEqual;
}
BOOLEAN
CompareStatuses (
CONST IN QNC_SMM_SOURCE_DESC *Src1,
CONST IN QNC_SMM_SOURCE_DESC *Src2
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Src1 - GC_TODO: add argument description
Src2 - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
{
BOOLEAN IsEqual;
UINTN loopvar;
IsEqual = TRUE;
for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
//
// It's okay to compare a NULL bit description to a non-NULL bit description.
// They are unequal and these tests will generate the correct result.
//
if (Src1->Sts[loopvar].Bit != Src2->Sts[loopvar].Bit ||
Src1->Sts[loopvar].Reg.Type != Src2->Sts[loopvar].Reg.Type ||
Src1->Sts[loopvar].Reg.Data.raw != Src2->Sts[loopvar].Reg.Data.raw
) {
IsEqual = FALSE;
break;
//
// out of for loop
//
}
}
return IsEqual;
}
BOOLEAN
CompareSources (
CONST IN QNC_SMM_SOURCE_DESC *Src1,
CONST IN QNC_SMM_SOURCE_DESC *Src2
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Src1 - GC_TODO: add argument description
Src2 - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
{
return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses (Src1, Src2));
}
BOOLEAN
SourceIsActive (
CONST IN QNC_SMM_SOURCE_DESC *Src
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Src - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
{
BOOLEAN IsActive;
UINTN loopvar;
BOOLEAN SciEn;
IsActive = TRUE;
SciEn = QNCSmmGetSciEn ();
if ((Src->Flags & QNC_SMM_SCI_EN_DEPENDENT) && (SciEn)) {
//
// This source is dependent on SciEn, and SciEn == 1. An ACPI OS is present,
// so we shouldn't do anything w/ this source until SciEn == 0.
//
IsActive = FALSE;
} else {
//
// Read each bit desc from hardware and make sure it's a one
//
for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
if (!IS_BIT_DESC_NULL (Src->En[loopvar])) {
if (ReadBitDesc (&Src->En[loopvar]) == 0) {
IsActive = FALSE;
break;
//
// out of for loop
//
}
}
}
if (IsActive) {
//
// Read each bit desc from hardware and make sure it's a one
//
for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
if (!IS_BIT_DESC_NULL (Src->Sts[loopvar])) {
if (ReadBitDesc (&Src->Sts[loopvar]) == 0) {
IsActive = FALSE;
break;
//
// out of for loop
//
}
}
}
}
}
return IsActive;
}
VOID
QNCSmmEnableSource (
CONST QNC_SMM_SOURCE_DESC *SrcDesc
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
SrcDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
{
UINTN loopvar;
//
// Set enables to 1 by writing a 1
//
for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) {
WriteBitDesc (&SrcDesc->En[loopvar], 1);
}
}
QNCSmmClearSource (SrcDesc);
}
VOID
QNCSmmDisableSource (
CONST QNC_SMM_SOURCE_DESC *SrcDesc
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
SrcDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
{
UINTN loopvar;
for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) {
if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) {
WriteBitDesc (&SrcDesc->En[loopvar], 0);
}
}
}
VOID
QNCSmmClearSource (
CONST QNC_SMM_SOURCE_DESC *SrcDesc
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
SrcDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
{
UINTN loopvar;
BOOLEAN ValueToWrite;
ValueToWrite =
((SrcDesc->Flags & QNC_SMM_CLEAR_WITH_ZERO) == 0) ? TRUE : FALSE;
for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) {
WriteBitDesc (&SrcDesc->Sts[loopvar], ValueToWrite);
}
}
}
VOID
QNCSmmClearSourceAndBlock (
CONST QNC_SMM_SOURCE_DESC *SrcDesc
)
// GC_TODO: function comment should start with '/*++'
/*
Sets the source to a 1 or 0 and then waits for it to clear.
Be very careful when calling this function -- it will not
ASSERT. An acceptable case to call the function is when
waiting for the NEWCENTURY_STS bit to clear (which takes
3 RTCCLKs).
*/
// GC_TODO: function comment should end with '--*/'
// GC_TODO: function comment is missing 'Routine Description:'
// GC_TODO: function comment is missing 'Arguments:'
// GC_TODO: function comment is missing 'Returns:'
// GC_TODO: SrcDesc - add argument and description to function comment
{
UINTN loopvar;
BOOLEAN IsSet;
BOOLEAN ValueToWrite;
ValueToWrite =
((SrcDesc->Flags & QNC_SMM_CLEAR_WITH_ZERO) == 0) ? TRUE : FALSE;
for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) {
if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) {
//
// Write the bit
//
WriteBitDesc (&SrcDesc->Sts[loopvar], ValueToWrite);
//
// Don't return until the bit actually clears.
//
IsSet = TRUE;
while (IsSet) {
IsSet = ReadBitDesc (&SrcDesc->Sts[loopvar]);
//
// IsSet will eventually clear -- or else we'll have
// an infinite loop.
//
}
}
}
}

View File

@@ -0,0 +1,225 @@
/** @file
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef QNC_SMM_HELPERS_H
#define QNC_SMM_HELPERS_H
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "QNCSmm.h"
#include "QNCxSmmHelpers.h"
//
// /////////////////////////////////////////////////////////////////////////////
// SUPPORT / HELPER FUNCTIONS (QNC version-independent)
//
VOID
QNCSmmPublishDispatchProtocols (
VOID
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
None
Returns:
GC_TODO: add return values
--*/
;
BOOLEAN
CompareEnables (
CONST IN QNC_SMM_SOURCE_DESC *Src1,
CONST IN QNC_SMM_SOURCE_DESC *Src2
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Src1 - GC_TODO: add argument description
Src2 - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
BOOLEAN
CompareStatuses (
CONST IN QNC_SMM_SOURCE_DESC *Src1,
CONST IN QNC_SMM_SOURCE_DESC *Src2
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Src1 - GC_TODO: add argument description
Src2 - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
BOOLEAN
CompareSources (
CONST IN QNC_SMM_SOURCE_DESC *Src1,
CONST IN QNC_SMM_SOURCE_DESC *Src2
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Src1 - GC_TODO: add argument description
Src2 - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
BOOLEAN
SourceIsActive (
CONST IN QNC_SMM_SOURCE_DESC *Src
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
Src - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
VOID
QNCSmmEnableSource (
CONST QNC_SMM_SOURCE_DESC *SrcDesc
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
SrcDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
VOID
QNCSmmDisableSource (
CONST QNC_SMM_SOURCE_DESC *SrcDesc
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
SrcDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
VOID
QNCSmmClearSource (
CONST QNC_SMM_SOURCE_DESC *SrcDesc
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
SrcDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
VOID
QNCSmmClearSourceAndBlock (
CONST QNC_SMM_SOURCE_DESC *SrcDesc
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
SrcDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
#endif

View File

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

View File

@@ -0,0 +1,184 @@
/** @file
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef QNCX_SMM_HELPERS_H
#define QNCX_SMM_HELPERS_H
//
// Include common header file for this module.
//
#include "CommonHeader.h"
#include "QNCSmm.h"
EFI_STATUS
QNCSmmInitHardware (
VOID
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
None
Returns:
GC_TODO: add return values
--*/
;
EFI_STATUS
QNCSmmEnableGlobalSmiBit (
VOID
)
/*++
Routine Description:
Enables the QNC to generate SMIs. Note that no SMIs will be generated
if no SMI sources are enabled. Conversely, no enabled SMI source will
generate SMIs if SMIs are not globally enabled. This is the main
switchbox for SMI generation.
Arguments:
None
Returns:
EFI_SUCCESS.
Asserts, otherwise.
--*/
;
EFI_STATUS
QNCSmmClearSmi (
VOID
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
None
Returns:
GC_TODO: add return values
--*/
;
BOOLEAN
QNCSmmSetAndCheckEos (
VOID
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
None
Returns:
GC_TODO: add return values
--*/
;
BOOLEAN
QNCSmmGetSciEn (
VOID
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
None
Returns:
GC_TODO: add return values
--*/
;
//
// ///////////////////////////////////////////////////////////////////////////
//
// These may or may not need to change w/ the QNC version;
// they're here because they're highly IA-32 dependent.
//
BOOLEAN
ReadBitDesc (
CONST QNC_SMM_BIT_DESC *BitDesc
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
BitDesc - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
VOID
WriteBitDesc (
CONST QNC_SMM_BIT_DESC *BitDesc,
CONST BOOLEAN ValueToWrite
)
/*++
Routine Description:
GC_TODO: Add function description
Arguments:
BitDesc - GC_TODO: add argument description
ValueToWrite - GC_TODO: add argument description
Returns:
GC_TODO: add return values
--*/
;
#endif

View File

@@ -0,0 +1,382 @@
/** @file
This is the driver that publishes the SMM Access Ppi
instance for the Quark SOC.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiPei.h>
#include <Ppi/SmmAccess.h>
#include <Guid/SmramMemoryReserve.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
#include <Library/PciLib.h>
#include <Library/PeiServicesLib.h>
#include <Library/QNCSmmLib.h>
#include <QNCAccess.h>
#define SMM_ACCESS_PRIVATE_DATA_FROM_THIS(a) \
CR ( \
a, \
SMM_ACCESS_PRIVATE_DATA, \
SmmAccess, \
SMM_ACCESS_PRIVATE_DATA_SIGNATURE \
)
#define MAX_CPU_SOCKET 1
#define MAX_SMRAM_RANGES 4
typedef struct {
UINTN Signature;
EFI_HANDLE Handle;
PEI_SMM_ACCESS_PPI SmmAccess;
UINTN NumberRegions;
EFI_SMRAM_DESCRIPTOR SmramDesc[MAX_SMRAM_RANGES];
UINT8 TsegSize;
UINT8 MaxBusNumber;
UINT8 SocketPopulated[MAX_CPU_SOCKET];
UINT8 SocketBusNum[MAX_CPU_SOCKET];
} SMM_ACCESS_PRIVATE_DATA;
#define SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', 's', 'm', 'a')
EFI_STATUS
EFIAPI
Open (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_SMM_ACCESS_PPI *This,
IN UINTN DescriptorIndex
)
/*++
Routine Description:
This routine accepts a request to "open" a region of SMRAM. The
region could be legacy ABSEG, HSEG, or TSEG near top of physical memory.
The use of "open" means that the memory is visible from all PEIM
and SMM agents.
Arguments:
PeiServices - General purpose services available to every PEIM.
This - Pointer to the SMM Access Interface.
DescriptorIndex - Region of SMRAM to Open.
Returns:
EFI_SUCCESS - The region was successfully opened.
EFI_DEVICE_ERROR - The region could not be opened because locked by
chipset.
EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
--*/
{
SMM_ACCESS_PRIVATE_DATA *SmmAccess;
SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
if (DescriptorIndex >= SmmAccess->NumberRegions) {
return EFI_INVALID_PARAMETER;
} else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) {
return EFI_DEVICE_ERROR;
}
//
// Open TSEG
//
if (!QNCOpenSmramRegion ()) {
SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
return EFI_DEVICE_ERROR;
}
SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED);
SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_OPEN;
SmmAccess->SmmAccess.OpenState = TRUE;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
Close (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_SMM_ACCESS_PPI *This,
IN UINTN DescriptorIndex
)
/*++
Routine Description:
This routine accepts a request to "close" a region of SMRAM. This is valid for
compatible SMRAM region.
Arguments:
PeiServices - General purpose services available to every PEIM.
This - Pointer to the SMM Access Interface.
DescriptorIndex - Region of SMRAM to Close.
Returns:
EFI_SUCCESS - The region was successfully closed.
EFI_DEVICE_ERROR - The region could not be closed because locked by
chipset.
EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
--*/
{
SMM_ACCESS_PRIVATE_DATA *SmmAccess;
BOOLEAN OpenState;
UINTN Index;
SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
if (DescriptorIndex >= SmmAccess->NumberRegions) {
return EFI_INVALID_PARAMETER;
} else if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_LOCKED) {
return EFI_DEVICE_ERROR;
}
if (SmmAccess->SmramDesc[DescriptorIndex].RegionState & EFI_SMRAM_CLOSED) {
return EFI_DEVICE_ERROR;
}
//
// Close TSEG
//
if (!QNCCloseSmramRegion ()) {
SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
return EFI_DEVICE_ERROR;
}
SmmAccess->SmramDesc[DescriptorIndex].RegionState &= ~EFI_SMRAM_OPEN;
SmmAccess->SmramDesc[DescriptorIndex].RegionState |= (EFI_SMRAM_CLOSED | EFI_ALLOCATED);
//
// Find out if any regions are still open
//
OpenState = FALSE;
for (Index = 0; Index < SmmAccess->NumberRegions; Index++) {
if ((SmmAccess->SmramDesc[Index].RegionState & EFI_SMRAM_OPEN) == EFI_SMRAM_OPEN) {
OpenState = TRUE;
}
}
SmmAccess->SmmAccess.OpenState = OpenState;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
Lock (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_SMM_ACCESS_PPI *This,
IN UINTN DescriptorIndex
)
/*++
Routine Description:
This routine accepts a request to "lock" SMRAM. The
region could be legacy AB or TSEG near top of physical memory.
The use of "lock" means that the memory can no longer be opened
to PEIM.
Arguments:
PeiServices - General purpose services available to every PEIM.
This - Pointer to the SMM Access Interface.
DescriptorIndex - Region of SMRAM to Lock.
Returns:
EFI_SUCCESS - The region was successfully locked.
EFI_DEVICE_ERROR - The region could not be locked because at least
one range is still open.
EFI_INVALID_PARAMETER - The descriptor index was out of bounds.
--*/
{
SMM_ACCESS_PRIVATE_DATA *SmmAccess;
SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
if (DescriptorIndex >= SmmAccess->NumberRegions) {
return EFI_INVALID_PARAMETER;
} else if (SmmAccess->SmmAccess.OpenState) {
return EFI_DEVICE_ERROR;
}
SmmAccess->SmramDesc[DescriptorIndex].RegionState |= EFI_SMRAM_LOCKED;
SmmAccess->SmmAccess.LockState = TRUE;
//
// Lock TSEG
//
QNCLockSmramRegion ();
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GetCapabilities (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_SMM_ACCESS_PPI *This,
IN OUT UINTN *SmramMapSize,
IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap
)
/*++
Routine Description:
This routine services a user request to discover the SMRAM
capabilities of this platform. This will report the possible
ranges that are possible for SMRAM access, based upon the
memory controller capabilities.
Arguments:
PeiServices - General purpose services available to every PEIM.
This - Pointer to the SMRAM Access Interface.
SmramMapSize - Pointer to the variable containing size of the
buffer to contain the description information.
SmramMap - Buffer containing the data describing the Smram
region descriptors.
Returns:
EFI_BUFFER_TOO_SMALL - The user did not provide a sufficient buffer.
EFI_SUCCESS - The user provided a sufficiently-sized buffer.
--*/
{
EFI_STATUS Status;
SMM_ACCESS_PRIVATE_DATA *SmmAccess;
UINTN BufferSize;
SmmAccess = SMM_ACCESS_PRIVATE_DATA_FROM_THIS (This);
BufferSize = SmmAccess->NumberRegions * sizeof (EFI_SMRAM_DESCRIPTOR);
if (*SmramMapSize < BufferSize) {
Status = EFI_BUFFER_TOO_SMALL;
} else {
CopyMem (SmramMap, SmmAccess->SmramDesc, *SmramMapSize);
Status = EFI_SUCCESS;
}
*SmramMapSize = BufferSize;
return Status;
}
EFI_STATUS
EFIAPI
SmmAccessPeiEntryPoint (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
/*++
Routine Description:
This is the constructor for the SMM Access Ppi
Arguments:
FfsHeader - FfsHeader.
PeiServices - General purpose services available to every PEIM.
Returns:
EFI_SUCCESS - Protocol successfully started and installed.
EFI_UNSUPPORTED - Protocol can't be started.
--*/
{
EFI_STATUS Status;
UINTN Index;
EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock;
SMM_ACCESS_PRIVATE_DATA *SmmAccessPrivate;
EFI_PEI_PPI_DESCRIPTOR *PpiList;
EFI_HOB_GUID_TYPE *GuidHob;
//
// Initialize private data
//
SmmAccessPrivate = AllocatePool (sizeof(*SmmAccessPrivate));
ASSERT(SmmAccessPrivate);
PpiList = AllocatePool (sizeof(*PpiList));
ASSERT (PpiList);
//
// Build SMM related information
//
SmmAccessPrivate->Signature = SMM_ACCESS_PRIVATE_DATA_SIGNATURE;
//
// Get Hob list
//
GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
ASSERT (DescriptorBlock);
// Get CPU Max bus number
SmmAccessPrivate->MaxBusNumber = PCI_BUS_NUMBER_QNC;
for (Index = 0; Index < MAX_CPU_SOCKET; Index++) {
SmmAccessPrivate->SocketPopulated[Index] = TRUE;
SmmAccessPrivate->SocketBusNum[Index] = PCI_BUS_NUMBER_QNC;
}
//
// Use the hob to publish SMRAM capabilities
//
ASSERT (DescriptorBlock->NumberOfSmmReservedRegions <= MAX_SMRAM_RANGES);
for (Index = 0; Index < DescriptorBlock->NumberOfSmmReservedRegions; Index++) {
SmmAccessPrivate->SmramDesc[Index].PhysicalStart = DescriptorBlock->Descriptor[Index].PhysicalStart;
SmmAccessPrivate->SmramDesc[Index].CpuStart = DescriptorBlock->Descriptor[Index].CpuStart;
SmmAccessPrivate->SmramDesc[Index].PhysicalSize = DescriptorBlock->Descriptor[Index].PhysicalSize;
SmmAccessPrivate->SmramDesc[Index].RegionState = DescriptorBlock->Descriptor[Index].RegionState;
}
SmmAccessPrivate->NumberRegions = Index;
SmmAccessPrivate->SmmAccess.Open = Open;
SmmAccessPrivate->SmmAccess.Close = Close;
SmmAccessPrivate->SmmAccess.Lock = Lock;
SmmAccessPrivate->SmmAccess.GetCapabilities = GetCapabilities;
SmmAccessPrivate->SmmAccess.LockState = FALSE;
SmmAccessPrivate->SmmAccess.OpenState = FALSE;
PpiList->Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
PpiList->Guid = &gPeiSmmAccessPpiGuid;
PpiList->Ppi = &SmmAccessPrivate->SmmAccess;
Status = (**PeiServices).InstallPpi (PeiServices, PpiList);
ASSERT_EFI_ERROR(Status);
DEBUG (
(EFI_D_INFO, "SMM Base:Size %08X:%08X\n",
(UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalStart),
(UINTN)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize)
));
SmmAccessPrivate->TsegSize = (UINT8)(SmmAccessPrivate->SmramDesc[SmmAccessPrivate->NumberRegions-1].PhysicalSize);
return EFI_SUCCESS;
}

View File

@@ -0,0 +1,51 @@
## @file
# Component description file for SmmAccessPei module
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = SmmAccessPei
FILE_GUID = B4E0CDFC-30CD-4b29-A445-B0AA95A532E4
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
ENTRY_POINT = SmmAccessPeiEntryPoint
[Sources]
SmmAccessPei.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
PeimEntryPoint
BaseMemoryLib
MemoryAllocationLib
DebugLib
HobLib
PeiServicesLib
PciLib
SmmLib
[Guids]
gEfiSmmPeiSmramMemoryReserveGuid # ALWAYS_CONSUMED
[Ppis]
gPeiSmmAccessPpiGuid # ALWAYS_PRODUCED
gEfiPeiMemoryDiscoveredPpiGuid # ALWAYS_CONSUMED
[Depex]
gEfiPeiMemoryDiscoveredPpiGuid

View File

@@ -0,0 +1,282 @@
/** @file
This module provides an implementation of the SMM Control PPI for use with
the QNC.
Copyright (c) 2013-2015 Intel Corporation.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <PiPei.h>
#include <Ppi/SmmControl.h>
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
#include <Library/PeiServicesLib.h>
#include <Library/PcdLib.h>
#include <Library/IoLib.h>
#include <Library/PciLib.h>
#include <IntelQNCPeim.h>
#include <Library/QNCAccessLib.h>
#include <Uefi/UefiBaseType.h>
/**
Generates an SMI using the parameters passed in.
@param PeiServices Describes the list of possible PEI Services.
@param This A pointer to an instance of
EFI_SMM_CONTROL_PPI
@param ArgumentBuffer The argument buffer
@param ArgumentBufferSize The size of the argument buffer
@param Periodic TRUE to indicate a periodical SMI
@param ActivationInterval Interval of the periodical SMI
@retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
@retval EFI_SUCCESS SMI generated
**/
EFI_STATUS
EFIAPI
PeiActivate (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_SMM_CONTROL_PPI *This,
IN OUT INT8 *ArgumentBuffer OPTIONAL,
IN OUT UINTN *ArgumentBufferSize OPTIONAL,
IN BOOLEAN Periodic OPTIONAL,
IN UINTN ActivationInterval OPTIONAL
);
/**
Clears an SMI.
@param PeiServices Describes the list of possible PEI Services.
@param This Pointer to an instance of EFI_SMM_CONTROL_PPI
@param Periodic TRUE to indicate a periodical SMI
@return Return value from SmmClear()
**/
EFI_STATUS
EFIAPI
PeiDeactivate (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_SMM_CONTROL_PPI *This,
IN BOOLEAN Periodic OPTIONAL
);
PEI_SMM_CONTROL_PPI mSmmControlPpi = {
PeiActivate,
PeiDeactivate
};
EFI_PEI_PPI_DESCRIPTOR mPpiList = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gPeiSmmControlPpiGuid,
&mSmmControlPpi
};
/**
Clear SMI related chipset status and re-enable SMI by setting the EOS bit.
@retval EFI_SUCCESS The requested operation has been carried out successfully
@retval EFI_DEVICE_ERROR The EOS bit could not be set.
**/
EFI_STATUS
SmmClear (
VOID
)
{
UINT16 PM1BLK_Base;
UINT16 GPE0BLK_Base;
//
// Get PM1BLK_Base & GPE0BLK_Base
//
PM1BLK_Base = PcdGet16 (PcdPm1blkIoBaseAddress);
GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
//
// Clear the Power Button Override Status Bit, it gates EOS from being set.
// In QuarkNcSocId - Bit is read only. Handled by external SMC, do nothing.
//
//
// Clear the APM SMI Status Bit
//
IoWrite32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_APM);
//
// Set the EOS Bit
//
IoOr32 ((GPE0BLK_Base + R_QNC_GPE0BLK_SMIS), B_QNC_GPE0BLK_SMIS_EOS);
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
SmmTrigger (
IN UINT8 Data
)
/*++
Routine Description:
Trigger the software SMI
Arguments:
Data The value to be set on the software SMI data port
Returns:
EFI_SUCCESS Function completes successfully
--*/
{
UINT16 GPE0BLK_Base;
UINT32 NewValue;
//
// Get GPE0BLK_Base
//
GPE0BLK_Base = PcdGet16 (PcdGpe0blkIoBaseAddress);
//
// Enable the APMC SMI
//
IoOr32 (GPE0BLK_Base + R_QNC_GPE0BLK_SMIE, B_QNC_GPE0BLK_SMIE_APM);
//
// Enable SMI globally
//
NewValue = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC);
NewValue |= SMI_EN;
QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, NewValue);
//
// Generate the APMC SMI
//
IoWrite8 (PcdGet16 (PcdSmmActivationPort), Data);
return EFI_SUCCESS;
}
/**
Generates an SMI using the parameters passed in.
@param PeiServices Describes the list of possible PEI Services.
@param This A pointer to an instance of
EFI_SMM_CONTROL_PPI
@param ArgumentBuffer The argument buffer
@param ArgumentBufferSize The size of the argument buffer
@param Periodic TRUE to indicate a periodical SMI
@param ActivationInterval Interval of the periodical SMI
@retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
@retval EFI_SUCCESS SMI generated
**/
EFI_STATUS
EFIAPI
PeiActivate (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_SMM_CONTROL_PPI *This,
IN OUT INT8 *ArgumentBuffer OPTIONAL,
IN OUT UINTN *ArgumentBufferSize OPTIONAL,
IN BOOLEAN Periodic OPTIONAL,
IN UINTN ActivationInterval OPTIONAL
)
{
INT8 Data;
EFI_STATUS Status;
//
// Periodic SMI not supported.
//
if (Periodic) {
DEBUG ((DEBUG_WARN, "Invalid parameter\n"));
return EFI_INVALID_PARAMETER;
}
if (ArgumentBuffer == NULL) {
Data = 0xFF;
} else {
if (ArgumentBufferSize == NULL || *ArgumentBufferSize != 1) {
return EFI_INVALID_PARAMETER;
}
Data = *ArgumentBuffer;
}
//
// Clear any pending the APM SMI
//
Status = SmmClear ();
if (EFI_ERROR (Status)) {
return Status;
}
return SmmTrigger (Data);
}
/**
Clears an SMI.
@param PeiServices Describes the list of possible PEI Services.
@param This Pointer to an instance of EFI_SMM_CONTROL_PPI
@param Periodic TRUE to indicate a periodical SMI
@return Return value from SmmClear()
**/
EFI_STATUS
EFIAPI
PeiDeactivate (
IN EFI_PEI_SERVICES **PeiServices,
IN PEI_SMM_CONTROL_PPI *This,
IN BOOLEAN Periodic OPTIONAL
)
{
if (Periodic) {
return EFI_INVALID_PARAMETER;
}
return SmmClear ();
}
/**
This is the constructor for the SMM Control Ppi.
This function installs EFI_SMM_CONTROL_PPI.
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_UNSUPPORTED There's no Intel ICH on this platform
@return The status returned from InstallPpi().
--*/
EFI_STATUS
EFIAPI
SmmControlPeiEntry (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList);
ASSERT_EFI_ERROR (Status);
return Status;
}

View File

@@ -0,0 +1,57 @@
## @file
# Component description file for SmmControlPei module.
#
# Copyright (c) 2013-2015 Intel Corporation.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = SmmControlPei
FILE_GUID = 60EC7720-512B-4490-9FD1-A336769AE01F
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
ENTRY_POINT = SmmControlPeiEntry
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
SmmControlPei.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
QuarkSocPkg/QuarkSocPkg.dec
[LibraryClasses]
PeimEntryPoint
DebugLib
PeiServicesLib
PcdLib
IoLib
PciLib
QNCAccessLib
[Ppis]
gPeiSmmControlPpiGuid # ALWAYS_PRODUCED
[Pcd]
gEfiQuarkNcSocIdTokenSpaceGuid.PcdPm1blkIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdGpe0blkIoBaseAddress
gEfiQuarkNcSocIdTokenSpaceGuid.PcdSmmActivationPort
[Depex]
TRUE

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