summaryrefslogtreecommitdiff
path: root/QuarkSocPkg/QuarkNorthCluster/MemoryInit
diff options
context:
space:
mode:
authorMichael Kinney <michael.d.kinney@intel.com>2015-12-15 19:22:23 +0000
committermdkinney <mdkinney@Edk2>2015-12-15 19:22:23 +0000
commit9b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164 (patch)
treebb30f13e652143e0ac74e589e908ca2a1782da73 /QuarkSocPkg/QuarkNorthCluster/MemoryInit
parent46ff196fde4882fca1a0210f7df9166d8832ad06 (diff)
downloadedk2-platforms-9b6bbcdbfdf5e54c6d1ed538ea8076d0858fb164.tar.xz
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
Diffstat (limited to 'QuarkSocPkg/QuarkNorthCluster/MemoryInit')
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c65
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h41
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf76
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h49
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h744
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h90
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c542
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h72
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h138
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c388
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c2645
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h28
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c1580
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h97
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h83
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c46
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h166
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c192
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c193
-rw-r--r--QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h21
20 files changed, 7256 insertions, 0 deletions
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c
new file mode 100644
index 0000000000..782a2d13a7
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.c
@@ -0,0 +1,65 @@
+/** @file
+Framework PEIM to initialize memory on a QuarkNcSocId Memory Controller.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// Include common header file for this module.
+//
+#include "MemoryInit.h"
+
+static PEI_QNC_MEMORY_INIT_PPI mPeiQNCMemoryInitPpi =
+{ MrcStart };
+
+static EFI_PEI_PPI_DESCRIPTOR PpiListPeiQNCMemoryInit =
+{
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gQNCMemoryInitPpiGuid,
+ &mPeiQNCMemoryInitPpi
+};
+
+void Mrc( MRCParams_t *MrcData);
+
+/**
+
+ Do memory initialization for QuarkNcSocId DDR3 SDRAM Controller
+
+ @param FfsHeader Not used.
+ @param PeiServices General purpose services available to every PEIM.
+
+ @return EFI_SUCCESS Memory initialization completed successfully.
+ All other error conditions encountered result in an ASSERT.
+
+ **/
+EFI_STATUS
+PeimMemoryInit(
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ Status = (**PeiServices).InstallPpi(PeiServices, &PpiListPeiQNCMemoryInit);
+
+ return Status;
+}
+
+VOID
+EFIAPI
+MrcStart(
+ IN OUT MRCParams_t *MrcData
+ )
+{
+
+ Mrc(MrcData);
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h
new file mode 100644
index 0000000000..5d61c4d71c
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInit.h
@@ -0,0 +1,41 @@
+/** @file
+Framework PEIM to initialize memory on an DDR2 SDRAM Memory Controller.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef _PEI_QNC_MEMORY_INIT_H_
+#define _PEI_QNC_MEMORY_INIT_H_
+
+//
+// The package level header files this module uses
+//
+#include <PiPei.h>
+#include <IntelQNCPeim.h>
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Ppi/QNCMemoryInit.h>
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+
+
+VOID
+EFIAPI
+MrcStart (
+ IN OUT MRCParams_t *MrcData
+ );
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf
new file mode 100644
index 0000000000..e32768446e
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/MemoryInitPei.inf
@@ -0,0 +1,76 @@
+## @file
+# This is the Memory Initialization Driver for Quark
+#
+# Copyright (c) 2013-2015 Intel Corporation.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MemoryInitPei
+ FILE_GUID = D2C69B26-82E1-4a1b-AD35-ED0261B9F347
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = PeimMemoryInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[BuildOptions]
+ GCC:DEBUG_*_*_CC_FLAGS = -DGCC -Wno-unused-function
+ GCC:RELEASE_*_*_CC_FLAGS = -DNDEBUG -DGCC -Wno-unused-function
+ INTEL:RELEASE_*_*_CC_FLAGS = /D NDEBUG
+ MSFT:RELEASE_*_*_CC_FLAGS = /D NDEBUG
+
+[Sources]
+ memory_options.h
+ platform.c
+ lprint.c
+ meminit.h
+ meminit.c
+ meminit_utils.h
+ meminit_utils.c
+ gen5_iosf_sb_definitions.h
+ general_definitions.h
+ io.h
+ core_types.h
+ prememinit.h
+ prememinit.c
+ mrc.h
+ mrc.c
+ hte.c
+ hte.h
+ MemoryInit.h
+ MemoryInit.c
+
+[Packages]
+ QuarkSocPkg/QuarkSocPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ DebugLib
+ BaseMemoryLib
+
+[Ppis]
+ gQNCMemoryInitPpiGuid # PPI ALWAYS_PRODUCED
+
+[Depex]
+ TRUE
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h
new file mode 100644
index 0000000000..78807a0958
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/core_types.h
@@ -0,0 +1,49 @@
+/** @file
+Core types used in Mrc.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef __MRC_CORE_TYPES_H
+#define __MRC_CORE_TYPES_H
+
+typedef char char_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef unsigned char bool;
+typedef unsigned int size_t;
+
+#ifdef ASM_INC
+// Unfortunately h2inc has issue with long long
+typedef struct uint64_s
+{
+ uint32_t lo;
+ uint32_t hi;
+}uint64_t;
+#else
+typedef unsigned long long uint64_t;
+#endif
+
+#ifdef SIM
+// Native word length is 64bit in simulation environment
+typedef uint64_t uintn_t;
+#else
+// Quark is 32bit
+typedef uint32_t uintn_t;
+#endif
+
+#define PTR32(a) ((volatile uint32_t*)(uintn_t)(a))
+
+#endif
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h
new file mode 100644
index 0000000000..a8083a1f98
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/gen5_iosf_sb_definitions.h
@@ -0,0 +1,744 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ * MCU register definition
+ *
+ ************************************************************************/
+#ifndef __IOSF_DEFINITIONS_H
+#define __IOSF_DEFINITIONS_H
+
+// Define each of the IOSF-SB register offsets used by MRC.
+
+
+// MCU registers (DUNIT):
+// ====
+#define DRP 0x0000
+#define DTR0 0x0001
+#define DTR1 0x0002
+#define DTR2 0x0003
+#define DTR3 0x0004
+#define DTR4 0x0005
+#define DPMC0 0x0006
+#define DPMC1 0x0007
+#define DRFC 0x0008
+#define DSCH 0x0009
+#define DCAL 0x000A
+#define DRMC 0x000B
+#define PMSTS 0x000C
+#define DCO 0x000F
+#define DSTAT 0x0020
+#define DECCCTRL 0x0060
+#define DFUSESTAT 0x0070
+#define SCRMSEED 0x0080
+#define SCRMLO 0x0081
+#define SCRMHI 0x0082
+
+#define MCU_CH_OFFSET 0x0040
+#define MCU_RK_OFFSET 0x0020
+
+////
+//
+// BEGIN DUnit register definition
+//
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t rank0Enabled :1; /**< BIT [0] Rank 0 Enable */
+ uint32_t rank1Enabled :1; /**< BIT [1] Rank 1 Enable */
+ uint32_t reserved0 :2;
+ uint32_t dimm0DevWidth :2; /**< BIT [5:4] DIMM 0 Device Width (Rank0&1) */
+ uint32_t dimm0DevDensity :2; /**< BIT [7:6] DIMM 0 Device Density */
+ uint32_t reserved1 :1;
+ uint32_t dimm1DevWidth :2; /**< BIT [10:9] DIMM 1 Device Width (Rank2&3) */
+ uint32_t dimm1DevDensity :2; /**< BIT [12:11] DIMM 1 Device Density */
+ uint32_t split64 :1; /**< BIT [13] split 64B transactions */
+ uint32_t addressMap :2; /**< BIT [15:14] Address Map select */
+ uint32_t reserved3 :14;
+ uint32_t mode32 :1; /**< BIT [30] Select 32bit data interface*/
+ uint32_t reserved4 :1;
+ } field;
+} RegDRP; /**< DRAM Rank Population and Interface Register */
+#pragma pack()
+
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t dramFrequency :2; /**< DRAM Frequency (000=800,001=1033,010=1333) */
+ uint32_t reserved1 :2;
+ uint32_t tRP :4; /**< bit [7:4] Precharge to Activate Delay */
+ uint32_t tRCD :4; /**< bit [11:8] Activate to CAS Delay */
+ uint32_t tCL :3; /**< bit [14:12] CAS Latency */
+ uint32_t reserved4 :1;
+ uint32_t tXS :1; /**< SRX Delay */
+ uint32_t reserved5 :1;
+ uint32_t tXSDLL :1; /**< SRX To DLL Delay */
+ uint32_t reserved6 :1;
+ uint32_t tZQCS :1; /**< bit [20] ZQTS recovery Latncy */
+ uint32_t reserved7 :1;
+ uint32_t tZQCL :1; /**< bit [22] ZQCL recovery Latncy */
+ uint32_t reserved8 :1;
+ uint32_t pmeDelay :2; /**< bit [25:24] Power mode entry delay */
+ uint32_t reserved9 :2;
+ uint32_t CKEDLY :4; /**< bit [31:28] */
+ } field;
+} RegDTR0; /**< DRAM Timing Register 0 */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t tWCL :3; /**< bit [2:0] CAS Write Latency */
+ uint32_t reserved1 :1;
+ uint32_t tCMD :2; /**< bit [5:4] Command transport duration */
+ uint32_t reserved2 :2;
+ uint32_t tWTP :4; /**< Write to Precharge */
+ uint32_t tCCD :2; /**< CAS to CAS delay */
+ uint32_t reserved4 :2;
+ uint32_t tFAW :4; /**< Four bank Activation Window*/
+ uint32_t tRAS :4; /**< Row Activation Period: */
+ uint32_t tRRD :2; /**<Row activation to Row activation Delay */
+ uint32_t reserved5 :2;
+ uint32_t tRTP :3; /**<Read to Precharge Delay */
+ uint32_t reserved6 :1;
+ } field;
+} RegDTR1; /**< DRAM Timing Register 1 */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t tRRDR :3; /**< RD to RD from different ranks, same DIMM */
+ uint32_t reserved1 :5;
+ uint32_t tWWDR :3; /**< WR to WR from different ranks, same DIMM. */
+ uint32_t reserved3 :5;
+ uint32_t tRWDR :4; /**< bit [19:16] RD to WR from different ranks, same DIMM. */
+ uint32_t reserved5 :12;
+ } field;
+} RegDTR2; /**< DRAM Timing Register 2 */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t tWRDR :3; /**< WR to RD from different ranks, same DIMM. */
+ uint32_t reserved1 :1;
+ uint32_t tWRDD :3; /**< WR to RD from different DIMM. */
+ uint32_t reserved2 :1;
+ uint32_t tRWSR :4; /**< RD to WR Same Rank. */
+ uint32_t reserved3 :1;
+ uint32_t tWRSR :4; /**< WR to RD Same Rank. */
+ uint32_t reserved4 :5;
+ uint32_t tXP :2; /**< Time from CKE set on to any command. */
+ uint32_t PWD_DLY :4; /**< Extended Power-Down Delay. */
+ uint32_t EnDeRate :1;
+ uint32_t DeRateOvr :1;
+ uint32_t DeRateStat :1;
+ uint32_t reserved5 :1;
+ } field;
+} RegDTR3; /**< DRAM Timing Register 3 */
+#pragma pack()
+
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t WRODTSTRT :2; /**< WR command to ODT assert delay */
+ uint32_t reserved1 :2;
+ uint32_t WRODTSTOP :3; /**< Write command to ODT de-assert delay. */
+ uint32_t reserved2 :1;
+ uint32_t RDODTSTRT :3; /**< Read command to ODT assert delay */
+ uint32_t reserved3 :1;
+ uint32_t RDODTSTOP :3; /**< Read command to ODT de-assert delay */
+ uint32_t ODTDIS :1; /**< ODT disable */
+ uint32_t TRGSTRDIS :1; /**< Write target rank is not stretched */
+ uint32_t RDODTDIS :1; /**< Disable Read ODT */
+ uint32_t WRBODTDIS :1; /**< Disable Write ODT */
+ uint32_t reserved5 :13;
+ } field;
+} RegDTR4; /**< DRAM Timing Register 3 */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t SREntryDelay :8; /**< Self-Refresh Entry Delay: */
+ uint32_t powerModeOpCode :5; /**< SPID Power Mode Opcode */
+ uint32_t reserved1 :3;
+ uint32_t PCLSTO :3; /**< Page Close Timeout Period */
+ uint32_t reserved2 :1;
+ uint32_t PCLSWKOK :1; /**< Wake Allowed For Page Close Timeout */
+ uint32_t PREAPWDEN :1; /**< Send Precharge All to rank before entering Power-Down mode. */
+ uint32_t reserved3 :1;
+ uint32_t DYNSREN :1; /**< Dynamic Self-Refresh */
+ uint32_t CLKGTDIS :1; /**< Clock Gating Disabled*/
+ uint32_t DISPWRDN :1; /**< Disable Power Down*/
+ uint32_t reserved4 :2;
+ uint32_t REUTCLKGTDIS :1;
+ uint32_t ENPHYCLKGATE :1;
+ uint32_t reserved5 :2;
+ } field;
+} RegDPMC0; /**< DRAM Power Management Control Register 0 */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t REFWMLO :4; /**< Refresh Opportunistic Watermark */
+ uint32_t REFWMHI :4; /**< Refresh High Watermark*/
+ uint32_t REFWMPNC :4; /**< Refresh Panic Watermark */
+ uint32_t tREFI :3; /**< bit [14:12] Refresh Period */
+ uint32_t reserved1 :1;
+ uint32_t REFCNTMAX :2; /**< Refresh Max tREFI Interval */
+ uint32_t reserved2 :2;
+ uint32_t REFSKEWDIS :1; /**< tREFI counters */
+ uint32_t REFDBTCLR :1;
+ uint32_t reserved3 :2;
+ uint32_t CuRefRate :3;
+ uint32_t DisRefBW :1;
+ uint32_t reserved4 :4;
+ } field;
+} RegDRCF; /**< DRAM Refresh Control Register*/
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t reserved1 :8;
+ uint32_t ZQCINT :3; /**< ZQ Calibration Short Interval: */
+ uint32_t reserved2 :1;
+ uint32_t SRXZQCL :2; /** < ZQ Calibration Length */
+ uint32_t ZQCalType :1;
+ uint32_t ZQCalStart :1;
+ uint32_t TQPollStart :1;
+ uint32_t TQPollRS :2;
+ uint32_t reserved3 :5;
+ uint32_t MRRData :8; /**< bit[31:24] */
+ } field;
+} RegDCAL; /**< DRAM Calibration Control*/
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t OOOAGETRH :5; /**< Out-of-Order Aging Threshold */
+ uint32_t reserved1 :3;
+ uint32_t OOODIS :1; /**< Out-of-Order Disable */
+ uint32_t OOOST3DIS :1; /**< Out-of-Order Disabled when RequestBD_Status is 3. */
+ uint32_t reserved2 :2;
+ uint32_t NEWBYPDIS :1;
+ uint32_t reserved3 :3;
+ uint32_t IPREQMAX :3; /** < Max In-Progress Requests stored in MC */
+ uint32_t reserved4 :13;
+ } field;
+} RegDSCH; /**< DRAM Scheduler Control Register */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t DRPLOCK :1; /**< DRP lock bit */
+ uint32_t reserved1 :7;
+ uint32_t REUTLOCK :1; /**< REUT lock bit */
+ uint32_t reserved2 :19;
+ uint32_t PMICTL :1; /**< PRI Control Select: 0-memory_manager, 1-hte */
+ uint32_t PMIDIS :1; /**< PMIDIS Should be set is using IOSF-SB RW */
+ uint32_t DIOIC :1; /**< DDRIO initialization is complete */
+ uint32_t IC :1; /**< D-unit Initialization Complete */
+ } field;
+} RegDCO; /**< DRAM Controller Operation Register*/
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t SBEEN :1; /**< Enable Single Bit Error Detection and Correction */
+ uint32_t DBEEN :1; /**< Enable Double Bit Error Detection */
+ uint32_t CBOEN :3; /**< Enable ECC Check Bits Override */
+ uint32_t SYNSEL :2; /**< ECC Syndrome Bits Select for Observation */
+ uint32_t CLRSBECNT :1; /**< Clear ECC Single Bit Error Count */
+ uint32_t CBOV :8; /**< ECC Check Bits Override Value */
+ uint32_t reserved1 :1; /**< */
+ uint32_t ENCBGEN :1; /**< Enable Generation of ECC Check Bits */
+ uint32_t ENCBGESWIZ :1; /**< Enable Same Chip ECC Byte Lane Swizzle */
+
+ } field;
+} RegDECCCTRL; /**< DRAM ECC Control Register */
+#pragma pack()
+
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t FUS_DUN_ECC_DIS :1;
+ uint32_t FUS_DUN_MAX_SUPPORTED_MEMORY :3;
+ uint32_t FUS_DUN_MAX_DEVDEN :2;
+ uint32_t RESERVED1 :1;
+ uint32_t FUS_DUN_RANK2_DIS :1;
+ uint32_t FUS_DUN_OOO_DIS :1;
+ uint32_t FUS_DUN_MEMX8_DIS :1;
+ uint32_t FUS_DUN_MEMX16_DIS :1;
+ uint32_t RESERVED2 :1;
+ uint32_t FUS_DUN_1N_DIS :1;
+ uint32_t FUS_DUN_DQ_SCRAMBLER_DIS :1;
+ uint32_t RESERVED3 :1;
+ uint32_t FUS_DUN_32BIT_DRAM_IFC :1;
+ } field;
+} RegDFUSESTAT;
+#pragma pack()
+
+//
+// END DUnit register definition
+//
+////
+
+
+
+////
+//
+// DRAM Initialization Structures used in JEDEC Message Bus Commands
+//
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ unsigned command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
+ unsigned bankAddress :3; /**< Bank Address (BA[2:0]) */
+ unsigned BL :2; /**< Burst Length, CDV:1*/
+ unsigned CL :1; /**< CL Reserved CDV:0 */
+ unsigned RBT :1; /**< Read Burst Type */
+ unsigned casLatency :3; /**< cas Latency */
+ unsigned TM :1; /**< Test mode */
+ unsigned dllReset :1; /**< DLL Reset */
+ unsigned writeRecovery :3; /**< Write Recovery for Auto Pre-Charge: 001=2,010=3,011=4,100=5,101=6 */
+ unsigned PPD :1; /**< DLL Control for Precharge Power-Down CDV:1 */
+ unsigned reserved1 :3;
+ unsigned rankSelect :4; /**< Rank Select */
+ unsigned reserved2 :6;
+ } field;
+} DramInitDDR3MRS0; /**< DDR3 Mode Register Set (MRS) Command */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ unsigned command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
+ unsigned bankAddress :3; /**< Bank Address (BA[2:0]) */
+ unsigned dllEnabled :1; /**< CDV=0 */
+ unsigned DIC0 :1; /**< Output Driver Impedance Control */
+ unsigned rttNom0 :1; /**< RTT_nom[0] */
+ unsigned MRC_AL :2; /**< Additive Latency = 0 */
+ unsigned DIC1 :1; /**< Reserved */
+ unsigned rttNom1 :1; /**< RTT_nom[1] */
+ unsigned wlEnabled :1; /**< Write Leveling Enable */
+ unsigned reserved1 :1;
+ unsigned rttNom2 :1; /** < RTT_nom[2] */
+ unsigned reserved2 :1;
+ unsigned TDQS :1; /**< TDQS Enable */
+ unsigned Qoff :1; /**< Output Buffers Disabled */
+ unsigned reserved3 :3;
+ unsigned rankSelect :4; /**< Rank Select */
+ unsigned reserved4 :6;
+ } field;
+} DramInitDDR3EMR1; /**< DDR3 Extended Mode Register 1 Set (EMRS1) Command */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
+ uint32_t bankAddress :3; /**< Bank Address (BA[2:0]) */
+ uint32_t PASR :3; /**< Partial Array Self-Refresh */
+ uint32_t CWL :3; /**< CAS Write Latency */
+ uint32_t ASR :1; /**< Auto Self-Refresh */
+ uint32_t SRT :1; /**< SR Temperature Range = 0*/
+ uint32_t reserved1 :1;
+ uint32_t rtt_WR :2; /**< Rtt_WR */
+ uint32_t reserved2 :5;
+ uint32_t rankSelect :4; /**< Rank Select */
+ uint32_t reserved3 :6;
+ } field;
+} DramInitDDR3EMR2; /**< DDR3 Extended Mode Register 2 Set (EMRS2) Command */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110-ZQ,111-NOP */
+ uint32_t bankAddress :3; /**< Bank Address (BA[2:0]) */
+ uint32_t MPR_Location :2; /**< MPR Location */
+ uint32_t MPR :1; /**< MPR: Multi Purpose Register */
+ uint32_t reserved1 :13;
+ uint32_t rankSelect :4; /**< Rank Select */
+ uint32_t reserved2 :6;
+ } field;
+} DramInitDDR3EMR3; /**< DDR3 Extended Mode Register 2 Set (EMRS2) Command */
+#pragma pack()
+
+#pragma pack(1)
+typedef union {
+ uint32_t raw;
+ struct {
+ uint32_t command :3; /**< Command: 000-MRS,001-Refresh,010-Pre-charge,011-Activate,110 - ZQ Calibration,111-NOP */
+ uint32_t bankAddress :3; /**< Bank Address (BA[2:0]) */
+ uint32_t multAddress :16; /**< Multiplexed Address (MA[14:0]) */
+ uint32_t rankSelect :2; /**< Rank Select */
+ uint32_t reserved3 :8;
+ } field;
+} DramInitMisc; /**< Miscellaneous DDRx Initialization Command */
+#pragma pack()
+
+//
+// Construct DRAM init command using DramInitXxxx pattern
+//
+#define DCMD_MRS1(rnk,dat) (0 | ((rnk)<<22) | (1<<3) | ((dat)<<6))
+#define DCMD_REF(rnk) (1 | ((rnk)<<22))
+#define DCMD_PRE(rnk) (2 | ((rnk)<<22))
+#define DCMD_PREA(rnk) (2 | ((rnk)<<22) | (BIT10<<6))
+#define DCMD_ACT(rnk,row) (3 | ((rnk)<<22) | ((row)<<6))
+#define DCMD_WR(rnk,col) (4 | ((rnk)<<22) | ((col)<<6))
+#define DCMD_RD(rnk,col) (5 | ((rnk)<<22) | ((col)<<6))
+#define DCMD_ZQCS(rnk) (6 | ((rnk)<<22))
+#define DCMD_ZQCL(rnk) (6 | ((rnk)<<22) | (BIT10<<6))
+#define DCMD_NOP(rnk) (7 | ((rnk)<<22))
+
+
+
+
+#define DDR3_EMRS1_DIC_40 (0)
+#define DDR3_EMRS1_DIC_34 (1)
+
+#define DDR3_EMRS2_RTTWR_60 (BIT9)
+#define DDR3_EMRS2_RTTWR_120 (BIT10)
+
+#define DDR3_EMRS1_RTTNOM_0 (0)
+#define DDR3_EMRS1_RTTNOM_60 (BIT2)
+#define DDR3_EMRS1_RTTNOM_120 (BIT6)
+#define DDR3_EMRS1_RTTNOM_40 (BIT6|BIT2)
+#define DDR3_EMRS1_RTTNOM_20 (BIT9)
+#define DDR3_EMRS1_RTTNOM_30 (BIT9|BIT2)
+
+
+//
+// END DRAM Init...
+//
+////
+
+
+// HOST_BRIDGE registers:
+#define HMBOUND 0x0020 //ok
+
+// MEMORY_MANAGER registers:
+#define BCTRL 0x0004
+#define BWFLUSH 0x0008
+#define BDEBUG1 0x00C4
+
+////
+//
+// BEGIN DDRIO registers
+//
+
+// DDR IOs & COMPs:
+#define DDRIODQ_BL_OFFSET 0x0800
+#define DDRIODQ_CH_OFFSET ((NUM_BYTE_LANES/2) * DDRIODQ_BL_OFFSET)
+#define DDRIOCCC_CH_OFFSET 0x0800
+#define DDRCOMP_CH_OFFSET 0x0100
+
+// CH0-BL01-DQ
+#define DQOBSCKEBBCTL 0x0000
+#define DQDLLTXCTL 0x0004
+#define DQDLLRXCTL 0x0008
+#define DQMDLLCTL 0x000C
+#define B0RXIOBUFCTL 0x0010
+#define B0VREFCTL 0x0014
+#define B0RXOFFSET1 0x0018
+#define B0RXOFFSET0 0x001C
+#define B1RXIOBUFCTL 0x0020
+#define B1VREFCTL 0x0024
+#define B1RXOFFSET1 0x0028
+#define B1RXOFFSET0 0x002C
+#define DQDFTCTL 0x0030
+#define DQTRAINSTS 0x0034
+#define B1DLLPICODER0 0x0038
+#define B0DLLPICODER0 0x003C
+#define B1DLLPICODER1 0x0040
+#define B0DLLPICODER1 0x0044
+#define B1DLLPICODER2 0x0048
+#define B0DLLPICODER2 0x004C
+#define B1DLLPICODER3 0x0050
+#define B0DLLPICODER3 0x0054
+#define B1RXDQSPICODE 0x0058
+#define B0RXDQSPICODE 0x005C
+#define B1RXDQPICODER32 0x0060
+#define B1RXDQPICODER10 0x0064
+#define B0RXDQPICODER32 0x0068
+#define B0RXDQPICODER10 0x006C
+#define B01PTRCTL0 0x0070
+#define B01PTRCTL1 0x0074
+#define B01DBCTL0 0x0078
+#define B01DBCTL1 0x007C
+#define B0LATCTL0 0x0080
+#define B1LATCTL0 0x0084
+#define B01LATCTL1 0x0088
+#define B0ONDURCTL 0x008C
+#define B1ONDURCTL 0x0090
+#define B0OVRCTL 0x0094
+#define B1OVRCTL 0x0098
+#define DQCTL 0x009C
+#define B0RK2RKCHGPTRCTRL 0x00A0
+#define B1RK2RKCHGPTRCTRL 0x00A4
+#define DQRK2RKCTL 0x00A8
+#define DQRK2RKPTRCTL 0x00AC
+#define B0RK2RKLAT 0x00B0
+#define B1RK2RKLAT 0x00B4
+#define DQCLKALIGNREG0 0x00B8
+#define DQCLKALIGNREG1 0x00BC
+#define DQCLKALIGNREG2 0x00C0
+#define DQCLKALIGNSTS0 0x00C4
+#define DQCLKALIGNSTS1 0x00C8
+#define DQCLKGATE 0x00CC
+#define B0COMPSLV1 0x00D0
+#define B1COMPSLV1 0x00D4
+#define B0COMPSLV2 0x00D8
+#define B1COMPSLV2 0x00DC
+#define B0COMPSLV3 0x00E0
+#define B1COMPSLV3 0x00E4
+#define DQVISALANECR0TOP 0x00E8
+#define DQVISALANECR1TOP 0x00EC
+#define DQVISACONTROLCRTOP 0x00F0
+#define DQVISALANECR0BL 0x00F4
+#define DQVISALANECR1BL 0x00F8
+#define DQVISACONTROLCRBL 0x00FC
+#define DQTIMINGCTRL 0x010C
+// CH0-ECC
+#define ECCDLLTXCTL 0x2004
+#define ECCDLLRXCTL 0x2008
+#define ECCMDLLCTL 0x200C
+#define ECCB1DLLPICODER0 0x2038
+#define ECCB1DLLPICODER1 0x2040
+#define ECCB1DLLPICODER2 0x2048
+#define ECCB1DLLPICODER3 0x2050
+#define ECCB01DBCTL0 0x2078
+#define ECCB01DBCTL1 0x207C
+#define ECCCLKALIGNREG0 0x20B8
+#define ECCCLKALIGNREG1 0x20BC
+#define ECCCLKALIGNREG2 0x20C0
+// CH0-CMD
+#define CMDOBSCKEBBCTL 0x4800
+#define CMDDLLTXCTL 0x4808
+#define CMDDLLRXCTL 0x480C
+#define CMDMDLLCTL 0x4810
+#define CMDRCOMPODT 0x4814
+#define CMDDLLPICODER0 0x4820
+#define CMDDLLPICODER1 0x4824
+#define CMDCFGREG0 0x4840
+#define CMDPTRREG 0x4844
+#define CMDCLKALIGNREG0 0x4850
+#define CMDCLKALIGNREG1 0x4854
+#define CMDCLKALIGNREG2 0x4858
+#define CMDPMCONFIG0 0x485C
+#define CMDPMDLYREG0 0x4860
+#define CMDPMDLYREG1 0x4864
+#define CMDPMDLYREG2 0x4868
+#define CMDPMDLYREG3 0x486C
+#define CMDPMDLYREG4 0x4870
+#define CMDCLKALIGNSTS0 0x4874
+#define CMDCLKALIGNSTS1 0x4878
+#define CMDPMSTS0 0x487C
+#define CMDPMSTS1 0x4880
+#define CMDCOMPSLV 0x4884
+#define CMDBONUS0 0x488C
+#define CMDBONUS1 0x4890
+#define CMDVISALANECR0 0x4894
+#define CMDVISALANECR1 0x4898
+#define CMDVISACONTROLCR 0x489C
+#define CMDCLKGATE 0x48A0
+#define CMDTIMINGCTRL 0x48A4
+// CH0-CLK-CTL
+#define CCOBSCKEBBCTL 0x5800
+#define CCRCOMPIO 0x5804
+#define CCDLLTXCTL 0x5808
+#define CCDLLRXCTL 0x580C
+#define CCMDLLCTL 0x5810
+#define CCRCOMPODT 0x5814
+#define CCDLLPICODER0 0x5820
+#define CCDLLPICODER1 0x5824
+#define CCDDR3RESETCTL 0x5830
+#define CCCFGREG0 0x5838
+#define CCCFGREG1 0x5840
+#define CCPTRREG 0x5844
+#define CCCLKALIGNREG0 0x5850
+#define CCCLKALIGNREG1 0x5854
+#define CCCLKALIGNREG2 0x5858
+#define CCPMCONFIG0 0x585C
+#define CCPMDLYREG0 0x5860
+#define CCPMDLYREG1 0x5864
+#define CCPMDLYREG2 0x5868
+#define CCPMDLYREG3 0x586C
+#define CCPMDLYREG4 0x5870
+#define CCCLKALIGNSTS0 0x5874
+#define CCCLKALIGNSTS1 0x5878
+#define CCPMSTS0 0x587C
+#define CCPMSTS1 0x5880
+#define CCCOMPSLV1 0x5884
+#define CCCOMPSLV2 0x5888
+#define CCCOMPSLV3 0x588C
+#define CCBONUS0 0x5894
+#define CCBONUS1 0x5898
+#define CCVISALANECR0 0x589C
+#define CCVISALANECR1 0x58A0
+#define CCVISACONTROLCR 0x58A4
+#define CCCLKGATE 0x58A8
+#define CCTIMINGCTL 0x58AC
+// COMP
+#define CMPCTRL 0x6800
+#define SOFTRSTCNTL 0x6804
+#define MSCNTR 0x6808
+#define NMSCNTRL 0x680C
+#define LATCH1CTL 0x6814
+#define COMPVISALANECR0 0x681C
+#define COMPVISALANECR1 0x6820
+#define COMPVISACONTROLCR 0x6824
+#define COMPBONUS0 0x6830
+#define TCOCNTCTRL 0x683C
+#define DQANAODTPUCTL 0x6840
+#define DQANAODTPDCTL 0x6844
+#define DQANADRVPUCTL 0x6848
+#define DQANADRVPDCTL 0x684C
+#define DQANADLYPUCTL 0x6850
+#define DQANADLYPDCTL 0x6854
+#define DQANATCOPUCTL 0x6858
+#define DQANATCOPDCTL 0x685C
+#define CMDANADRVPUCTL 0x6868
+#define CMDANADRVPDCTL 0x686C
+#define CMDANADLYPUCTL 0x6870
+#define CMDANADLYPDCTL 0x6874
+#define CLKANAODTPUCTL 0x6880
+#define CLKANAODTPDCTL 0x6884
+#define CLKANADRVPUCTL 0x6888
+#define CLKANADRVPDCTL 0x688C
+#define CLKANADLYPUCTL 0x6890
+#define CLKANADLYPDCTL 0x6894
+#define CLKANATCOPUCTL 0x6898
+#define CLKANATCOPDCTL 0x689C
+#define DQSANAODTPUCTL 0x68A0
+#define DQSANAODTPDCTL 0x68A4
+#define DQSANADRVPUCTL 0x68A8
+#define DQSANADRVPDCTL 0x68AC
+#define DQSANADLYPUCTL 0x68B0
+#define DQSANADLYPDCTL 0x68B4
+#define DQSANATCOPUCTL 0x68B8
+#define DQSANATCOPDCTL 0x68BC
+#define CTLANADRVPUCTL 0x68C8
+#define CTLANADRVPDCTL 0x68CC
+#define CTLANADLYPUCTL 0x68D0
+#define CTLANADLYPDCTL 0x68D4
+#define CHNLBUFSTATIC 0x68F0
+#define COMPOBSCNTRL 0x68F4
+#define COMPBUFFDBG0 0x68F8
+#define COMPBUFFDBG1 0x68FC
+#define CFGMISCCH0 0x6900
+#define COMPEN0CH0 0x6904
+#define COMPEN1CH0 0x6908
+#define COMPEN2CH0 0x690C
+#define STATLEGEN0CH0 0x6910
+#define STATLEGEN1CH0 0x6914
+#define DQVREFCH0 0x6918
+#define CMDVREFCH0 0x691C
+#define CLKVREFCH0 0x6920
+#define DQSVREFCH0 0x6924
+#define CTLVREFCH0 0x6928
+#define TCOVREFCH0 0x692C
+#define DLYSELCH0 0x6930
+#define TCODRAMBUFODTCH0 0x6934
+#define CCBUFODTCH0 0x6938
+#define RXOFFSETCH0 0x693C
+#define DQODTPUCTLCH0 0x6940
+#define DQODTPDCTLCH0 0x6944
+#define DQDRVPUCTLCH0 0x6948
+#define DQDRVPDCTLCH0 0x694C
+#define DQDLYPUCTLCH0 0x6950
+#define DQDLYPDCTLCH0 0x6954
+#define DQTCOPUCTLCH0 0x6958
+#define DQTCOPDCTLCH0 0x695C
+#define CMDDRVPUCTLCH0 0x6968
+#define CMDDRVPDCTLCH0 0x696C
+#define CMDDLYPUCTLCH0 0x6970
+#define CMDDLYPDCTLCH0 0x6974
+#define CLKODTPUCTLCH0 0x6980
+#define CLKODTPDCTLCH0 0x6984
+#define CLKDRVPUCTLCH0 0x6988
+#define CLKDRVPDCTLCH0 0x698C
+#define CLKDLYPUCTLCH0 0x6990
+#define CLKDLYPDCTLCH0 0x6994
+#define CLKTCOPUCTLCH0 0x6998
+#define CLKTCOPDCTLCH0 0x699C
+#define DQSODTPUCTLCH0 0x69A0
+#define DQSODTPDCTLCH0 0x69A4
+#define DQSDRVPUCTLCH0 0x69A8
+#define DQSDRVPDCTLCH0 0x69AC
+#define DQSDLYPUCTLCH0 0x69B0
+#define DQSDLYPDCTLCH0 0x69B4
+#define DQSTCOPUCTLCH0 0x69B8
+#define DQSTCOPDCTLCH0 0x69BC
+#define CTLDRVPUCTLCH0 0x69C8
+#define CTLDRVPDCTLCH0 0x69CC
+#define CTLDLYPUCTLCH0 0x69D0
+#define CTLDLYPDCTLCH0 0x69D4
+#define FNLUPDTCTLCH0 0x69F0
+// PLL
+#define MPLLCTRL0 0x7800
+#define MPLLCTRL1 0x7808
+#define MPLLCSR0 0x7810
+#define MPLLCSR1 0x7814
+#define MPLLCSR2 0x7820
+#define MPLLDFT 0x7828
+#define MPLLMON0CTL 0x7830
+#define MPLLMON1CTL 0x7838
+#define MPLLMON2CTL 0x783C
+#define SFRTRIM 0x7850
+#define MPLLDFTOUT0 0x7858
+#define MPLLDFTOUT1 0x785C
+#define MASTERRSTN 0x7880
+#define PLLLOCKDEL 0x7884
+#define SFRDEL 0x7888
+#define CRUVISALANECR0 0x78F0
+#define CRUVISALANECR1 0x78F4
+#define CRUVISACONTROLCR 0x78F8
+#define IOSFVISALANECR0 0x78FC
+#define IOSFVISALANECR1 0x7900
+#define IOSFVISACONTROLCR 0x7904
+
+//
+// END DDRIO registers
+//
+////
+
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h
new file mode 100644
index 0000000000..c5f92b3b5d
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/general_definitions.h
@@ -0,0 +1,90 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+#ifndef __GENERAL_DEFINITIONS_H
+#define __GENERAL_DEFINITIONS_H
+
+#undef BIT0
+#undef BIT1
+#undef BIT2
+#undef BIT3
+#undef BIT4
+#undef BIT5
+#undef BIT6
+#undef BIT7
+#undef BIT8
+#undef BIT9
+#undef BIT10
+#undef BIT11
+#undef BIT12
+#undef BIT13
+#undef BIT14
+#undef BIT15
+#undef BIT16
+#undef BIT17
+#undef BIT18
+#undef BIT19
+#undef BIT20
+#undef BIT21
+#undef BIT22
+#undef BIT23
+#undef BIT24
+#undef BIT25
+#undef BIT26
+#undef BIT27
+#undef BIT28
+#undef BIT29
+#undef BIT30
+#undef BIT31
+
+
+
+// defines
+#define BIT0 0x00000001U
+#define BIT1 0x00000002U
+#define BIT2 0x00000004U
+#define BIT3 0x00000008U
+#define BIT4 0x00000010U
+#define BIT5 0x00000020U
+#define BIT6 0x00000040U
+#define BIT7 0x00000080U
+#define BIT8 0x00000100U
+#define BIT9 0x00000200U
+#define BIT10 0x00000400U
+#define BIT11 0x00000800U
+#define BIT12 0x00001000U
+#define BIT13 0x00002000U
+#define BIT14 0x00004000U
+#define BIT15 0x00008000U
+#define BIT16 0x00010000U
+#define BIT17 0x00020000U
+#define BIT18 0x00040000U
+#define BIT19 0x00080000U
+#define BIT20 0x00100000U
+#define BIT21 0x00200000U
+#define BIT22 0x00400000U
+#define BIT23 0x00800000U
+#define BIT24 0x01000000U
+#define BIT25 0x02000000U
+#define BIT26 0x04000000U
+#define BIT27 0x08000000U
+#define BIT28 0x10000000U
+#define BIT29 0x20000000U
+#define BIT30 0x40000000U
+#define BIT31 0x80000000U
+
+
+#define true 0x01
+#define false 0x00
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c
new file mode 100644
index 0000000000..92ec4ba1f6
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.c
@@ -0,0 +1,542 @@
+/** @file
+HTE handling routines for MRC use.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "mrc.h"
+#include "memory_options.h"
+#include "io.h"
+
+#include "hte.h"
+
+
+#ifdef SIM
+VOID delay_n(UINT32 nanoseconds);
+#define MySimStall(a) delay_n(a/1000)
+#endif
+
+STATIC VOID EnableAllHteErrors(
+ UINT8 Mask)
+/*++
+
+ Routine Description:
+
+ This function enables to HTE to detect all possible errors for
+ the given training parameters (per-bit or full byte lane).
+
+ Returns:
+
+ None
+
+ --*/
+{
+ isbW32m(HTE, 0x000200A2, 0xFFFFFFFF);
+ isbW32m(HTE, 0x000200A3, 0x000000FF);
+ isbW32m(HTE, 0x000200A4, 0x00000000);
+}
+
+STATIC UINT32 CheckHteErrors(
+ VOID)
+/*++
+
+ Routine Description:
+
+ This function goes and reads the HTE register in order to find any error
+
+ Returns:
+
+ The errors detected in the HTE status register
+
+ --*/
+{
+ return isbR32m(HTE, 0x000200A7);
+}
+
+STATIC VOID WaitForHteComplete(
+ VOID)
+/*++
+
+ Routine Description:
+
+ This function waits until HTE finishes
+
+ Returns:
+
+ None
+
+ --*/
+{
+ UINT32 Tmp;
+
+ ENTERFN();
+
+ //
+ // Is the test done?
+ //
+ do
+ {
+#ifdef SIM
+ MySimStall (35000); // 35 ns delay
+#endif
+ } while (0 != (isbR32m(HTE, 0x00020012) & BIT30));
+
+ Tmp = isbR32m(HTE, 0x00020011);
+ Tmp = Tmp | BIT9;
+ Tmp = Tmp & ~(BIT13 | BIT12);
+ isbW32m(HTE, 0x00020011, Tmp);
+
+ LEAVEFN();
+}
+
+STATIC VOID ClearHteErrorRegisters(
+ VOID)
+/*++
+
+ Routine Description:
+
+ Clears registers related with errors in the HTE.
+
+ Returns:
+
+ None
+
+ --*/
+{
+ UINT32 Tmp;
+
+ //
+ // Clear all HTE errors and enable error checking
+ // for burst and chunk.
+ //
+ Tmp = isbR32m(HTE, 0x000200A1);
+ Tmp |= BIT8;
+ isbW32m(HTE, 0x000200A1, Tmp);
+}
+
+UINT32 HteMemInit(
+ MRC_PARAMS *CurrentMrcData,
+ UINT8 MemInitFlag,
+ UINT8 HaltHteEngineOnError)
+
+/*++
+
+ Routine Description:
+
+ Uses HW HTE engine to initialize or test all memory attached to a given DUNIT.
+ If MemInitFlag is 1, this routine writes 0s to all memory locations to initialize
+ ECC.
+ If MemInitFlag is 0, this routine will send an 5AA55AA5 pattern to all memory
+ locations on the RankMask and then read it back. Then it sends an A55AA55A
+ pattern to all memory locations on the RankMask and reads it back.
+
+ Arguments:
+
+ CurrentMrcData: Host struture for all MRC global data.
+ MemInitFlag: 0 for memtest, 1 for meminit.
+ HaltHteEngineOnError: Halt the HTE engine on first error observed, or keep
+ running to see how many errors are found.
+
+ Returns:
+ Errors register showing HTE failures.
+ Also prints out which rank failed the HTE test if failure occurs.
+ For rank detection to work, the address map must be left in its default
+ state. If MRC changes the address map, this function must be modified
+ to change it back to default at the beginning, then restore it at the end.
+
+ --*/
+{
+ UINT32 Offset;
+ UINT8 TestNum;
+ UINT8 i;
+
+ //
+ // Clear out the error registers at the start of each memory
+ // init or memory test run.
+ //
+ ClearHteErrorRegisters();
+
+ isbW32m(HTE, 0x00020062, 0x00000015);
+
+ for (Offset = 0x80; Offset <= 0x8F; Offset++)
+ {
+ isbW32m(HTE, Offset, ((Offset & 1) ? 0xA55A : 0x5AA5));
+ }
+
+ isbW32m(HTE, 0x00020021, 0x00000000);
+#ifdef QUICKSIM
+ // Just do 4 cache lines for simulation memtest to save time.
+ isbW32m(HTE, 0x00020022, 4-1);
+#else
+ isbW32m(HTE, 0x00020022, (CurrentMrcData->mem_size >> 6) - 1);
+#endif
+
+ isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
+ isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
+ isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
+ isbW32m(HTE, 0x00020066, 0x03000000);
+
+ switch (MemInitFlag)
+ {
+ case MrcMemInit:
+ TestNum = 1; // Only 1 write pass through memory is needed to initialize ECC.
+ break;
+ case MrcMemTest:
+ TestNum = 4; // Write/read then write/read with inverted pattern.
+ break;
+ default:
+ DPF(D_INFO, "Unknown parameter for MemInitFlag: %d\n", MemInitFlag);
+ return 0xFFFFFFFF;
+ break;
+ }
+
+ DPF(D_INFO, "HteMemInit");
+ for (i = 0; i < TestNum; i++)
+ {
+ DPF(D_INFO, ".");
+
+ if (i == 0)
+ {
+ isbW32m(HTE, 0x00020061, 0x00000000);
+ isbW32m(HTE, 0x00020020, 0x00110010);
+ }
+ else if (i == 1)
+ {
+ isbW32m(HTE, 0x00020061, 0x00000000);
+ isbW32m(HTE, 0x00020020, 0x00010010);
+ }
+ else if (i == 2)
+ {
+ isbW32m(HTE, 0x00020061, 0x00010100);
+ isbW32m(HTE, 0x00020020, 0x00110010);
+ }
+ else
+ {
+ isbW32m(HTE, 0x00020061, 0x00010100);
+ isbW32m(HTE, 0x00020020, 0x00010010);
+ }
+
+ isbW32m(HTE, 0x00020011, 0x00111000);
+ isbW32m(HTE, 0x00020011, 0x00111100);
+
+ WaitForHteComplete();
+
+ //
+ // If this is a READ pass, check for errors at the end.
+ //
+ if ((i % 2) == 1)
+ {
+ //
+ // Return immediately if error.
+ //
+ if (CheckHteErrors())
+ {
+ break;
+ }
+ }
+ }
+
+ DPF(D_INFO, "done\n", i);
+ return CheckHteErrors();
+}
+
+STATIC UINT16 BasicDataCompareHte(
+ MRC_PARAMS *CurrentMrcData,
+ UINT32 Address,
+ UINT8 FirstRun,
+ UINT8 Mode)
+/*++
+
+ Routine Description:
+
+ Execute basic single cache line memory write/read/verify test using simple constant
+ pattern (different for READ_RAIN and WRITE_TRAIN modes.
+ See BasicWriteReadHTE which is external visible wrapper.
+
+ Arguments:
+
+ CurrentMrcData: Host struture for all MRC global data.
+ Address: memory adress being tested (must hit specific channel/rank)
+ FirstRun: If set then hte registers are configured, otherwise
+ it is assumed configuration is done and just re-run the test.
+ Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)
+
+ Returns:
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)
+
+ --*/
+{
+ UINT32 Pattern;
+ UINT32 Offset;
+
+ if (FirstRun)
+ {
+ isbW32m(HTE, 0x00020020, 0x01B10021);
+ isbW32m(HTE, 0x00020021, 0x06000000);
+ isbW32m(HTE, 0x00020022, Address >> 6);
+ isbW32m(HTE, 0x00020062, 0x00800015);
+ isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
+ isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
+ isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
+ isbW32m(HTE, 0x00020061, 0x00030008);
+
+ if (Mode == WRITE_TRAIN)
+ {
+ Pattern = 0xC33C0000;
+ }
+ else // READ_TRAIN
+ {
+ Pattern = 0xAA5555AA;
+ }
+
+ for (Offset = 0x80; Offset <= 0x8F; Offset++)
+ {
+ isbW32m(HTE, Offset, Pattern);
+ }
+ }
+
+ isbW32m(HTE, 0x000200A1, 0xFFFF1000);
+
+ isbW32m(HTE, 0x00020011, 0x00011000);
+ isbW32m(HTE, 0x00020011, 0x00011100);
+
+ WaitForHteComplete();
+
+ //
+ // Return bits 15:8 of HTE_CH0_ERR_XSTAT to check for any bytelane errors.
+ //
+ return ((CheckHteErrors() >> 8) & 0xFF);
+}
+
+STATIC UINT16 ReadWriteDataCompareHte(
+ MRC_PARAMS *CurrentMrcData,
+ UINT32 Address,
+ UINT8 LoopCount,
+ UINT32 LfsrSeedVictim,
+ UINT32 LfsrSeedAggressor,
+ UINT8 VictimBit,
+ UINT8 FirstRun)
+/*++
+
+ Routine Description:
+
+ Examines single cache line memory with write/read/verify test using
+ multiple data patterns (victim-aggressor algorithm).
+ See WriteStressBitLanesHTE which is external visible wrapper.
+
+ Arguments:
+
+ CurrentMrcData: host struture for all MRC global data.
+ Address: memory adress being tested (must hit specific channel/rank)
+ LoopCount: number of test iterations
+ LfsrSeedXxx: victim aggressor data pattern seed
+ VictimBit: should be 0 as auto rotate feature is in use.
+ FirstRun: If set then hte registers are configured, otherwise
+ it is assumed configuration is done and just re-run the test.
+
+ Returns:
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)
+
+ --*/
+{
+ UINT32 Offset;
+ UINT32 Tmp;
+
+ if (FirstRun)
+ {
+ isbW32m(HTE, 0x00020020, 0x00910024);
+ isbW32m(HTE, 0x00020023, 0x00810024);
+ isbW32m(HTE, 0x00020021, 0x06070000);
+ isbW32m(HTE, 0x00020024, 0x06070000);
+ isbW32m(HTE, 0x00020022, Address >> 6);
+ isbW32m(HTE, 0x00020025, Address >> 6);
+ isbW32m(HTE, 0x00020062, 0x0000002A);
+ isbW32m(HTE, 0x00020063, LfsrSeedVictim);
+ isbW32m(HTE, 0x00020064, LfsrSeedAggressor);
+ isbW32m(HTE, 0x00020065, LfsrSeedVictim);
+
+ //
+ // Write the pattern buffers to select the victim bit. Start with bit0.
+ //
+ for (Offset = 0x80; Offset <= 0x8F; Offset++)
+ {
+ if ((Offset % 8) == VictimBit)
+ {
+ isbW32m(HTE, Offset, 0x55555555);
+ }
+ else
+ {
+ isbW32m(HTE, Offset, 0xCCCCCCCC);
+ }
+ }
+
+ isbW32m(HTE, 0x00020061, 0x00000000);
+ isbW32m(HTE, 0x00020066, 0x03440000);
+ isbW32m(HTE, 0x000200A1, 0xFFFF1000);
+ }
+
+ Tmp = 0x10001000 | (LoopCount << 16);
+ isbW32m(HTE, 0x00020011, Tmp);
+ isbW32m(HTE, 0x00020011, Tmp | BIT8);
+
+ WaitForHteComplete();
+
+ return (CheckHteErrors() >> 8) & 0xFF;
+}
+
+UINT16 BasicWriteReadHTE(
+ MRC_PARAMS *CurrentMrcData,
+ UINT32 Address,
+ UINT8 FirstRun,
+ UINT8 Mode)
+/*++
+
+ Routine Description:
+
+ Execute basic single cache line memory write/read/verify test using simple constant
+ pattern (different for READ_RAIN and WRITE_TRAIN modes.
+
+ Arguments:
+
+ CurrentMrcData: Host struture for all MRC global data.
+ Address: memory adress being tested (must hit specific channel/rank)
+ FirstRun: If set then hte registers are configured, otherwise
+ it is assumed configuration is done and just re-run the test.
+ Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)
+
+ Returns:
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)
+
+ --*/
+{
+ UINT16 ByteLaneErrors;
+
+ ENTERFN();
+
+ //
+ // Enable all error reporting in preparation for HTE test.
+ //
+ EnableAllHteErrors(0xFF);
+ ClearHteErrorRegisters();
+
+ ByteLaneErrors = BasicDataCompareHte(CurrentMrcData, Address, FirstRun,
+ Mode);
+
+ LEAVEFN();
+ return ByteLaneErrors;
+}
+
+UINT16 WriteStressBitLanesHTE(
+ MRC_PARAMS *CurrentMrcData,
+ UINT32 Address,
+ UINT8 FirstRun)
+/*++
+
+ Routine Description:
+
+ Examines single cache line memory with write/read/verify test using
+ multiple data patterns (victim-aggressor algorithm).
+
+ Arguments:
+
+ CurrentMrcData: host struture for all MRC global data.
+ Address: memory adress being tested (must hit specific channel/rank)
+ FirstRun: If set then hte registers are configured, otherwise
+ it is assumed configuration is done and just re-run the test.
+
+ Returns:
+ Returns byte lane failure on each bit (for Quark only bit0 and bit1)
+
+ --*/
+{
+ UINT16 ByteLaneErrors;
+ UINT8 VictimBit = 0;
+
+ ENTERFN();
+
+ //
+ // Enable all error reporting in preparation for HTE test.
+ //
+ EnableAllHteErrors(0xFF);
+ ClearHteErrorRegisters();
+
+ //
+ // Loop through each bit in the bytelane. Each pass creates a victim bit
+ // while keeping all other bits the same - as aggressors.
+ // AVN HTE adds an auto-rotate feature which allows us to program the entire victim/aggressor
+ // sequence in 1 step. The victim bit rotates on each pass so no need to have software implement
+ // a victim bit loop like on VLV.
+ //
+ ByteLaneErrors = ReadWriteDataCompareHte(CurrentMrcData, Address,
+ HTE_LOOP_CNT, HTE_LFSR_VICTIM_SEED, HTE_LFSR_AGRESSOR_SEED, VictimBit,
+ FirstRun);
+
+ LEAVEFN();
+ return ByteLaneErrors;
+}
+
+VOID HteMemOp(
+ UINT32 Address,
+ UINT8 FirstRun,
+ UINT8 IsWrite)
+/*++
+
+ Routine Description:
+
+ Execute basic single cache line memory write or read.
+ This is just for receive enable / fine write levelling purpose.
+
+ Arguments:
+
+ CurrentMrcData: Host structure for all MRC global data.
+ Address: memory address used (must hit specific channel/rank)
+ FirstRun: If set then hte registers are configured, otherwise
+ it is assumed configuration is done and just re-run the test.
+ IsWrite: When non-zero memory write operation executed, otherwise read
+
+ Returns:
+ None
+
+ --*/
+{
+ UINT32 Offset;
+ UINT32 Tmp;
+
+ EnableAllHteErrors(0xFF);
+ ClearHteErrorRegisters();
+
+ if (FirstRun)
+ {
+ Tmp = IsWrite ? 0x01110021 : 0x01010021;
+ isbW32m(HTE, 0x00020020, Tmp);
+
+ isbW32m(HTE, 0x00020021, 0x06000000);
+ isbW32m(HTE, 0x00020022, Address >> 6);
+ isbW32m(HTE, 0x00020062, 0x00800015);
+ isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
+ isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
+ isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
+ isbW32m(HTE, 0x00020061, 0x00030008);
+
+ for (Offset = 0x80; Offset <= 0x8F; Offset++)
+ {
+ isbW32m(HTE, Offset, 0xC33C0000);
+ }
+ }
+
+ isbW32m(HTE, 0x000200A1, 0xFFFF1000);
+ isbW32m(HTE, 0x00020011, 0x00011000);
+ isbW32m(HTE, 0x00020011, 0x00011100);
+
+ WaitForHteComplete();
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h
new file mode 100644
index 0000000000..eeb6192ca0
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/hte.h
@@ -0,0 +1,72 @@
+/** @file
+HTE handling routines for MRC use.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef __HTE_H
+#define __HTE_H
+
+#define STATIC static
+#define VOID void
+
+#if !defined(__GNUC__) && (__STDC_VERSION__ < 199901L)
+typedef uint32_t UINT32;
+typedef uint16_t UINT16;
+typedef uint8_t UINT8;
+#endif
+
+typedef enum
+{
+ MrcNoHaltSystemOnError,
+ MrcHaltSystemOnError,
+ MrcHaltHteEngineOnError,
+ MrcNoHaltHteEngineOnError
+} HALT_TYPE;
+
+typedef enum
+{
+ MrcMemInit, MrcMemTest
+} MEM_INIT_OR_TEST;
+
+#define READ_TRAIN 1
+#define WRITE_TRAIN 2
+
+#define HTE_MEMTEST_NUM 2
+#define HTE_LOOP_CNT 5 // EXP_LOOP_CNT field of HTE_CMD_CTL. This CANNOT be less than 4
+#define HTE_LFSR_VICTIM_SEED 0xF294BA21 // Random seed for victim.
+#define HTE_LFSR_AGRESSOR_SEED 0xEBA7492D // Random seed for aggressor.
+UINT32
+HteMemInit(
+ MRC_PARAMS *CurrentMrcData,
+ UINT8 MemInitFlag,
+ UINT8 HaltHteEngineOnError);
+
+UINT16
+BasicWriteReadHTE(
+ MRC_PARAMS *CurrentMrcData,
+ UINT32 Address,
+ UINT8 FirstRun,
+ UINT8 Mode);
+
+UINT16
+WriteStressBitLanesHTE(
+ MRC_PARAMS *CurrentMrcData,
+ UINT32 Address,
+ UINT8 FirstRun);
+
+VOID
+HteMemOp(
+ UINT32 Address,
+ UINT8 FirstRun,
+ UINT8 IsWrite);
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h
new file mode 100644
index 0000000000..7419c593dc
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/io.h
@@ -0,0 +1,138 @@
+/** @file
+Declaration of IO handling routines.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef __IO_H
+#define __IO_H
+
+#include "core_types.h"
+
+#include "general_definitions.h"
+#include "gen5_iosf_sb_definitions.h"
+
+// Instruction not present on Quark
+#define SFENCE()
+
+#define DEAD_LOOP() for(;;);
+
+////
+// Define each of the IOSF_SB ports used by MRC
+//
+
+//
+// Has to be 0 because of emulation static data
+// initialisation:
+// Space_t EmuSpace[ SPACE_COUNT] = {0};
+//
+#define FREE 0x000
+
+// Pseudo side-band ports for access abstraction
+// See Wr32/Rd32 functions
+#define MEM 0x101
+#define MMIO 0x102
+#define DCMD 0x0A0
+
+// Real side-band ports
+// See Wr32/Rd32 functions
+#define MCU 0x001
+#define HOST_BRIDGE 0x003
+#define MEMORY_MANAGER 0x005
+#define HTE 0x011
+#define DDRPHY 0x012
+#define FUSE 0x033
+
+// End of IOSF_SB ports
+////
+
+// Pciexbar address
+#define EC_BASE 0xE0000000
+
+#define PCIADDR(bus,dev,fn,reg) ( \
+ (EC_BASE) + \
+ ((bus) << 20) + \
+ ((dev) << 15) + \
+ ((fn) << 12) + \
+ (reg))
+
+// Various offsets used in the building sideband commands.
+#define SB_OPCODE_OFFSET 24
+#define SB_PORT_OFFSET 16
+#define SB_REG_OFFEST 8
+
+// Sideband opcodes
+#define SB_REG_READ_OPCODE 0x10
+#define SB_REG_WRITE_OPCODE 0x11
+
+#define SB_FUSE_REG_READ_OPCODE 0x06
+#define SB_FUSE_REG_WRITE_OPCODE 0x07
+
+#define SB_DDRIO_REG_READ_OPCODE 0x06
+#define SB_DDRIO_REG_WRITE_OPCODE 0x07
+
+#define SB_DRAM_CMND_OPCODE 0x68
+#define SB_WAKE_CMND_OPCODE 0xCA
+#define SB_SUSPEND_CMND_OPCODE 0xCC
+
+// Register addresses for sideband command and data.
+#define SB_PACKET_REG 0x00D0
+#define SB_DATA_REG 0x00D4
+#define SB_HADR_REG 0x00D8
+
+// We always flag all 4 bytes in the register reads/writes as required.
+#define SB_ALL_BYTES_ENABLED 0xF0
+
+#define SB_COMMAND(Opcode, Port, Reg) \
+ ((Opcode << SB_OPCODE_OFFSET) | \
+ (Port << SB_PORT_OFFSET) | \
+ (Reg << SB_REG_OFFEST) | \
+ SB_ALL_BYTES_ENABLED)
+
+// iosf
+#define isbM32m WrMask32
+#define isbW32m Wr32
+#define isbR32m Rd32
+
+// pci
+
+void pciwrite32(
+ uint32_t bus,
+ uint32_t dev,
+ uint32_t fn,
+ uint32_t reg,
+ uint32_t data);
+
+uint32_t pciread32(
+ uint32_t bus,
+ uint32_t dev,
+ uint32_t fn,
+ uint32_t reg);
+
+// general
+
+uint32_t Rd32(
+ uint32_t unit,
+ uint32_t addr);
+
+void Wr32(
+ uint32_t unit,
+ uint32_t addr,
+ uint32_t data);
+
+void WrMask32(
+ uint32_t unit,
+ uint32_t addr,
+ uint32_t data,
+ uint32_t mask);
+
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c
new file mode 100644
index 0000000000..f77db8b78b
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/lprint.c
@@ -0,0 +1,388 @@
+/** @file
+Serial conole output and string formating.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "memory_options.h"
+#include "general_definitions.h"
+
+// Resource programmed to PCI bridge, 1MB bound alignment is needed.
+// The default value is overwritten by MRC parameter, assuming code
+// relocated to eSRAM.
+uint32_t UartMmioBase = 0;
+
+// Serial port registers based on SerialPortLib.c
+#define R_UART_BAUD_THR 0
+#define R_UART_LSR 20
+
+#define B_UART_LSR_RXRDY BIT0
+#define B_UART_LSR_TXRDY BIT5
+#define B_UART_LSR_TEMT BIT6
+
+// Print mask see DPF and D_Xxxx
+#define DPF_MASK DpfPrintMask
+
+// Select class of messages enabled for printing
+uint32_t DpfPrintMask =
+ D_ERROR |
+ D_INFO |
+ // D_REGRD |
+ // D_REGWR |
+ // D_FCALL |
+ // D_TRN |
+ 0;
+
+#ifdef NDEBUG
+// Don't generate debug code
+void dpf( uint32_t mask, char_t* bla, ...)
+{
+ return;
+}
+
+uint8_t mgetc(void)
+{
+ return 0;
+}
+
+uint8_t mgetch(void)
+{
+ return 0;
+}
+
+#else
+
+#ifdef SIM
+// Use Vpi console in simulation environment
+#include <vpi_user.h>
+
+void dpf( uint32_t mask, char_t* bla, ...)
+{
+ va_list va;
+
+ if( 0 == (mask & DPF_MASK)) return;
+
+ va_start( va, bla);
+ vpi_vprintf( bla, va);
+ va_end(va);
+}
+
+#else
+
+#ifdef EMU
+// Use standard console in windows environment
+#include <stdio.h>
+#endif
+
+// Read character from serial port
+uint8_t mgetc(void)
+{
+#ifdef EMU
+
+ // Emulation in Windows environment uses console
+ getchar();
+
+#else
+ uint8_t c;
+
+ while ((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) == 0);
+ c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);
+
+ return c;
+#endif
+}
+
+
+uint8_t mgetch(void)
+{
+#ifdef EMU
+ return 0;
+#else
+ uint8_t c = 0;
+
+ if((*(volatile uint8_t*) (UartMmioBase + R_UART_LSR) & B_UART_LSR_RXRDY) != 0)
+ {
+ c = *(volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR);
+ }
+
+ return c;
+#endif
+}
+
+// Print single character
+static void printc(
+ uint8_t c)
+{
+#ifdef EMU
+
+ // Emulation in Windows environment uses console output
+ putchar(c);
+
+#else
+
+ //
+ // Use MMIO access to serial port on PCI
+ // while( 0 == (0x20 & inp(0x3f8 + 5)));
+ // outp(0x3f8 + 0, c);
+ //
+ while (0
+ == (B_UART_LSR_TEMT & *((volatile uint8_t*) (UartMmioBase + R_UART_LSR))))
+ ;
+ *((volatile uint8_t*) (UartMmioBase + R_UART_BAUD_THR)) = c;
+#endif
+}
+
+// Print 0 terminated string on serial console
+static void printstr(
+ char_t *str)
+{
+ while (*str)
+ {
+ printc(*str++);
+ }
+}
+// Print 64bit number as hex string on serial console
+// the width parameters allows skipping leading zeros
+static void printhexx(
+ uint64_t val,
+ uint32_t width)
+{
+ uint32_t i;
+ uint8_t c;
+ uint8_t empty = 1;
+
+ // 64bit number has 16 characters in hex representation
+ for (i = 16; i > 0; i--)
+ {
+ c = *(((uint8_t *)&val) + ((i - 1) >> 1));
+ if (((i - 1) & 1) != 0)
+ c = c >> 4;
+ c = c & 0x0F;
+
+ if (c > 9)
+ c += 'A' - 10;
+ else
+ c += '0';
+
+ if (c != '0')
+ {
+ // end of leading zeros
+ empty = 0;
+ }
+
+ // don't print leading zero
+ if (!empty || i <= width)
+ {
+ printc(c);
+ }
+ }
+}
+// Print 32bit number as hex string on serial console
+// the width parameters allows skipping leading zeros
+static void printhex(
+ uint32_t val,
+ uint32_t width)
+{
+ uint32_t i;
+ uint8_t c;
+ uint8_t empty = 1;
+
+ // 32bit number has 8 characters in hex representation
+ for (i = 8; i > 0; i--)
+ {
+ c = (uint8_t) ((val >> 28) & 0x0F);
+ if (c > 9)
+ c += 'A' - 10;
+ else
+ c += '0';
+
+ val = val << 4;
+
+ if (c != '0')
+ {
+ // end of leading zeros
+ empty = 0;
+ }
+
+ // don't print leading zero
+ if (!empty || i <= width)
+ {
+ printc(c);
+ }
+ }
+}
+// Print 32bit number as decimal string on serial console
+// the width parameters allows skipping leading zeros
+static void printdec(
+ uint32_t val,
+ uint32_t width)
+{
+ uint32_t i;
+ uint8_t c = 0;
+ uint8_t empty = 1;
+
+ // Ten digits is enough for 32bit number in decimal
+ uint8_t buf[10];
+
+ for (i = 0; i < sizeof(buf); i++)
+ {
+ c = (uint8_t) (val % 10);
+ buf[i] = c + '0';
+ val = val / 10;
+ }
+
+ while (i > 0)
+ {
+ c = buf[--i];
+
+ if (c != '0')
+ {
+ // end of leading zeros
+ empty = 0;
+ }
+
+ // don't print leading zero
+ if (!empty || i < width)
+ {
+ printc(c);
+ }
+ }
+}
+
+// Consume numeric substring leading the given string
+// Return pointer to the first non-numeric character
+// Buffer reference by width is updated with number
+// converted from the numeric substring.
+static char_t *getwidth(
+ char_t *bla,
+ uint32_t *width)
+{
+ uint32_t val = 0;
+
+ while (*bla >= '0' && *bla <= '9')
+ {
+ val = val * 10 + *bla - '0';
+ bla += 1;
+ }
+
+ if (val > 0)
+ {
+ *width = val;
+ }
+ return bla;
+}
+
+// Consume print format designator from the head of given string
+// Return pointer to first character after format designator
+// input fmt
+// ----- ---
+// s -> s
+// d -> d
+// X -> X
+// llX -> L
+static char_t *getformat(
+ char_t *bla,
+ uint8_t *fmt)
+{
+ if (bla[0] == 's')
+ {
+ bla += 1;
+ *fmt = 's';
+ }
+ else if (bla[0] == 'd')
+ {
+ bla += 1;
+ *fmt = 'd';
+ }
+ else if (bla[0] == 'X' || bla[0] == 'x')
+ {
+ bla += 1;
+ *fmt = 'X';
+ }
+ else if (bla[0] == 'l' && bla[1] == 'l' && bla[2] == 'X')
+ {
+ bla += 3;
+ *fmt = 'L';
+ }
+
+ return bla;
+}
+
+// Simplified implementation of standard printf function
+// The output is directed to serial console. Only selected
+// class of messages is printed (mask has to match DpfPrintMask)
+// Supported print formats: %[n]s,%[n]d,%[n]X,,%[n]llX
+// The width is ignored for %s format.
+void dpf(
+ uint32_t mask,
+ char_t* bla,
+ ...)
+{
+ uint32_t* arg = (uint32_t*) (&bla + 1);
+
+ // Check UART MMIO base configured
+ if (0 == UartMmioBase)
+ return;
+
+ // Check event not masked
+ if (0 == (mask & DPF_MASK))
+ return;
+
+ for (;;)
+ {
+ uint8_t x = *bla++;
+ if (x == 0)
+ break;
+
+ if (x == '\n')
+ {
+ printc('\r');
+ printc('\n');
+ }
+ else if (x == '%')
+ {
+ uint8_t fmt = 0;
+ uint32_t width = 1;
+
+ bla = getwidth(bla, &width);
+ bla = getformat(bla, &fmt);
+
+ // Print value
+ if (fmt == 'd')
+ {
+ printdec(*arg, width);
+ arg += 1;
+ }
+ else if (fmt == 'X')
+ {
+ printhex(*arg, width);
+ arg += 1;
+ }
+ else if (fmt == 'L')
+ {
+ printhexx(*(uint64_t*) arg, width);
+ arg += 2;
+ }
+ else if (fmt == 's')
+ {
+ printstr(*(char**) arg);
+ arg += 1;
+ }
+ }
+ else
+ {
+ printc(x);
+ }
+ }
+}
+
+#endif //SIM
+#endif //NDEBUG
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c
new file mode 100644
index 0000000000..26c56e6037
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.c
@@ -0,0 +1,2645 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ * This file contains all of the Cat Mountain Memory Reference Code (MRC).
+ *
+ * These functions are generic and should work for any Cat Mountain config.
+ *
+ * MRC requires two data structures to be passed in which are initialised by "PreMemInit()".
+ *
+ * The basic flow is as follows:
+ * 01) Check for supported DDR speed configuration
+ * 02) Set up MEMORY_MANAGER buffer as pass-through (POR)
+ * 03) Set Channel Interleaving Mode and Channel Stride to the most aggressive setting possible
+ * 04) Set up the MCU logic
+ * 05) Set up the DDR_PHY logic
+ * 06) Initialise the DRAMs (JEDEC)
+ * 07) Perform the Receive Enable Calibration algorithm
+ * 08) Perform the Write Leveling algorithm
+ * 09) Perform the Read Training algorithm (includes internal Vref)
+ * 10) Perform the Write Training algorithm
+ * 11) Set Channel Interleaving Mode and Channel Stride to the desired settings
+ *
+ * Dunit configuration based on Valleyview MRC.
+ *
+ ***************************************************************************/
+
+#include "mrc.h"
+#include "memory_options.h"
+
+#include "meminit.h"
+#include "meminit_utils.h"
+#include "hte.h"
+#include "io.h"
+
+// Override ODT to off state if requested
+#define DRMC_DEFAULT (mrc_params->rd_odt_value==0?BIT12:0)
+
+
+// tRFC values (in picoseconds) per density
+const uint32_t tRFC[5] =
+{
+ 90000, // 512Mb
+ 110000, // 1Gb
+ 160000, // 2Gb
+ 300000, // 4Gb
+ 350000, // 8Gb
+ };
+
+// tCK clock period in picoseconds per speed index 800, 1066, 1333
+const uint32_t tCK[3] =
+{
+ 2500,
+ 1875,
+ 1500
+};
+
+#ifdef SIM
+// Select static timings specific to simulation environment
+#define PLATFORM_ID 0
+#else
+// Select static timings specific to ClantonPeek platform
+#define PLATFORM_ID 1
+#endif
+
+
+// Global variables
+const uint16_t ddr_wclk[] =
+ {193, 158};
+
+const uint16_t ddr_wctl[] =
+ { 1, 217};
+
+const uint16_t ddr_wcmd[] =
+ { 1, 220};
+
+
+#ifdef BACKUP_RCVN
+const uint16_t ddr_rcvn[] =
+ {129, 498};
+#endif // BACKUP_RCVN
+
+#ifdef BACKUP_WDQS
+const uint16_t ddr_wdqs[] =
+ { 65, 289};
+#endif // BACKUP_WDQS
+
+#ifdef BACKUP_RDQS
+const uint8_t ddr_rdqs[] =
+ { 32, 24};
+#endif // BACKUP_RDQS
+
+#ifdef BACKUP_WDQ
+const uint16_t ddr_wdq[] =
+ { 32, 257};
+#endif // BACKUP_WDQ
+
+
+
+// Select MEMORY_MANAGER as the source for PRI interface
+static void select_memory_manager(
+ MRCParams_t *mrc_params)
+{
+ RegDCO Dco;
+
+ ENTERFN();
+
+ Dco.raw = isbR32m(MCU, DCO);
+ Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER
+ isbW32m(MCU, DCO, Dco.raw);
+
+ LEAVEFN();
+}
+
+// Select HTE as the source for PRI interface
+void select_hte(
+ MRCParams_t *mrc_params)
+{
+ RegDCO Dco;
+
+ ENTERFN();
+
+ Dco.raw = isbR32m(MCU, DCO);
+ Dco.field.PMICTL = 1; //1 - PRI owned by HTE
+ isbW32m(MCU, DCO, Dco.raw);
+
+ LEAVEFN();
+}
+
+// Send DRAM command, data should be formated
+// using DCMD_Xxxx macro or emrsXCommand structure.
+static void dram_init_command(
+ uint32_t data)
+{
+ Wr32(DCMD, 0, data);
+}
+
+// Send DRAM wake command using special MCU side-band WAKE opcode
+static void dram_wake_command(
+ void)
+{
+ ENTERFN();
+
+ Wr32(MMIO, PCIADDR(0,0,0,SB_PACKET_REG),
+ (uint32_t) SB_COMMAND(SB_WAKE_CMND_OPCODE, MCU, 0));
+
+ LEAVEFN();
+}
+
+// Stop self refresh driven by MCU
+static void clear_self_refresh(
+ MRCParams_t *mrc_params)
+{
+ ENTERFN();
+
+ // clear the PMSTS Channel Self Refresh bits
+ isbM32m(MCU, PMSTS, BIT0, BIT0);
+
+ LEAVEFN();
+}
+
+// Configure MCU before jedec init sequence
+static void prog_decode_before_jedec(
+ MRCParams_t *mrc_params)
+{
+ RegDRP Drp;
+ RegDRCF Drfc;
+ RegDCAL Dcal;
+ RegDSCH Dsch;
+ RegDPMC0 Dpmc0;
+
+ ENTERFN();
+
+ // Disable power saving features
+ Dpmc0.raw = isbR32m(MCU, DPMC0);
+ Dpmc0.field.CLKGTDIS = 1;
+ Dpmc0.field.DISPWRDN = 1;
+ Dpmc0.field.DYNSREN = 0;
+ Dpmc0.field.PCLSTO = 0;
+ isbW32m(MCU, DPMC0, Dpmc0.raw);
+
+ // Disable out of order transactions
+ Dsch.raw = isbR32m(MCU, DSCH);
+ Dsch.field.OOODIS = 1;
+ Dsch.field.NEWBYPDIS = 1;
+ isbW32m(MCU, DSCH, Dsch.raw);
+
+ // Disable issuing the REF command
+ Drfc.raw = isbR32m(MCU, DRFC);
+ Drfc.field.tREFI = 0;
+ isbW32m(MCU, DRFC, Drfc.raw);
+
+ // Disable ZQ calibration short
+ Dcal.raw = isbR32m(MCU, DCAL);
+ Dcal.field.ZQCINT = 0;
+ Dcal.field.SRXZQCL = 0;
+ isbW32m(MCU, DCAL, Dcal.raw);
+
+ // Training performed in address mode 0, rank population has limited impact, however
+ // simulator complains if enabled non-existing rank.
+ Drp.raw = 0;
+ if (mrc_params->rank_enables & 1)
+ Drp.field.rank0Enabled = 1;
+ if (mrc_params->rank_enables & 2)
+ Drp.field.rank1Enabled = 1;
+ isbW32m(MCU, DRP, Drp.raw);
+
+ LEAVEFN();
+}
+
+// After Cold Reset, BIOS should set COLDWAKE bit to 1 before
+// sending the WAKE message to the Dunit.
+// For Standby Exit, or any other mode in which the DRAM is in
+// SR, this bit must be set to 0.
+static void perform_ddr_reset(
+ MRCParams_t *mrc_params)
+{
+ ENTERFN();
+
+ // Set COLDWAKE bit before sending the WAKE message
+ isbM32m(MCU, DRMC, BIT16, BIT16);
+
+ // Send wake command to DUNIT (MUST be done before JEDEC)
+ dram_wake_command();
+
+ // Set default value
+ isbW32m(MCU, DRMC, DRMC_DEFAULT);
+
+ LEAVEFN();
+}
+
+// Dunit Initialisation Complete.
+// Indicates that initialisation of the Dunit has completed.
+// Memory accesses are permitted and maintenance operation
+// begins. Until this bit is set to a 1, the memory controller will
+// not accept DRAM requests from the MEMORY_MANAGER or HTE.
+static void set_ddr_init_complete(
+ MRCParams_t *mrc_params)
+{
+ RegDCO Dco;
+
+ ENTERFN();
+
+ Dco.raw = isbR32m(MCU, DCO);
+ Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER
+ Dco.field.IC = 1; //1 - initialisation complete
+ isbW32m(MCU, DCO, Dco.raw);
+
+ LEAVEFN();
+}
+
+static void prog_page_ctrl(
+ MRCParams_t *mrc_params)
+{
+ RegDPMC0 Dpmc0;
+
+ ENTERFN();
+
+ Dpmc0.raw = isbR32m(MCU, DPMC0);
+
+ Dpmc0.field.PCLSTO = 0x4;
+ Dpmc0.field.PREAPWDEN = 1;
+
+ isbW32m(MCU, DPMC0, Dpmc0.raw);
+}
+
+// Configure MCU Power Management Control Register
+// and Scheduler Control Register.
+static void prog_ddr_control(
+ MRCParams_t *mrc_params)
+{
+ RegDSCH Dsch;
+ RegDPMC0 Dpmc0;
+
+ ENTERFN();
+
+ Dpmc0.raw = isbR32m(MCU, DPMC0);
+ Dsch.raw = isbR32m(MCU, DSCH);
+
+ Dpmc0.field.DISPWRDN = mrc_params->power_down_disable;
+ Dpmc0.field.CLKGTDIS = 0;
+ Dpmc0.field.PCLSTO = 4;
+ Dpmc0.field.PREAPWDEN = 1;
+
+ Dsch.field.OOODIS = 0;
+ Dsch.field.OOOST3DIS = 0;
+ Dsch.field.NEWBYPDIS = 0;
+
+ isbW32m(MCU, DSCH, Dsch.raw);
+ isbW32m(MCU, DPMC0, Dpmc0.raw);
+
+ // CMDTRIST = 2h - CMD/ADDR are tristated when no valid command
+ isbM32m(MCU, DPMC1, 2 << 4, BIT5|BIT4);
+
+ LEAVEFN();
+}
+
+// After training complete configure MCU Rank Population Register
+// specifying: ranks enabled, device width, density, address mode.
+static void prog_dra_drb(
+ MRCParams_t *mrc_params)
+{
+ RegDRP Drp;
+ RegDCO Dco;
+
+ ENTERFN();
+
+ Dco.raw = isbR32m(MCU, DCO);
+ Dco.field.IC = 0;
+ isbW32m(MCU, DCO, Dco.raw);
+
+ Drp.raw = 0;
+ if (mrc_params->rank_enables & 1)
+ Drp.field.rank0Enabled = 1;
+ if (mrc_params->rank_enables & 2)
+ Drp.field.rank1Enabled = 1;
+ if (mrc_params->dram_width == x16)
+ {
+ Drp.field.dimm0DevWidth = 1;
+ Drp.field.dimm1DevWidth = 1;
+ }
+ // Density encoding in DRAMParams_t 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb
+ // has to be mapped RANKDENSx encoding (0=1Gb)
+ Drp.field.dimm0DevDensity = mrc_params->params.DENSITY - 1;
+ Drp.field.dimm1DevDensity = mrc_params->params.DENSITY - 1;
+
+ // Address mode can be overwritten if ECC enabled
+ Drp.field.addressMap = mrc_params->address_mode;
+
+ isbW32m(MCU, DRP, Drp.raw);
+
+ Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER
+ Dco.field.IC = 1; //1 - initialisation complete
+ isbW32m(MCU, DCO, Dco.raw);
+
+ LEAVEFN();
+}
+
+// Configure refresh rate and short ZQ calibration interval.
+// Activate dynamic self refresh.
+static void change_refresh_period(
+ MRCParams_t *mrc_params)
+{
+ RegDRCF Drfc;
+ RegDCAL Dcal;
+ RegDPMC0 Dpmc0;
+
+ ENTERFN();
+
+ Drfc.raw = isbR32m(MCU, DRFC);
+ Drfc.field.tREFI = mrc_params->refresh_rate;
+ Drfc.field.REFDBTCLR = 1;
+ isbW32m(MCU, DRFC, Drfc.raw);
+
+ Dcal.raw = isbR32m(MCU, DCAL);
+ Dcal.field.ZQCINT = 3; // 63ms
+ isbW32m(MCU, DCAL, Dcal.raw);
+
+ Dpmc0.raw = isbR32m(MCU, DPMC0);
+ Dpmc0.field.ENPHYCLKGATE = 1;
+ Dpmc0.field.DYNSREN = 1;
+ isbW32m(MCU, DPMC0, Dpmc0.raw);
+
+ LEAVEFN();
+}
+
+// Send DRAM wake command
+static void perform_wake(
+ MRCParams_t *mrc_params)
+{
+ ENTERFN();
+
+ dram_wake_command();
+
+ LEAVEFN();
+}
+
+// prog_ddr_timing_control (aka mcu_init):
+// POST_CODE[major] == 0x02
+//
+// It will initialise timing registers in the MCU (DTR0..DTR4).
+static void prog_ddr_timing_control(
+ MRCParams_t *mrc_params)
+{
+ uint8_t TCL, WL;
+ uint8_t TRP, TRCD, TRAS, TRFC, TWR, TWTR, TRRD, TRTP, TFAW;
+ uint32_t TCK;
+
+ RegDTR0 Dtr0;
+ RegDTR1 Dtr1;
+ RegDTR2 Dtr2;
+ RegDTR3 Dtr3;
+ RegDTR4 Dtr4;
+
+ ENTERFN();
+
+ // mcu_init starts
+ post_code(0x02, 0x00);
+
+ Dtr0.raw = isbR32m(MCU, DTR0);
+ Dtr1.raw = isbR32m(MCU, DTR1);
+ Dtr2.raw = isbR32m(MCU, DTR2);
+ Dtr3.raw = isbR32m(MCU, DTR3);
+ Dtr4.raw = isbR32m(MCU, DTR4);
+
+ TCK = tCK[mrc_params->ddr_speed]; // Clock in picoseconds
+ TCL = mrc_params->params.tCL; // CAS latency in clocks
+ TRP = TCL; // Per CAT MRC
+ TRCD = TCL; // Per CAT MRC
+ TRAS = MCEIL(mrc_params->params.tRAS, TCK);
+ TRFC = MCEIL(tRFC[mrc_params->params.DENSITY], TCK);
+ TWR = MCEIL(15000, TCK); // Per JEDEC: tWR=15000ps DDR2/3 from 800-1600
+
+ TWTR = MCEIL(mrc_params->params.tWTR, TCK);
+ TRRD = MCEIL(mrc_params->params.tRRD, TCK);
+ TRTP = 4; // Valid for 800 and 1066, use 5 for 1333
+ TFAW = MCEIL(mrc_params->params.tFAW, TCK);
+
+ WL = 5 + mrc_params->ddr_speed;
+
+ Dtr0.field.dramFrequency = mrc_params->ddr_speed;
+
+ Dtr0.field.tCL = TCL - 5; //Convert from TCL (DRAM clocks) to VLV indx
+ Dtr0.field.tRP = TRP - 5; //5 bit DRAM Clock
+ Dtr0.field.tRCD = TRCD - 5; //5 bit DRAM Clock
+
+ Dtr1.field.tWCL = WL - 3; //Convert from WL (DRAM clocks) to VLV indx
+ Dtr1.field.tWTP = WL + 4 + TWR - 14; //Change to tWTP
+ Dtr1.field.tRTP = MMAX(TRTP, 4) - 3; //4 bit DRAM Clock
+ Dtr1.field.tRRD = TRRD - 4; //4 bit DRAM Clock
+ Dtr1.field.tCMD = 1; //2N
+ Dtr1.field.tRAS = TRAS - 14; //6 bit DRAM Clock
+
+ Dtr1.field.tFAW = ((TFAW + 1) >> 1) - 5; //4 bit DRAM Clock
+ Dtr1.field.tCCD = 0; //Set 4 Clock CAS to CAS delay (multi-burst)
+ Dtr2.field.tRRDR = 1;
+ Dtr2.field.tWWDR = 2;
+ Dtr2.field.tRWDR = 2;
+ Dtr3.field.tWRDR = 2;
+ Dtr3.field.tWRDD = 2;
+
+ if (mrc_params->ddr_speed == DDRFREQ_800)
+ {
+ // Extended RW delay (+1)
+ Dtr3.field.tRWSR = TCL - 5 + 1;
+ }
+ else if(mrc_params->ddr_speed == DDRFREQ_1066)
+ {
+ // Extended RW delay (+1)
+ Dtr3.field.tRWSR = TCL - 5 + 1;
+ }
+
+ Dtr3.field.tWRSR = 4 + WL + TWTR - 11;
+
+ if (mrc_params->ddr_speed == DDRFREQ_800)
+ {
+ Dtr3.field.tXP = MMAX(0, 1 - Dtr1.field.tCMD);
+ }
+ else
+ {
+ Dtr3.field.tXP = MMAX(0, 2 - Dtr1.field.tCMD);
+ }
+
+ Dtr4.field.WRODTSTRT = Dtr1.field.tCMD;
+ Dtr4.field.WRODTSTOP = Dtr1.field.tCMD;
+ Dtr4.field.RDODTSTRT = Dtr1.field.tCMD + Dtr0.field.tCL - Dtr1.field.tWCL + 2; //Convert from WL (DRAM clocks) to VLV indx
+ Dtr4.field.RDODTSTOP = Dtr1.field.tCMD + Dtr0.field.tCL - Dtr1.field.tWCL + 2;
+ Dtr4.field.TRGSTRDIS = 0;
+ Dtr4.field.ODTDIS = 0;
+
+ isbW32m(MCU, DTR0, Dtr0.raw);
+ isbW32m(MCU, DTR1, Dtr1.raw);
+ isbW32m(MCU, DTR2, Dtr2.raw);
+ isbW32m(MCU, DTR3, Dtr3.raw);
+ isbW32m(MCU, DTR4, Dtr4.raw);
+
+ LEAVEFN();
+}
+
+// ddrphy_init:
+// POST_CODE[major] == 0x03
+//
+// This function performs some initialisation on the DDRIO unit.
+// This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES.
+static void ddrphy_init(MRCParams_t *mrc_params)
+{
+ uint32_t tempD; // temporary DWORD
+ uint8_t channel_i; // channel counter
+ uint8_t rank_i; // rank counter
+ uint8_t bl_grp_i; // byte lane group counter (2 BLs per module)
+
+ uint8_t bl_divisor = /*(mrc_params->channel_width==x16)?2:*/1; // byte lane divisor
+ uint8_t speed = mrc_params->ddr_speed & (BIT1|BIT0); // For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333
+ uint8_t tCAS;
+ uint8_t tCWL;
+
+ ENTERFN();
+
+ tCAS = mrc_params->params.tCL;
+ tCWL = 5 + mrc_params->ddr_speed;
+
+ // ddrphy_init starts
+ post_code(0x03, 0x00);
+
+ // HSD#231531
+ // Make sure IOBUFACT is deasserted before initialising the DDR PHY.
+ // HSD#234845
+ // Make sure WRPTRENABLE is deasserted before initialising the DDR PHY.
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+ if (mrc_params->channel_enables & (1<<channel_i)) {
+ // Deassert DDRPHY Initialisation Complete
+ isbM32m(DDRPHY, (CMDPMCONFIG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT20, BIT20); // SPID_INIT_COMPLETE=0
+ // Deassert IOBUFACT
+ isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT2, BIT2); // IOBUFACTRST_N=0
+ // Disable WRPTR
+ isbM32m(DDRPHY, (CMDPTRREG + (channel_i * DDRIOCCC_CH_OFFSET)), ~BIT0, BIT0); // WRPTRENABLE=0
+ } // if channel enabled
+ } // channel_i loop
+
+ // Put PHY in reset
+ isbM32m(DDRPHY, MASTERRSTN, 0, BIT0); // PHYRSTN=0
+
+ // Initialise DQ01,DQ23,CMD,CLK-CTL,COMP modules
+ // STEP0:
+ post_code(0x03, 0x10);
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+ if (mrc_params->channel_enables & (1<<channel_i)) {
+
+ // DQ01-DQ23
+ for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {
+ isbM32m(DDRPHY, (DQOBSCKEBBCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((bl_grp_i) ? (0x00) : (BIT22)), (BIT22)); // Analog MUX select - IO2xCLKSEL
+
+ // ODT Strength
+ switch (mrc_params->rd_odt_value) {
+ case 1: tempD = 0x3; break; // 60 ohm
+ case 2: tempD = 0x3; break; // 120 ohm
+ case 3: tempD = 0x3; break; // 180 ohm
+ default: tempD = 0x3; break; // 120 ohm
+ }
+ isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (tempD<<5), (BIT6|BIT5)); // ODT strength
+ isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (tempD<<5), (BIT6|BIT5)); // ODT strength
+ // Dynamic ODT/DIFFAMP
+ tempD = (((tCAS)<<24)|((tCAS)<<16)|((tCAS)<<8)|((tCAS)<<0));
+ switch (speed) {
+ case 0: tempD -= 0x01010101; break; // 800
+ case 1: tempD -= 0x02020202; break; // 1066
+ case 2: tempD -= 0x03030303; break; // 1333
+ case 3: tempD -= 0x04040404; break; // 1600
+ }
+ isbM32m(DDRPHY, (B01LATCTL1 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // Launch Time: ODT, DIFFAMP, ODT, DIFFAMP
+ switch (speed) {
+ // HSD#234715
+ case 0: tempD = ((0x06<<16)|(0x07<<8)); break; // 800
+ case 1: tempD = ((0x07<<16)|(0x08<<8)); break; // 1066
+ case 2: tempD = ((0x09<<16)|(0x0A<<8)); break; // 1333
+ case 3: tempD = ((0x0A<<16)|(0x0B<<8)); break; // 1600
+ }
+ isbM32m(DDRPHY, (B0ONDURCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT13|BIT12|BIT11|BIT10|BIT9|BIT8))); // On Duration: ODT, DIFFAMP
+ isbM32m(DDRPHY, (B1ONDURCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT13|BIT12|BIT11|BIT10|BIT9|BIT8))); // On Duration: ODT, DIFFAMP
+
+ switch (mrc_params->rd_odt_value) {
+ case 0: tempD = ((0x3F<<16)|(0x3f<<10)); break; // override DIFFAMP=on, ODT=off
+ default: tempD = ((0x3F<<16)|(0x2A<<10)); break; // override DIFFAMP=on, ODT=on
+ }
+ isbM32m(DDRPHY, (B0OVRCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10))); // Override: DIFFAMP, ODT
+ isbM32m(DDRPHY, (B1OVRCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), tempD, ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10))); // Override: DIFFAMP, ODT
+
+ // DLL Setup
+ // 1xCLK Domain Timings: tEDP,RCVEN,WDQS (PO)
+ isbM32m(DDRPHY, (B0LATCTL0 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (((tCAS+7)<<16)|((tCAS-4)<<8)|((tCWL-2)<<0)), ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // 1xCLK: tEDP, RCVEN, WDQS
+ isbM32m(DDRPHY, (B1LATCTL0 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (((tCAS+7)<<16)|((tCAS-4)<<8)|((tCWL-2)<<0)), ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // 1xCLK: tEDP, RCVEN, WDQS
+
+ // RCVEN Bypass (PO)
+ isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x0<<7)|(0x0<<0)), (BIT7|BIT0)); // AFE Bypass, RCVEN DIFFAMP
+ isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x0<<7)|(0x0<<0)), (BIT7|BIT0)); // AFE Bypass, RCVEN DIFFAMP
+ // TX
+ isbM32m(DDRPHY, (DQCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT16), (BIT16)); // 0 means driving DQ during DQS-preamble
+ isbM32m(DDRPHY, (B01PTRCTL1 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT8), (BIT8)); // WR_LVL mode disable
+ // RX (PO)
+ isbM32m(DDRPHY, (B0VREFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x03<<2)|(0x0<<1)|(0x0<<0)), ((BIT7|BIT6|BIT5|BIT4|BIT3|BIT2)|BIT1|BIT0)); // Internal Vref Code, Enable#, Ext_or_Int (1=Ext)
+ isbM32m(DDRPHY, (B1VREFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((0x03<<2)|(0x0<<1)|(0x0<<0)), ((BIT7|BIT6|BIT5|BIT4|BIT3|BIT2)|BIT1|BIT0)); // Internal Vref Code, Enable#, Ext_or_Int (1=Ext)
+ isbM32m(DDRPHY, (B0RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (0), (BIT4)); // Per-Bit De-Skew Enable
+ isbM32m(DDRPHY, (B1RXIOBUFCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (0), (BIT4)); // Per-Bit De-Skew Enable
+ }
+ // CLKEBB
+ isbM32m(DDRPHY, (CMDOBSCKEBBCTL + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT23));
+
+ // Enable tristate control of cmd/address bus
+ isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT1|BIT0));
+
+ // ODT RCOMP
+ isbM32m(DDRPHY, (CMDRCOMPODT + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x03<<5)|(0x03<<0)), ((BIT9|BIT8|BIT7|BIT6|BIT5)|(BIT4|BIT3|BIT2|BIT1|BIT0)));
+
+ // CMDPM* registers must be programmed in this order...
+ isbM32m(DDRPHY, (CMDPMDLYREG4 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFFFU<<16)|(0xFFFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24|BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8|BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Turn On Delays: SFR (regulator), MPLL
+ isbM32m(DDRPHY, (CMDPMDLYREG3 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFU<<28)|(0xFFF<<16)|(0xF<<12)|(0x616<<0)), ((BIT31|BIT30|BIT29|BIT28)|(BIT27|BIT26|BIT25|BIT24|BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8|BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Delays: ASSERT_IOBUFACT_to_ALLON0_for_PM_MSG_3, VREG (MDLL) Turn On, ALLON0_to_DEASSERT_IOBUFACT_for_PM_MSG_gt0, MDLL Turn On
+ isbM32m(DDRPHY, (CMDPMDLYREG2 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFU<<24)|(0xFF<<16)|(0xFF<<8)|(0xFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // MPLL Divider Reset Delays
+ isbM32m(DDRPHY, (CMDPMDLYREG1 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFU<<24)|(0xFF<<16)|(0xFF<<8)|(0xFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Turn Off Delays: VREG, Staggered MDLL, MDLL, PI
+ isbM32m(DDRPHY, (CMDPMDLYREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xFFU<<24)|(0xFF<<16)|(0xFF<<8)|(0xFF<<0)), ((BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT23|BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // Turn On Delays: MPLL, Staggered MDLL, PI, IOBUFACT
+ isbM32m(DDRPHY, (CMDPMCONFIG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x6<<8)|BIT6|(0x4<<0)), (BIT31|BIT30|BIT29|BIT28|BIT27|BIT26|BIT25|BIT24|BIT23|BIT22|BIT21|(BIT11|BIT10|BIT9|BIT8)|BIT6|(BIT3|BIT2|BIT1|BIT0))); // Allow PUnit signals
+ isbM32m(DDRPHY, (CMDMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x3<<4)|(0x7<<0)), ((BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // DLL_VREG Bias Trim, VREF Tuning for DLL_VREG
+ // CLK-CTL
+ isbM32m(DDRPHY, (CCOBSCKEBBCTL + (channel_i * DDRIOCCC_CH_OFFSET)), 0, (BIT24)); // CLKEBB
+ isbM32m(DDRPHY, (CCCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x0<<16)|(0x0<<12)|(0x0<<8)|(0xF<<4)|BIT0), ((BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|BIT0)); // Buffer Enable: CS,CKE,ODT,CLK
+ isbM32m(DDRPHY, (CCRCOMPODT + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x03<<8)|(0x03<<0)), ((BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT RCOMP
+ isbM32m(DDRPHY, (CCMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x3<<4)|(0x7<<0)), ((BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // DLL_VREG Bias Trim, VREF Tuning for DLL_VREG
+
+ // COMP (RON channel specific)
+ // - DQ/DQS/DM RON: 32 Ohm
+ // - CTRL/CMD RON: 27 Ohm
+ // - CLK RON: 26 Ohm
+ isbM32m(DDRPHY, (DQVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x08<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP Vref PU/PD
+ isbM32m(DDRPHY, (CMDVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0C<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP Vref PU/PD
+ isbM32m(DDRPHY, (CLKVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0F<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP Vref PU/PD
+ isbM32m(DDRPHY, (DQSVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x08<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP Vref PU/PD
+ isbM32m(DDRPHY, (CTLVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0C<<24)|(0x03<<16)), ((BIT29|BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP Vref PU/PD
+
+ // DQS Swapped Input Enable
+ isbM32m(DDRPHY, (COMPEN1CH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT19|BIT17), ((BIT31|BIT30)|BIT19|BIT17|(BIT15|BIT14)));
+
+ // ODT VREF = 1.5 x 274/360+274 = 0.65V (code of ~50)
+ isbM32m(DDRPHY, (DQVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x32<<8)|(0x03<<0)), ((BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT Vref PU/PD
+ isbM32m(DDRPHY, (DQSVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x32<<8)|(0x03<<0)), ((BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT Vref PU/PD
+ isbM32m(DDRPHY, (CLKVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x0E<<8)|(0x05<<0)), ((BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // ODT Vref PU/PD
+
+ // Slew rate settings are frequency specific, numbers below are for 800Mhz (speed == 0)
+ // - DQ/DQS/DM/CLK SR: 4V/ns,
+ // - CTRL/CMD SR: 1.5V/ns
+ tempD = (0x0E<<16)|(0x0E<<12)|(0x08<<8)|(0x0B<<4)|(0x0B<<0);
+ isbM32m(DDRPHY, (DLYSELCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (tempD), ((BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // DCOMP Delay Select: CTL,CMD,CLK,DQS,DQ
+ isbM32m(DDRPHY, (TCOVREFCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x05<<16)|(0x05<<8)|(0x05<<0)), ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT5|BIT4|BIT3|BIT2|BIT1|BIT0))); // TCO Vref CLK,DQS,DQ
+ isbM32m(DDRPHY, (CCBUFODTCH0 + (channel_i * DDRCOMP_CH_OFFSET)), ((0x03<<8)|(0x03<<0)), ((BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT4|BIT3|BIT2|BIT1|BIT0))); // ODTCOMP CMD/CTL PU/PD
+ isbM32m(DDRPHY, (COMPEN0CH0 + (channel_i * DDRCOMP_CH_OFFSET)), (0), ((BIT31|BIT30)|BIT8)); // COMP
+
+ #ifdef BACKUP_COMPS
+ // DQ COMP Overrides
+ isbM32m(DDRPHY, (DQDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU
+ isbM32m(DDRPHY, (DQDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD
+ isbM32m(DDRPHY, (DQDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU
+ isbM32m(DDRPHY, (DQDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD
+ isbM32m(DDRPHY, (DQODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU
+ isbM32m(DDRPHY, (DQODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD
+ isbM32m(DDRPHY, (DQTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU
+ isbM32m(DDRPHY, (DQTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD
+ // DQS COMP Overrides
+ isbM32m(DDRPHY, (DQSDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU
+ isbM32m(DDRPHY, (DQSDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD
+ isbM32m(DDRPHY, (DQSDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU
+ isbM32m(DDRPHY, (DQSDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x10<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD
+ isbM32m(DDRPHY, (DQSODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU
+ isbM32m(DDRPHY, (DQSODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD
+ isbM32m(DDRPHY, (DQSTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU
+ isbM32m(DDRPHY, (DQSTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD
+ // CLK COMP Overrides
+ isbM32m(DDRPHY, (CLKDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0C<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU
+ isbM32m(DDRPHY, (CLKDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0C<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD
+ isbM32m(DDRPHY, (CLKDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x07<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU
+ isbM32m(DDRPHY, (CLKDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x07<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD
+ isbM32m(DDRPHY, (CLKODTPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PU
+ isbM32m(DDRPHY, (CLKODTPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0B<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODTCOMP PD
+ isbM32m(DDRPHY, (CLKTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PU
+ isbM32m(DDRPHY, (CLKTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31), (BIT31)); // TCOCOMP PD
+ // CMD COMP Overrides
+ isbM32m(DDRPHY, (CMDDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU
+ isbM32m(DDRPHY, (CMDDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD
+ isbM32m(DDRPHY, (CMDDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU
+ isbM32m(DDRPHY, (CMDDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD
+ // CTL COMP Overrides
+ isbM32m(DDRPHY, (CTLDRVPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PU
+ isbM32m(DDRPHY, (CTLDRVPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0D<<16)), (BIT31|(BIT21|BIT20|BIT19|BIT18|BIT17|BIT16))); // RCOMP PD
+ isbM32m(DDRPHY, (CTLDLYPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PU
+ isbM32m(DDRPHY, (CTLDLYPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x0A<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // DCOMP PD
+ #else
+ // DQ TCOCOMP Overrides
+ isbM32m(DDRPHY, (DQTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU
+ isbM32m(DDRPHY, (DQTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD
+ // DQS TCOCOMP Overrides
+ isbM32m(DDRPHY, (DQSTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU
+ isbM32m(DDRPHY, (DQSTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD
+ // CLK TCOCOMP Overrides
+ isbM32m(DDRPHY, (CLKTCOPUCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PU
+ isbM32m(DDRPHY, (CLKTCOPDCTLCH0 + (channel_i * DDRCOMP_CH_OFFSET)), (BIT31|(0x1F<<16)), (BIT31|(BIT20|BIT19|BIT18|BIT17|BIT16))); // TCOCOMP PD
+ #endif // BACKUP_COMPS
+ // program STATIC delays
+ #ifdef BACKUP_WCMD
+ set_wcmd(channel_i, ddr_wcmd[PLATFORM_ID]);
+ #else
+ set_wcmd(channel_i, ddr_wclk[PLATFORM_ID] + HALF_CLK);
+ #endif // BACKUP_WCMD
+ for (rank_i=0; rank_i<NUM_RANKS; rank_i++) {
+ if (mrc_params->rank_enables & (1<<rank_i)) {
+ set_wclk(channel_i, rank_i, ddr_wclk[PLATFORM_ID]);
+ #ifdef BACKUP_WCTL
+ set_wctl(channel_i, rank_i, ddr_wctl[PLATFORM_ID]);
+ #else
+ set_wctl(channel_i, rank_i, ddr_wclk[PLATFORM_ID] + HALF_CLK);
+ #endif // BACKUP_WCTL
+ }
+ }
+ }
+ }
+ // COMP (non channel specific)
+ //isbM32m(DDRPHY, (), (), ());
+ isbM32m(DDRPHY, (DQANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable
+ isbM32m(DDRPHY, (DQANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable
+ isbM32m(DDRPHY, (CMDANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable
+ isbM32m(DDRPHY, (CMDANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable
+ isbM32m(DDRPHY, (CLKANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable
+ isbM32m(DDRPHY, (CLKANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable
+ isbM32m(DDRPHY, (DQSANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable
+ isbM32m(DDRPHY, (DQSANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable
+ isbM32m(DDRPHY, (CTLANADRVPUCTL), (BIT30), (BIT30)); // RCOMP: Dither PU Enable
+ isbM32m(DDRPHY, (CTLANADRVPDCTL), (BIT30), (BIT30)); // RCOMP: Dither PD Enable
+ isbM32m(DDRPHY, (DQANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable
+ isbM32m(DDRPHY, (DQANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable
+ isbM32m(DDRPHY, (CLKANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable
+ isbM32m(DDRPHY, (CLKANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable
+ isbM32m(DDRPHY, (DQSANAODTPUCTL), (BIT30), (BIT30)); // ODT: Dither PU Enable
+ isbM32m(DDRPHY, (DQSANAODTPDCTL), (BIT30), (BIT30)); // ODT: Dither PD Enable
+ isbM32m(DDRPHY, (DQANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable
+ isbM32m(DDRPHY, (DQANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable
+ isbM32m(DDRPHY, (CMDANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable
+ isbM32m(DDRPHY, (CMDANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable
+ isbM32m(DDRPHY, (CLKANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable
+ isbM32m(DDRPHY, (CLKANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable
+ isbM32m(DDRPHY, (DQSANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable
+ isbM32m(DDRPHY, (DQSANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable
+ isbM32m(DDRPHY, (CTLANADLYPUCTL), (BIT30), (BIT30)); // DCOMP: Dither PU Enable
+ isbM32m(DDRPHY, (CTLANADLYPDCTL), (BIT30), (BIT30)); // DCOMP: Dither PD Enable
+ isbM32m(DDRPHY, (DQANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable
+ isbM32m(DDRPHY, (DQANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable
+ isbM32m(DDRPHY, (CLKANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable
+ isbM32m(DDRPHY, (CLKANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable
+ isbM32m(DDRPHY, (DQSANATCOPUCTL), (BIT30), (BIT30)); // TCO: Dither PU Enable
+ isbM32m(DDRPHY, (DQSANATCOPDCTL), (BIT30), (BIT30)); // TCO: Dither PD Enable
+ isbM32m(DDRPHY, (TCOCNTCTRL), (0x1<<0), (BIT1|BIT0)); // TCOCOMP: Pulse Count
+ isbM32m(DDRPHY, (CHNLBUFSTATIC), ((0x03<<24)|(0x03<<16)), ((BIT28|BIT27|BIT26|BIT25|BIT24)|(BIT20|BIT19|BIT18|BIT17|BIT16))); // ODT: CMD/CTL PD/PU
+ isbM32m(DDRPHY, (MSCNTR), (0x64<<0), (BIT7|BIT6|BIT5|BIT4|BIT3|BIT2|BIT1|BIT0)); // Set 1us counter
+ isbM32m(DDRPHY, (LATCH1CTL), (0x1<<28), (BIT30|BIT29|BIT28)); // ???
+
+ // Release PHY from reset
+ isbM32m(DDRPHY, MASTERRSTN, BIT0, BIT0); // PHYRSTN=1
+
+ // STEP1:
+ post_code(0x03, 0x11);
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+ if (mrc_params->channel_enables & (1<<channel_i)) {
+ // DQ01-DQ23
+ for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {
+ isbM32m(DDRPHY, (DQMDLLCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG
+ delay_n(3);
+ }
+ // ECC
+ isbM32m(DDRPHY, (ECCMDLLCTL), (BIT13), (BIT13)); // Enable VREG
+ delay_n(3);
+ // CMD
+ isbM32m(DDRPHY, (CMDMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG
+ delay_n(3);
+ // CLK-CTL
+ isbM32m(DDRPHY, (CCMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT13), (BIT13)); // Enable VREG
+ delay_n(3);
+ }
+ }
+
+ // STEP2:
+ post_code(0x03, 0x12);
+ delay_n(200);
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+ if (mrc_params->channel_enables & (1<<channel_i)) {
+ // DQ01-DQ23
+ for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {
+ isbM32m(DDRPHY, (DQMDLLCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT17), (BIT17)); // Enable MCDLL
+ delay_n(50);
+ }
+ // ECC
+ isbM32m(DDRPHY, (ECCMDLLCTL), (BIT17), (BIT17)); // Enable MCDLL
+ delay_n(50);
+ // CMD
+ isbM32m(DDRPHY, (CMDMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT18), (BIT18)); // Enable MCDLL
+ delay_n(50);
+ // CLK-CTL
+ isbM32m(DDRPHY, (CCMDLLCTL + (channel_i * DDRIOCCC_CH_OFFSET)), (BIT18), (BIT18)); // Enable MCDLL
+ delay_n(50);
+ }
+ }
+
+ // STEP3:
+ post_code(0x03, 0x13);
+ delay_n(100);
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+ if (mrc_params->channel_enables & (1<<channel_i)) {
+ // DQ01-DQ23
+ for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {
+#ifdef FORCE_16BIT_DDRIO
+ tempD = ((bl_grp_i) && (mrc_params->channel_width == x16)) ? ((0x1<<12)|(0x1<<8)|(0xF<<4)|(0xF<<0)) : ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0));
+#else
+ tempD = ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0));
+#endif
+ isbM32m(DDRPHY, (DQDLLTXCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (tempD), ((BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // Enable TXDLL
+ delay_n(3);
+ isbM32m(DDRPHY, (DQDLLRXCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT3|BIT2|BIT1|BIT0), (BIT3|BIT2|BIT1|BIT0)); // Enable RXDLL
+ delay_n(3);
+ isbM32m(DDRPHY, (B0OVRCTL + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), (BIT3|BIT2|BIT1|BIT0), (BIT3|BIT2|BIT1|BIT0)); // Enable RXDLL Overrides BL0
+ }
+
+ // ECC
+ tempD = ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0));
+ isbM32m(DDRPHY, (ECCDLLTXCTL), (tempD), ((BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // Enable TXDLL
+ delay_n(3);
+
+ // CMD (PO)
+ isbM32m(DDRPHY, (CMDDLLTXCTL + (channel_i * DDRIOCCC_CH_OFFSET)), ((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0)), ((BIT15|BIT14|BIT13|BIT12)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4)|(BIT3|BIT2|BIT1|BIT0))); // Enable TXDLL
+ delay_n(3);
+ }
+ }
+
+
+ // STEP4:
+ post_code(0x03, 0x14);
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++) {
+ if (mrc_params->channel_enables & (1<<channel_i)) {
+ // Host To Memory Clock Alignment (HMC) for 800/1066
+ for (bl_grp_i=0; bl_grp_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_grp_i++) {
+ isbM32m(DDRPHY, (DQCLKALIGNREG2 + (bl_grp_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), ((bl_grp_i)?(0x3):(0x1)), (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID
+ }
+ isbM32m(DDRPHY, (ECCCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x2, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID
+ isbM32m(DDRPHY, (CMDCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x0, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID
+ isbM32m(DDRPHY, (CCCLKALIGNREG2 + (channel_i * DDRIODQ_CH_OFFSET)), 0x2, (BIT3|BIT2|BIT1|BIT0)); // CLK_ALIGN_MOD_ID
+ isbM32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), (0x2<<4), (BIT5|BIT4)); // CLK_ALIGN_MODE
+ isbM32m(DDRPHY, (CMDCLKALIGNREG1 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x18<<16)|(0x10<<8)|(0x8<<2)|(0x1<<0)), ((BIT22|BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT14|BIT13|BIT12|BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4|BIT3|BIT2)|(BIT1|BIT0))); // NUM_SAMPLES, MAX_SAMPLES, MACRO_PI_STEP, MICRO_PI_STEP
+ isbM32m(DDRPHY, (CMDCLKALIGNREG2 + (channel_i * DDRIOCCC_CH_OFFSET)), ((0x10<<16)|(0x4<<8)|(0x2<<4)), ((BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT11|BIT10|BIT9|BIT8)|(BIT7|BIT6|BIT5|BIT4))); // ???, TOTAL_NUM_MODULES, FIRST_U_PARTITION
+ #ifdef HMC_TEST
+ isbM32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT24, BIT24); // START_CLK_ALIGN=1
+ while (isbR32m(DDRPHY, (CMDCLKALIGNREG0 + (channel_i * DDRIOCCC_CH_OFFSET))) & BIT24); // wait for START_CLK_ALIGN=0
+ #endif // HMC_TEST
+
+ // Set RD/WR Pointer Seperation & COUNTEN & FIFOPTREN
+ isbM32m(DDRPHY, (CMDPTRREG + (channel_i * DDRIOCCC_CH_OFFSET)), BIT0, BIT0); // WRPTRENABLE=1
+
+
+#ifdef SIM
+ // comp is not working on simulator
+#else
+ // COMP initial
+ isbM32m(DDRPHY, (COMPEN0CH0 + (channel_i * DDRCOMP_CH_OFFSET)), BIT5, BIT5); // enable bypass for CLK buffer (PO)
+ isbM32m(DDRPHY, (CMPCTRL), (BIT0), (BIT0)); // Initial COMP Enable
+ while (isbR32m(DDRPHY, (CMPCTRL)) & BIT0); // wait for Initial COMP Enable = 0
+ isbM32m(DDRPHY, (COMPEN0CH0 + (channel_i * DDRCOMP_CH_OFFSET)), ~BIT5, BIT5); // disable bypass for CLK buffer (PO)
+#endif
+
+ // IOBUFACT
+ // STEP4a
+ isbM32m(DDRPHY, (CMDCFGREG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT2, BIT2); // IOBUFACTRST_N=1
+
+ // DDRPHY initialisation complete
+ isbM32m(DDRPHY, (CMDPMCONFIG0 + (channel_i * DDRIOCCC_CH_OFFSET)), BIT20, BIT20); // SPID_INIT_COMPLETE=1
+ }
+ }
+
+ LEAVEFN();
+ return;
+}
+
+// jedec_init (aka PerformJedecInit):
+// This function performs JEDEC initialisation on all enabled channels.
+static void jedec_init(
+ MRCParams_t *mrc_params,
+ uint32_t silent)
+{
+ uint8_t TWR, WL, Rank;
+ uint32_t TCK;
+
+ RegDTR0 DTR0reg;
+
+ DramInitDDR3MRS0 mrs0Command;
+ DramInitDDR3EMR1 emrs1Command;
+ DramInitDDR3EMR2 emrs2Command;
+ DramInitDDR3EMR3 emrs3Command;
+
+ ENTERFN();
+
+ // jedec_init starts
+ if (!silent)
+ {
+ post_code(0x04, 0x00);
+ }
+
+ // Assert RESET# for 200us
+ isbM32m(DDRPHY, CCDDR3RESETCTL, BIT1, (BIT8|BIT1)); // DDR3_RESET_SET=0, DDR3_RESET_RESET=1
+#ifdef QUICKSIM
+ // Don't waste time during simulation
+ delay_u(2);
+#else
+ delay_u(200);
+#endif
+ isbM32m(DDRPHY, CCDDR3RESETCTL, BIT8, (BIT8|BIT1)); // DDR3_RESET_SET=1, DDR3_RESET_RESET=0
+
+ DTR0reg.raw = isbR32m(MCU, DTR0);
+
+ // Set CKEVAL for populated ranks
+ // then send NOP to each rank (#4550197)
+ {
+ uint32_t DRPbuffer;
+ uint32_t DRMCbuffer;
+
+ DRPbuffer = isbR32m(MCU, DRP);
+ DRPbuffer &= 0x3;
+ DRMCbuffer = isbR32m(MCU, DRMC);
+ DRMCbuffer &= 0xFFFFFFFC;
+ DRMCbuffer |= (BIT4 | DRPbuffer);
+
+ isbW32m(MCU, DRMC, DRMCbuffer);
+
+ for (Rank = 0; Rank < NUM_RANKS; Rank++)
+ {
+ // Skip to next populated rank
+ if ((mrc_params->rank_enables & (1 << Rank)) == 0)
+ {
+ continue;
+ }
+
+ dram_init_command(DCMD_NOP(Rank));
+ }
+
+ isbW32m(MCU, DRMC, DRMC_DEFAULT);
+ }
+
+ // setup for emrs 2
+ // BIT[15:11] --> Always "0"
+ // BIT[10:09] --> Rtt_WR: want "Dynamic ODT Off" (0)
+ // BIT[08] --> Always "0"
+ // BIT[07] --> SRT: use sr_temp_range
+ // BIT[06] --> ASR: want "Manual SR Reference" (0)
+ // BIT[05:03] --> CWL: use oem_tCWL
+ // BIT[02:00] --> PASR: want "Full Array" (0)
+ emrs2Command.raw = 0;
+ emrs2Command.field.bankAddress = 2;
+
+ WL = 5 + mrc_params->ddr_speed;
+ emrs2Command.field.CWL = WL - 5;
+ emrs2Command.field.SRT = mrc_params->sr_temp_range;
+
+ // setup for emrs 3
+ // BIT[15:03] --> Always "0"
+ // BIT[02] --> MPR: want "Normal Operation" (0)
+ // BIT[01:00] --> MPR_Loc: want "Predefined Pattern" (0)
+ emrs3Command.raw = 0;
+ emrs3Command.field.bankAddress = 3;
+
+ // setup for emrs 1
+ // BIT[15:13] --> Always "0"
+ // BIT[12:12] --> Qoff: want "Output Buffer Enabled" (0)
+ // BIT[11:11] --> TDQS: want "Disabled" (0)
+ // BIT[10:10] --> Always "0"
+ // BIT[09,06,02] --> Rtt_nom: use rtt_nom_value
+ // BIT[08] --> Always "0"
+ // BIT[07] --> WR_LVL: want "Disabled" (0)
+ // BIT[05,01] --> DIC: use ron_value
+ // BIT[04:03] --> AL: additive latency want "0" (0)
+ // BIT[00] --> DLL: want "Enable" (0)
+ //
+ // (BIT5|BIT1) set Ron value
+ // 00 --> RZQ/6 (40ohm)
+ // 01 --> RZQ/7 (34ohm)
+ // 1* --> RESERVED
+ //
+ // (BIT9|BIT6|BIT2) set Rtt_nom value
+ // 000 --> Disabled
+ // 001 --> RZQ/4 ( 60ohm)
+ // 010 --> RZQ/2 (120ohm)
+ // 011 --> RZQ/6 ( 40ohm)
+ // 1** --> RESERVED
+ emrs1Command.raw = 0;
+ emrs1Command.field.bankAddress = 1;
+ emrs1Command.field.dllEnabled = 0; // 0 = Enable , 1 = Disable
+
+ if (mrc_params->ron_value == 0)
+ {
+ emrs1Command.field.DIC0 = DDR3_EMRS1_DIC_34;
+ }
+ else
+ {
+ emrs1Command.field.DIC0 = DDR3_EMRS1_DIC_40;
+ }
+
+
+ if (mrc_params->rtt_nom_value == 0)
+ {
+ emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_40 << 6);
+ }
+ else if (mrc_params->rtt_nom_value == 1)
+ {
+ emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_60 << 6);
+ }
+ else if (mrc_params->rtt_nom_value == 2)
+ {
+ emrs1Command.raw |= (DDR3_EMRS1_RTTNOM_120 << 6);
+ }
+
+ // save MRS1 value (excluding control fields)
+ mrc_params->mrs1 = emrs1Command.raw >> 6;
+
+ // setup for mrs 0
+ // BIT[15:13] --> Always "0"
+ // BIT[12] --> PPD: for Quark (1)
+ // BIT[11:09] --> WR: use oem_tWR
+ // BIT[08] --> DLL: want "Reset" (1, self clearing)
+ // BIT[07] --> MODE: want "Normal" (0)
+ // BIT[06:04,02] --> CL: use oem_tCAS
+ // BIT[03] --> RD_BURST_TYPE: want "Interleave" (1)
+ // BIT[01:00] --> BL: want "8 Fixed" (0)
+ // WR:
+ // 0 --> 16
+ // 1 --> 5
+ // 2 --> 6
+ // 3 --> 7
+ // 4 --> 8
+ // 5 --> 10
+ // 6 --> 12
+ // 7 --> 14
+ // CL:
+ // BIT[02:02] "0" if oem_tCAS <= 11 (1866?)
+ // BIT[06:04] use oem_tCAS-4
+ mrs0Command.raw = 0;
+ mrs0Command.field.bankAddress = 0;
+ mrs0Command.field.dllReset = 1;
+ mrs0Command.field.BL = 0;
+ mrs0Command.field.PPD = 1;
+ mrs0Command.field.casLatency = DTR0reg.field.tCL + 1;
+
+ TCK = tCK[mrc_params->ddr_speed];
+ TWR = MCEIL(15000, TCK); // Per JEDEC: tWR=15000ps DDR2/3 from 800-1600
+ mrs0Command.field.writeRecovery = TWR - 4;
+
+ for (Rank = 0; Rank < NUM_RANKS; Rank++)
+ {
+ // Skip to next populated rank
+ if ((mrc_params->rank_enables & (1 << Rank)) == 0)
+ {
+ continue;
+ }
+
+ emrs2Command.field.rankSelect = Rank;
+ dram_init_command(emrs2Command.raw);
+
+ emrs3Command.field.rankSelect = Rank;
+ dram_init_command(emrs3Command.raw);
+
+ emrs1Command.field.rankSelect = Rank;
+ dram_init_command(emrs1Command.raw);
+
+ mrs0Command.field.rankSelect = Rank;
+ dram_init_command(mrs0Command.raw);
+
+ dram_init_command(DCMD_ZQCL(Rank));
+ }
+
+ LEAVEFN();
+ return;
+}
+
+// rcvn_cal:
+// POST_CODE[major] == 0x05
+//
+// This function will perform our RCVEN Calibration Algorithm.
+// We will only use the 2xCLK domain timings to perform RCVEN Calibration.
+// All byte lanes will be calibrated "simultaneously" per channel per rank.
+static void rcvn_cal(
+ MRCParams_t *mrc_params)
+{
+ uint8_t channel_i; // channel counter
+ uint8_t rank_i; // rank counter
+ uint8_t bl_i; // byte lane counter
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+
+#ifdef R2R_SHARING
+ uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs
+#ifndef BACKUP_RCVN
+ uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs
+#endif // BACKUP_RCVN
+#endif // R2R_SHARING
+
+#ifdef BACKUP_RCVN
+#else
+ uint32_t tempD; // temporary DWORD
+ uint32_t delay[NUM_BYTE_LANES]; // absolute PI value to be programmed on the byte lane
+ RegDTR1 dtr1;
+ RegDTR1 dtr1save;
+#endif // BACKUP_RCVN
+ ENTERFN();
+
+ // rcvn_cal starts
+ post_code(0x05, 0x00);
+
+#ifndef BACKUP_RCVN
+ // need separate burst to sample DQS preamble
+ dtr1.raw = dtr1save.raw = isbR32m(MCU, DTR1);
+ dtr1.field.tCCD = 1;
+ isbW32m(MCU, DTR1, dtr1.raw);
+#endif
+
+#ifdef R2R_SHARING
+ // need to set "final_delay[][]" elements to "0"
+ memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));
+#endif // R2R_SHARING
+
+ // loop through each enabled channel
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1 << channel_i))
+ {
+ // perform RCVEN Calibration on a per rank basis
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1 << rank_i))
+ {
+ // POST_CODE here indicates the current channel and rank being calibrated
+ post_code(0x05, (0x10 + ((channel_i << 4) | rank_i)));
+
+#ifdef BACKUP_RCVN
+ // set hard-coded timing values
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+ {
+ set_rcvn(channel_i, rank_i, bl_i, ddr_rcvn[PLATFORM_ID]);
+ }
+#else
+ // enable FIFORST
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i += 2)
+ {
+ isbM32m(DDRPHY, (B01PTRCTL1 + ((bl_i >> 1) * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), 0,
+ BIT8); // 0 is enabled
+ } // bl_i loop
+ // initialise the starting delay to 128 PI (tCAS +1 CLK)
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+#ifdef SIM
+ // Original value was late at the end of DQS sequence
+ delay[bl_i] = 3 * FULL_CLK;
+#else
+ delay[bl_i] = (4 + 1) * FULL_CLK; // 1x CLK domain timing is tCAS-4
+#endif
+
+ set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);
+ } // bl_i loop
+
+ // now find the rising edge
+ find_rising_edge(mrc_params, delay, channel_i, rank_i, true);
+ // Now increase delay by 32 PI (1/4 CLK) to place in center of high pulse.
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ delay[bl_i] += QRTR_CLK;
+ set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);
+ } // bl_i loop
+ // Now decrement delay by 128 PI (1 CLK) until we sample a "0"
+ do
+ {
+
+ tempD = sample_dqs(mrc_params, channel_i, rank_i, true);
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ if (tempD & (1 << bl_i))
+ {
+ if (delay[bl_i] >= FULL_CLK)
+ {
+ delay[bl_i] -= FULL_CLK;
+ set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);
+ }
+ else
+ {
+ // not enough delay
+ training_message(channel_i, rank_i, bl_i);
+ post_code(0xEE, 0x50);
+ }
+ }
+ } // bl_i loop
+ } while (tempD & 0xFF);
+
+#ifdef R2R_SHARING
+ // increment "num_ranks_enabled"
+ num_ranks_enabled++;
+ // Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble.
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ delay[bl_i] += QRTR_CLK;
+ // add "delay[]" values to "final_delay[][]" for rolling average
+ final_delay[channel_i][bl_i] += delay[bl_i];
+ // set timing based on rolling average values
+ set_rcvn(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));
+ } // bl_i loop
+#else
+ // Finally increment delay by 32 PI (1/4 CLK) to place in center of preamble.
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+ {
+ delay[bl_i] += QRTR_CLK;
+ set_rcvn(channel_i, rank_i, bl_i, delay[bl_i]);
+ } // bl_i loop
+
+#endif // R2R_SHARING
+
+ // disable FIFORST
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i += 2)
+ {
+ isbM32m(DDRPHY, (B01PTRCTL1 + ((bl_i >> 1) * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)), BIT8,
+ BIT8); // 1 is disabled
+ } // bl_i loop
+
+#endif // BACKUP_RCVN
+
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+
+#ifndef BACKUP_RCVN
+ // restore original
+ isbW32m(MCU, DTR1, dtr1save.raw);
+#endif
+
+#ifdef MRC_SV
+ if (mrc_params->tune_rcvn)
+ {
+ uint32_t rcven, val;
+ uint32_t rdcmd2rcven;
+
+ /*
+ Formulas for RDCMD2DATAVALID & DIFFAMP dynamic timings
+
+ 1. Set after RCVEN training
+
+ //Tune RDCMD2DATAVALID
+
+ x80/x84[21:16]
+ MAX OF 2 RANKS : round up (rdcmd2rcven (rcven 1x) + 2x x 2 + PI/128) + 5
+
+ //rdcmd2rcven x80/84[12:8]
+ //rcven 2x x70[23:20] & [11:8]
+
+ //Tune DIFFAMP Timings
+
+ //diffampen launch x88[20:16] & [4:0] -- B01LATCTL1
+ MIN OF 2 RANKS : round down (rcven 1x + 2x x 2 + PI/128) - 1
+
+ //diffampen length x8C/x90 [13:8] -- B0ONDURCTL B1ONDURCTL
+ MAX OF 2 RANKS : roundup (rcven 1x + 2x x 2 + PI/128) + 5
+
+
+ 2. need to do a fiforst after settings these values
+ */
+
+ DPF(D_INFO, "BEFORE\n");
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0LATCTL0));
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B01LATCTL1));
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0ONDURCTL));
+
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1LATCTL0));
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1ONDURCTL));
+
+ rcven = get_rcvn(0, 0, 0) / 128;
+ rdcmd2rcven = (isbR32m(DDRPHY, B0LATCTL0) >> 8) & 0x1F;
+ val = rdcmd2rcven + rcven + 6;
+ isbM32m(DDRPHY, B0LATCTL0, val << 16, (BIT21|BIT20|BIT19|BIT18|BIT17|BIT16));
+
+ val = rdcmd2rcven + rcven - 1;
+ isbM32m(DDRPHY, B01LATCTL1, val << 0, (BIT4|BIT3|BIT2|BIT1|BIT0));
+
+ val = rdcmd2rcven + rcven + 5;
+ isbM32m(DDRPHY, B0ONDURCTL, val << 8, (BIT13|BIT12|BIT11|BIT10|BIT9|BIT8));
+
+ rcven = get_rcvn(0, 0, 1) / 128;
+ rdcmd2rcven = (isbR32m(DDRPHY, B1LATCTL0) >> 8) & 0x1F;
+ val = rdcmd2rcven + rcven + 6;
+ isbM32m(DDRPHY, B1LATCTL0, val << 16, (BIT21|BIT20|BIT19|BIT18|BIT17|BIT16));
+
+ val = rdcmd2rcven + rcven - 1;
+ isbM32m(DDRPHY, B01LATCTL1, val << 16, (BIT20|BIT19|BIT18|BIT17|BIT16));
+
+ val = rdcmd2rcven + rcven + 5;
+ isbM32m(DDRPHY, B1ONDURCTL, val << 8, (BIT13|BIT12|BIT11|BIT10|BIT9|BIT8));
+
+ DPF(D_INFO, "AFTER\n");
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0LATCTL0));
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B01LATCTL1));
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B0ONDURCTL));
+
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1LATCTL0));
+ DPF(D_INFO, "### %x\n", isbR32m(DDRPHY, B1ONDURCTL));
+
+ DPF(D_INFO, "\nPress a key\n");
+ mgetc();
+
+ // fifo reset
+ isbM32m(DDRPHY, B01PTRCTL1, 0, BIT8); // 0 is enabled
+ delay_n(3);
+ isbM32m(DDRPHY, B01PTRCTL1, BIT8, BIT8); // 1 is disabled
+ }
+#endif
+
+ LEAVEFN();
+ return;
+}
+
+// Check memory executing write/read/verify of many data patterns
+// at the specified address. Bits in the result indicate failure
+// on specific byte lane.
+static uint32_t check_bls_ex(
+ MRCParams_t *mrc_params,
+ uint32_t address)
+{
+ uint32_t result;
+ uint8_t first_run = 0;
+
+ if (mrc_params->hte_setup)
+ {
+ mrc_params->hte_setup = 0;
+
+ first_run = 1;
+ select_hte(mrc_params);
+ }
+
+ result = WriteStressBitLanesHTE(mrc_params, address, first_run);
+
+ DPF(D_TRN, "check_bls_ex result is %x\n", result);
+ return result;
+}
+
+// Check memory executing simple write/read/verify at
+// the specified address. Bits in the result indicate failure
+// on specific byte lane.
+static uint32_t check_rw_coarse(
+ MRCParams_t *mrc_params,
+ uint32_t address)
+{
+ uint32_t result = 0;
+ uint8_t first_run = 0;
+
+ if (mrc_params->hte_setup)
+ {
+ mrc_params->hte_setup = 0;
+
+ first_run = 1;
+ select_hte(mrc_params);
+ }
+
+ result = BasicWriteReadHTE(mrc_params, address, first_run, WRITE_TRAIN);
+
+ DPF(D_TRN, "check_rw_coarse result is %x\n", result);
+ return result;
+}
+
+// wr_level:
+// POST_CODE[major] == 0x06
+//
+// This function will perform the Write Levelling algorithm (align WCLK and WDQS).
+// This algorithm will act on each rank in each channel separately.
+static void wr_level(
+ MRCParams_t *mrc_params)
+{
+ uint8_t channel_i; // channel counter
+ uint8_t rank_i; // rank counter
+ uint8_t bl_i; // byte lane counter
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+
+#ifdef R2R_SHARING
+ uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs
+#ifndef BACKUP_WDQS
+ uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs
+#endif // BACKUP_WDQS
+#endif // R2R_SHARING
+
+#ifdef BACKUP_WDQS
+#else
+ bool all_edges_found; // determines stop condition for CRS_WR_LVL
+ uint32_t delay[NUM_BYTE_LANES]; // absolute PI value to be programmed on the byte lane
+ // static makes it so the data is loaded in the heap once by shadow(), where
+ // non-static copies the data onto the stack every time this function is called.
+
+ uint32_t address; // address to be checked during COARSE_WR_LVL
+ RegDTR4 dtr4;
+ RegDTR4 dtr4save;
+#endif // BACKUP_WDQS
+
+ ENTERFN();
+
+ // wr_level starts
+ post_code(0x06, 0x00);
+
+#ifdef R2R_SHARING
+ // need to set "final_delay[][]" elements to "0"
+ memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));
+#endif // R2R_SHARING
+ // loop through each enabled channel
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1 << channel_i))
+ {
+ // perform WRITE LEVELING algorithm on a per rank basis
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1 << rank_i))
+ {
+ // POST_CODE here indicates the current rank and channel being calibrated
+ post_code(0x06, (0x10 + ((channel_i << 4) | rank_i)));
+
+#ifdef BACKUP_WDQS
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+ {
+ set_wdqs(channel_i, rank_i, bl_i, ddr_wdqs[PLATFORM_ID]);
+ set_wdq(channel_i, rank_i, bl_i, (ddr_wdqs[PLATFORM_ID] - QRTR_CLK));
+ }
+#else
+
+ { // Begin product specific code
+
+ // perform a single PRECHARGE_ALL command to make DRAM state machine go to IDLE state
+ dram_init_command(DCMD_PREA(rank_i));
+
+ // enable Write Levelling Mode (EMRS1 w/ Write Levelling Mode Enable)
+ dram_init_command(DCMD_MRS1(rank_i,0x0082));
+
+ // set ODT DRAM Full Time Termination disable in MCU
+ dtr4.raw = dtr4save.raw = isbR32m(MCU, DTR4);
+ dtr4.field.ODTDIS = 1;
+ isbW32m(MCU, DTR4, dtr4.raw);
+
+ for (bl_i = 0; bl_i < ((NUM_BYTE_LANES / bl_divisor) / 2); bl_i++)
+ {
+ isbM32m(DDRPHY, DQCTL + (DDRIODQ_BL_OFFSET * bl_i) + (DDRIODQ_CH_OFFSET * channel_i),
+ (BIT28 | (0x1 << 8) | (0x1 << 6) | (0x1 << 4) | (0x1 << 2)),
+ (BIT28 | (BIT9|BIT8) | (BIT7|BIT6) | (BIT5|BIT4) | (BIT3|BIT2))); // Enable Sandy Bridge Mode (WDQ Tri-State) & Ensure 5 WDQS pulses during Write Leveling
+ }
+
+ isbM32m(DDRPHY, CCDDR3RESETCTL + (DDRIOCCC_CH_OFFSET * channel_i), (BIT16), (BIT16)); // Write Leveling Mode enabled in IO
+ } // End product specific code
+ // Initialise the starting delay to WCLK
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ { // Begin product specific code
+ // CLK0 --> RK0
+ // CLK1 --> RK1
+ delay[bl_i] = get_wclk(channel_i, rank_i);
+ } // End product specific code
+ set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]);
+ } // bl_i loop
+ // now find the rising edge
+ find_rising_edge(mrc_params, delay, channel_i, rank_i, false);
+ { // Begin product specific code
+ // disable Write Levelling Mode
+ isbM32m(DDRPHY, CCDDR3RESETCTL + (DDRIOCCC_CH_OFFSET * channel_i), (0), (BIT16)); // Write Leveling Mode disabled in IO
+
+ for (bl_i = 0; bl_i < ((NUM_BYTE_LANES / bl_divisor) / 2); bl_i++)
+ {
+ isbM32m(DDRPHY, DQCTL + (DDRIODQ_BL_OFFSET * bl_i) + (DDRIODQ_CH_OFFSET * channel_i),
+ ((0x1 << 8) | (0x1 << 6) | (0x1 << 4) | (0x1 << 2)),
+ (BIT28 | (BIT9|BIT8) | (BIT7|BIT6) | (BIT5|BIT4) | (BIT3|BIT2))); // Disable Sandy Bridge Mode & Ensure 4 WDQS pulses during normal operation
+ } // bl_i loop
+
+ // restore original DTR4
+ isbW32m(MCU, DTR4, dtr4save.raw);
+
+ // restore original value (Write Levelling Mode Disable)
+ dram_init_command(DCMD_MRS1(rank_i, mrc_params->mrs1));
+
+ // perform a single PRECHARGE_ALL command to make DRAM state machine go to IDLE state
+ dram_init_command(DCMD_PREA(rank_i));
+ } // End product specific code
+
+ post_code(0x06, (0x30 + ((channel_i << 4) | rank_i)));
+
+ // COARSE WRITE LEVEL:
+ // check that we're on the correct clock edge
+
+ // hte reconfiguration request
+ mrc_params->hte_setup = 1;
+
+ // start CRS_WR_LVL with WDQS = WDQS + 128 PI
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ delay[bl_i] = get_wdqs(channel_i, rank_i, bl_i) + FULL_CLK;
+ set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]);
+ // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI)
+ set_wdq(channel_i, rank_i, bl_i, (delay[bl_i] - QRTR_CLK));
+ } // bl_i loop
+
+ // get an address in the targeted channel/rank
+ address = get_addr(mrc_params, channel_i, rank_i);
+ do
+ {
+ uint32_t coarse_result = 0x00;
+ uint32_t coarse_result_mask = byte_lane_mask(mrc_params);
+ all_edges_found = true; // assume pass
+
+#ifdef SIM
+ // need restore memory to idle state as write can be in bad sync
+ dram_init_command (DCMD_PREA(rank_i));
+#endif
+
+ mrc_params->hte_setup = 1;
+ coarse_result = check_rw_coarse(mrc_params, address);
+
+ // check for failures and margin the byte lane back 128 PI (1 CLK)
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ if (coarse_result & (coarse_result_mask << bl_i))
+ {
+ all_edges_found = false;
+ delay[bl_i] -= FULL_CLK;
+ set_wdqs(channel_i, rank_i, bl_i, delay[bl_i]);
+ // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI)
+ set_wdq(channel_i, rank_i, bl_i, (delay[bl_i] - QRTR_CLK));
+ }
+ } // bl_i loop
+
+ } while (!all_edges_found);
+
+#ifdef R2R_SHARING
+ // increment "num_ranks_enabled"
+ num_ranks_enabled++;
+ // accumulate "final_delay[][]" values from "delay[]" values for rolling average
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ final_delay[channel_i][bl_i] += delay[bl_i];
+ set_wdqs(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));
+ // program WDQ timings based on WDQS (WDQ = WDQS - 32 PI)
+ set_wdq(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled) - QRTR_CLK);
+ } // bl_i loop
+#endif // R2R_SHARING
+#endif // BACKUP_WDQS
+
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+
+ LEAVEFN();
+ return;
+}
+
+// rd_train:
+// POST_CODE[major] == 0x07
+//
+// This function will perform the READ TRAINING Algorithm on all channels/ranks/byte_lanes simultaneously to minimize execution time.
+// The idea here is to train the VREF and RDQS (and eventually RDQ) values to achieve maximum READ margins.
+// The algorithm will first determine the X coordinate (RDQS setting).
+// This is done by collapsing the VREF eye until we find a minimum required RDQS eye for VREF_MIN and VREF_MAX.
+// Then we take the averages of the RDQS eye at VREF_MIN and VREF_MAX, then average those; this will be the final X coordinate.
+// The algorithm will then determine the Y coordinate (VREF setting).
+// This is done by collapsing the RDQS eye until we find a minimum required VREF eye for RDQS_MIN and RDQS_MAX.
+// Then we take the averages of the VREF eye at RDQS_MIN and RDQS_MAX, then average those; this will be the final Y coordinate.
+// NOTE: this algorithm assumes the eye curves have a one-to-one relationship, meaning for each X the curve has only one Y and vice-a-versa.
+static void rd_train(
+ MRCParams_t *mrc_params)
+{
+
+#define MIN_RDQS_EYE 10 // in PI Codes
+#define MIN_VREF_EYE 10 // in VREF Codes
+#define RDQS_STEP 1 // how many RDQS codes to jump while margining
+#define VREF_STEP 1 // how many VREF codes to jump while margining
+#define VREF_MIN (0x00) // offset into "vref_codes[]" for minimum allowed VREF setting
+#define VREF_MAX (0x3F) // offset into "vref_codes[]" for maximum allowed VREF setting
+#define RDQS_MIN (0x00) // minimum RDQS delay value
+#define RDQS_MAX (0x3F) // maximum RDQS delay value
+#define B 0 // BOTTOM VREF
+#define T 1 // TOP VREF
+#define L 0 // LEFT RDQS
+#define R 1 // RIGHT RDQS
+
+ uint8_t channel_i; // channel counter
+ uint8_t rank_i; // rank counter
+ uint8_t bl_i; // byte lane counter
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+#ifdef BACKUP_RDQS
+#else
+ uint8_t side_x; // tracks LEFT/RIGHT approach vectors
+ uint8_t side_y; // tracks BOTTOM/TOP approach vectors
+ uint8_t x_coordinate[2/*side_x*/][2/*side_y*/][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; // X coordinate data (passing RDQS values) for approach vectors
+ uint8_t y_coordinate[2/*side_x*/][2/*side_y*/][NUM_CHANNELS][NUM_BYTE_LANES]; // Y coordinate data (passing VREF values) for approach vectors
+ uint8_t x_center[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; // centered X (RDQS)
+ uint8_t y_center[NUM_CHANNELS][NUM_BYTE_LANES]; // centered Y (VREF)
+ uint32_t address; // target address for "check_bls_ex()"
+ uint32_t result; // result of "check_bls_ex()"
+ uint32_t bl_mask; // byte lane mask for "result" checking
+#ifdef R2R_SHARING
+ uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs
+ uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs
+#endif // R2R_SHARING
+#endif // BACKUP_RDQS
+ // rd_train starts
+ post_code(0x07, 0x00);
+
+ ENTERFN();
+
+#ifdef BACKUP_RDQS
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1<<channel_i))
+ {
+ for (rank_i=0; rank_i<NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1<<rank_i))
+ {
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+ {
+ set_rdqs(channel_i, rank_i, bl_i, ddr_rdqs[PLATFORM_ID]);
+ } // bl_i loop
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+#else
+ // initialise x/y_coordinate arrays
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1 << channel_i))
+ {
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1 << rank_i))
+ {
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ // x_coordinate:
+ x_coordinate[L][B][channel_i][rank_i][bl_i] = RDQS_MIN;
+ x_coordinate[R][B][channel_i][rank_i][bl_i] = RDQS_MAX;
+ x_coordinate[L][T][channel_i][rank_i][bl_i] = RDQS_MIN;
+ x_coordinate[R][T][channel_i][rank_i][bl_i] = RDQS_MAX;
+ // y_coordinate:
+ y_coordinate[L][B][channel_i][bl_i] = VREF_MIN;
+ y_coordinate[R][B][channel_i][bl_i] = VREF_MIN;
+ y_coordinate[L][T][channel_i][bl_i] = VREF_MAX;
+ y_coordinate[R][T][channel_i][bl_i] = VREF_MAX;
+ } // bl_i loop
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+
+ // initialise other variables
+ bl_mask = byte_lane_mask(mrc_params);
+ address = get_addr(mrc_params, 0, 0);
+
+#ifdef R2R_SHARING
+ // need to set "final_delay[][]" elements to "0"
+ memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));
+#endif // R2R_SHARING
+
+ // look for passing coordinates
+ for (side_y = B; side_y <= T; side_y++)
+ {
+ for (side_x = L; side_x <= R; side_x++)
+ {
+
+ post_code(0x07, (0x10 + (side_y * 2) + (side_x)));
+
+ // find passing values
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (0x1 << channel_i))
+ {
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+
+ if (mrc_params->rank_enables & (0x1 << rank_i))
+ {
+ // set x/y_coordinate search starting settings
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ set_rdqs(channel_i, rank_i, bl_i, x_coordinate[side_x][side_y][channel_i][rank_i][bl_i]);
+ set_vref(channel_i, bl_i, y_coordinate[side_x][side_y][channel_i][bl_i]);
+ } // bl_i loop
+ // get an address in the target channel/rank
+ address = get_addr(mrc_params, channel_i, rank_i);
+
+ // request HTE reconfiguration
+ mrc_params->hte_setup = 1;
+
+ // test the settings
+ do
+ {
+
+ // result[07:00] == failing byte lane (MAX 8)
+ result = check_bls_ex( mrc_params, address);
+
+ // check for failures
+ if (result & 0xFF)
+ {
+ // at least 1 byte lane failed
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ if (result & (bl_mask << bl_i))
+ {
+ // adjust the RDQS values accordingly
+ if (side_x == L)
+ {
+ x_coordinate[L][side_y][channel_i][rank_i][bl_i] += RDQS_STEP;
+ }
+ else
+ {
+ x_coordinate[R][side_y][channel_i][rank_i][bl_i] -= RDQS_STEP;
+ }
+ // check that we haven't closed the RDQS_EYE too much
+ if ((x_coordinate[L][side_y][channel_i][rank_i][bl_i] > (RDQS_MAX - MIN_RDQS_EYE)) ||
+ (x_coordinate[R][side_y][channel_i][rank_i][bl_i] < (RDQS_MIN + MIN_RDQS_EYE))
+ ||
+ (x_coordinate[L][side_y][channel_i][rank_i][bl_i]
+ == x_coordinate[R][side_y][channel_i][rank_i][bl_i]))
+ {
+ // not enough RDQS margin available at this VREF
+ // update VREF values accordingly
+ if (side_y == B)
+ {
+ y_coordinate[side_x][B][channel_i][bl_i] += VREF_STEP;
+ }
+ else
+ {
+ y_coordinate[side_x][T][channel_i][bl_i] -= VREF_STEP;
+ }
+ // check that we haven't closed the VREF_EYE too much
+ if ((y_coordinate[side_x][B][channel_i][bl_i] > (VREF_MAX - MIN_VREF_EYE)) ||
+ (y_coordinate[side_x][T][channel_i][bl_i] < (VREF_MIN + MIN_VREF_EYE)) ||
+ (y_coordinate[side_x][B][channel_i][bl_i] == y_coordinate[side_x][T][channel_i][bl_i]))
+ {
+ // VREF_EYE collapsed below MIN_VREF_EYE
+ training_message(channel_i, rank_i, bl_i);
+ post_code(0xEE, (0x70 + (side_y * 2) + (side_x)));
+ }
+ else
+ {
+ // update the VREF setting
+ set_vref(channel_i, bl_i, y_coordinate[side_x][side_y][channel_i][bl_i]);
+ // reset the X coordinate to begin the search at the new VREF
+ x_coordinate[side_x][side_y][channel_i][rank_i][bl_i] =
+ (side_x == L) ? (RDQS_MIN) : (RDQS_MAX);
+ }
+ }
+ // update the RDQS setting
+ set_rdqs(channel_i, rank_i, bl_i, x_coordinate[side_x][side_y][channel_i][rank_i][bl_i]);
+ } // if bl_i failed
+ } // bl_i loop
+ } // at least 1 byte lane failed
+ } while (result & 0xFF);
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+ } // side_x loop
+ } // side_y loop
+
+ post_code(0x07, 0x20);
+
+ // find final RDQS (X coordinate) & final VREF (Y coordinate)
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1 << channel_i))
+ {
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1 << rank_i))
+ {
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ uint32_t tempD1;
+ uint32_t tempD2;
+
+ // x_coordinate:
+ DPF(D_INFO, "RDQS T/B eye rank%d lane%d : %d-%d %d-%d\n", rank_i, bl_i,
+ x_coordinate[L][T][channel_i][rank_i][bl_i],
+ x_coordinate[R][T][channel_i][rank_i][bl_i],
+ x_coordinate[L][B][channel_i][rank_i][bl_i],
+ x_coordinate[R][B][channel_i][rank_i][bl_i]);
+
+ tempD1 = (x_coordinate[R][T][channel_i][rank_i][bl_i] + x_coordinate[L][T][channel_i][rank_i][bl_i]) / 2; // average the TOP side LEFT & RIGHT values
+ tempD2 = (x_coordinate[R][B][channel_i][rank_i][bl_i] + x_coordinate[L][B][channel_i][rank_i][bl_i]) / 2; // average the BOTTOM side LEFT & RIGHT values
+ x_center[channel_i][rank_i][bl_i] = (uint8_t) ((tempD1 + tempD2) / 2); // average the above averages
+
+ // y_coordinate:
+ DPF(D_INFO, "VREF R/L eye lane%d : %d-%d %d-%d\n", bl_i,
+ y_coordinate[R][B][channel_i][bl_i],
+ y_coordinate[R][T][channel_i][bl_i],
+ y_coordinate[L][B][channel_i][bl_i],
+ y_coordinate[L][T][channel_i][bl_i]);
+
+ tempD1 = (y_coordinate[R][T][channel_i][bl_i] + y_coordinate[R][B][channel_i][bl_i]) / 2; // average the RIGHT side TOP & BOTTOM values
+ tempD2 = (y_coordinate[L][T][channel_i][bl_i] + y_coordinate[L][B][channel_i][bl_i]) / 2; // average the LEFT side TOP & BOTTOM values
+ y_center[channel_i][bl_i] = (uint8_t) ((tempD1 + tempD2) / 2); // average the above averages
+ } // bl_i loop
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+
+#ifdef RX_EYE_CHECK
+ // perform an eye check
+ for (side_y=B; side_y<=T; side_y++)
+ {
+ for (side_x=L; side_x<=R; side_x++)
+ {
+
+ post_code(0x07, (0x30 + (side_y * 2) + (side_x)));
+
+ // update the settings for the eye check
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1<<channel_i))
+ {
+ for (rank_i=0; rank_i<NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1<<rank_i))
+ {
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+ {
+ if (side_x == L)
+ {
+ set_rdqs(channel_i, rank_i, bl_i, (x_center[channel_i][rank_i][bl_i] - (MIN_RDQS_EYE / 2)));
+ }
+ else
+ {
+ set_rdqs(channel_i, rank_i, bl_i, (x_center[channel_i][rank_i][bl_i] + (MIN_RDQS_EYE / 2)));
+ }
+ if (side_y == B)
+ {
+ set_vref(channel_i, bl_i, (y_center[channel_i][bl_i] - (MIN_VREF_EYE / 2)));
+ }
+ else
+ {
+ set_vref(channel_i, bl_i, (y_center[channel_i][bl_i] + (MIN_VREF_EYE / 2)));
+ }
+ } // bl_i loop
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+
+ // request HTE reconfiguration
+ mrc_params->hte_setup = 1;
+
+ // check the eye
+ if (check_bls_ex( mrc_params, address) & 0xFF)
+ {
+ // one or more byte lanes failed
+ post_code(0xEE, (0x74 + (side_x * 2) + (side_y)));
+ }
+ } // side_x loop
+ } // side_y loop
+#endif // RX_EYE_CHECK
+
+ post_code(0x07, 0x40);
+
+ // set final placements
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1 << channel_i))
+ {
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1 << rank_i))
+ {
+#ifdef R2R_SHARING
+ // increment "num_ranks_enabled"
+ num_ranks_enabled++;
+#endif // R2R_SHARING
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ // x_coordinate:
+#ifdef R2R_SHARING
+ final_delay[channel_i][bl_i] += x_center[channel_i][rank_i][bl_i];
+ set_rdqs(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));
+#else
+ set_rdqs(channel_i, rank_i, bl_i, x_center[channel_i][rank_i][bl_i]);
+#endif // R2R_SHARING
+ // y_coordinate:
+ set_vref(channel_i, bl_i, y_center[channel_i][bl_i]);
+ } // bl_i loop
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+#endif // BACKUP_RDQS
+ LEAVEFN();
+ return;
+}
+
+// wr_train:
+// POST_CODE[major] == 0x08
+//
+// This function will perform the WRITE TRAINING Algorithm on all channels/ranks/byte_lanes simultaneously to minimize execution time.
+// The idea here is to train the WDQ timings to achieve maximum WRITE margins.
+// The algorithm will start with WDQ at the current WDQ setting (tracks WDQS in WR_LVL) +/- 32 PIs (+/- 1/4 CLK) and collapse the eye until all data patterns pass.
+// This is because WDQS will be aligned to WCLK by the Write Leveling algorithm and WDQ will only ever have a 1/2 CLK window of validity.
+static void wr_train(
+ MRCParams_t *mrc_params)
+{
+
+#define WDQ_STEP 1 // how many WDQ codes to jump while margining
+#define L 0 // LEFT side loop value definition
+#define R 1 // RIGHT side loop value definition
+
+ uint8_t channel_i; // channel counter
+ uint8_t rank_i; // rank counter
+ uint8_t bl_i; // byte lane counter
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+#ifdef BACKUP_WDQ
+#else
+ uint8_t side_i; // LEFT/RIGHT side indicator (0=L, 1=R)
+ uint32_t tempD; // temporary DWORD
+ uint32_t delay[2/*side_i*/][NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES]; // 2 arrays, for L & R side passing delays
+ uint32_t address; // target address for "check_bls_ex()"
+ uint32_t result; // result of "check_bls_ex()"
+ uint32_t bl_mask; // byte lane mask for "result" checking
+#ifdef R2R_SHARING
+ uint32_t final_delay[NUM_CHANNELS][NUM_BYTE_LANES]; // used to find placement for rank2rank sharing configs
+ uint32_t num_ranks_enabled = 0; // used to find placement for rank2rank sharing configs
+#endif // R2R_SHARING
+#endif // BACKUP_WDQ
+
+ // wr_train starts
+ post_code(0x08, 0x00);
+
+ ENTERFN();
+
+#ifdef BACKUP_WDQ
+ for (channel_i=0; channel_i<NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1<<channel_i))
+ {
+ for (rank_i=0; rank_i<NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1<<rank_i))
+ {
+ for (bl_i=0; bl_i<(NUM_BYTE_LANES/bl_divisor); bl_i++)
+ {
+ set_wdq(channel_i, rank_i, bl_i, ddr_wdq[PLATFORM_ID]);
+ } // bl_i loop
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+#else
+ // initialise "delay"
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1 << channel_i))
+ {
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1 << rank_i))
+ {
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ // want to start with WDQ = (WDQS - QRTR_CLK) +/- QRTR_CLK
+ tempD = get_wdqs(channel_i, rank_i, bl_i) - QRTR_CLK;
+ delay[L][channel_i][rank_i][bl_i] = tempD - QRTR_CLK;
+ delay[R][channel_i][rank_i][bl_i] = tempD + QRTR_CLK;
+ } // bl_i loop
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+
+ // initialise other variables
+ bl_mask = byte_lane_mask(mrc_params);
+ address = get_addr(mrc_params, 0, 0);
+
+#ifdef R2R_SHARING
+ // need to set "final_delay[][]" elements to "0"
+ memset((void *) (final_delay), 0x00, (size_t) sizeof(final_delay));
+#endif // R2R_SHARING
+
+ // start algorithm on the LEFT side and train each channel/bl until no failures are observed, then repeat for the RIGHT side.
+ for (side_i = L; side_i <= R; side_i++)
+ {
+ post_code(0x08, (0x10 + (side_i)));
+
+ // set starting values
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1 << channel_i))
+ {
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1 << rank_i))
+ {
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ set_wdq(channel_i, rank_i, bl_i, delay[side_i][channel_i][rank_i][bl_i]);
+ } // bl_i loop
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+
+ // find passing values
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (0x1 << channel_i))
+ {
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (0x1 << rank_i))
+ {
+ // get an address in the target channel/rank
+ address = get_addr(mrc_params, channel_i, rank_i);
+
+ // request HTE reconfiguration
+ mrc_params->hte_setup = 1;
+
+ // check the settings
+ do
+ {
+
+#ifdef SIM
+ // need restore memory to idle state as write can be in bad sync
+ dram_init_command (DCMD_PREA(rank_i));
+#endif
+
+ // result[07:00] == failing byte lane (MAX 8)
+ result = check_bls_ex( mrc_params, address);
+ // check for failures
+ if (result & 0xFF)
+ {
+ // at least 1 byte lane failed
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ if (result & (bl_mask << bl_i))
+ {
+ if (side_i == L)
+ {
+ delay[L][channel_i][rank_i][bl_i] += WDQ_STEP;
+ }
+ else
+ {
+ delay[R][channel_i][rank_i][bl_i] -= WDQ_STEP;
+ }
+ // check for algorithm failure
+ if (delay[L][channel_i][rank_i][bl_i] != delay[R][channel_i][rank_i][bl_i])
+ {
+ // margin available, update delay setting
+ set_wdq(channel_i, rank_i, bl_i, delay[side_i][channel_i][rank_i][bl_i]);
+ }
+ else
+ {
+ // no margin available, notify the user and halt
+ training_message(channel_i, rank_i, bl_i);
+ post_code(0xEE, (0x80 + side_i));
+ }
+ } // if bl_i failed
+ } // bl_i loop
+ } // at least 1 byte lane failed
+ } while (result & 0xFF); // stop when all byte lanes pass
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+ } // side_i loop
+
+ // program WDQ to the middle of passing window
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1 << channel_i))
+ {
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1 << rank_i))
+ {
+#ifdef R2R_SHARING
+ // increment "num_ranks_enabled"
+ num_ranks_enabled++;
+#endif // R2R_SHARING
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+
+ DPF(D_INFO, "WDQ eye rank%d lane%d : %d-%d\n", rank_i, bl_i,
+ delay[L][channel_i][rank_i][bl_i],
+ delay[R][channel_i][rank_i][bl_i]);
+
+ tempD = (delay[R][channel_i][rank_i][bl_i] + delay[L][channel_i][rank_i][bl_i]) / 2;
+
+#ifdef R2R_SHARING
+ final_delay[channel_i][bl_i] += tempD;
+ set_wdq(channel_i, rank_i, bl_i, ((final_delay[channel_i][bl_i]) / num_ranks_enabled));
+#else
+ set_wdq(channel_i, rank_i, bl_i, tempD);
+#endif // R2R_SHARING
+
+ } // bl_i loop
+ } // if rank is enabled
+ } // rank_i loop
+ } // if channel is enabled
+ } // channel_i loop
+#endif // BACKUP_WDQ
+ LEAVEFN();
+ return;
+}
+
+// Wrapper for jedec initialisation routine
+static void perform_jedec_init(
+ MRCParams_t *mrc_params)
+{
+ jedec_init(mrc_params, 0);
+}
+
+// Configure DDRPHY for Auto-Refresh, Periodic Compensations,
+// Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down
+static void set_auto_refresh(
+ MRCParams_t *mrc_params)
+{
+ uint32_t channel_i;
+ uint32_t rank_i;
+ uint32_t bl_i;
+ uint32_t bl_divisor = /*(mrc_params->channel_width==x16)?2:*/1;
+ uint32_t tempD;
+
+ ENTERFN();
+
+ // enable Auto-Refresh, Periodic Compensations, Dynamic Diff-Amp, ZQSPERIOD, Auto-Precharge, CKE Power-Down
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1 << channel_i))
+ {
+ // Enable Periodic RCOMPS
+ isbM32m(DDRPHY, CMPCTRL, (BIT1), (BIT1));
+
+
+ // Enable Dynamic DiffAmp & Set Read ODT Value
+ switch (mrc_params->rd_odt_value)
+ {
+ case 0: tempD = 0x3F; break; // OFF
+ default: tempD = 0x00; break; // Auto
+ } // rd_odt_value switch
+
+ for (bl_i=0; bl_i<((NUM_BYTE_LANES/bl_divisor)/2); bl_i++)
+ {
+ isbM32m(DDRPHY, (B0OVRCTL + (bl_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)),
+ ((0x00<<16)|(tempD<<10)),
+ ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10))); // Override: DIFFAMP, ODT
+
+ isbM32m(DDRPHY, (B1OVRCTL + (bl_i * DDRIODQ_BL_OFFSET) + (channel_i * DDRIODQ_CH_OFFSET)),
+ ((0x00<<16)|(tempD<<10)),
+ ((BIT21|BIT20|BIT19|BIT18|BIT17|BIT16)|(BIT15|BIT14|BIT13|BIT12|BIT11|BIT10)));// Override: DIFFAMP, ODT
+ } // bl_i loop
+
+ // Issue ZQCS command
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1 << rank_i))
+ {
+ dram_init_command(DCMD_ZQCS(rank_i));
+ } // if rank_i enabled
+ } // rank_i loop
+
+ } // if channel_i enabled
+ } // channel_i loop
+
+ clear_pointers();
+
+ LEAVEFN();
+ return;
+}
+
+// Depending on configuration enables ECC support.
+// Available memory size is decresed, and updated with 0s
+// in order to clear error status. Address mode 2 forced.
+static void ecc_enable(
+ MRCParams_t *mrc_params)
+{
+ RegDRP Drp;
+ RegDSCH Dsch;
+ RegDECCCTRL Ctr;
+
+ if (mrc_params->ecc_enables == 0) return;
+
+ ENTERFN();
+
+ // Configuration required in ECC mode
+ Drp.raw = isbR32m(MCU, DRP);
+ Drp.field.addressMap = 2;
+ Drp.field.split64 = 1;
+ isbW32m(MCU, DRP, Drp.raw);
+
+ // Disable new request bypass
+ Dsch.raw = isbR32m(MCU, DSCH);
+ Dsch.field.NEWBYPDIS = 1;
+ isbW32m(MCU, DSCH, Dsch.raw);
+
+ // Enable ECC
+ Ctr.raw = 0;
+ Ctr.field.SBEEN = 1;
+ Ctr.field.DBEEN = 1;
+ Ctr.field.ENCBGEN = 1;
+ isbW32m(MCU, DECCCTRL, Ctr.raw);
+
+#ifdef SIM
+ // Read back to be sure writing took place
+ Ctr.raw = isbR32m(MCU, DECCCTRL);
+#endif
+
+ // Assume 8 bank memory, one bank is gone for ECC
+ mrc_params->mem_size -= mrc_params->mem_size / 8;
+
+ // For S3 resume memory content has to be preserved
+ if (mrc_params->boot_mode != bmS3)
+ {
+ select_hte(mrc_params);
+ HteMemInit(mrc_params, MrcMemInit, MrcHaltHteEngineOnError);
+ select_memory_manager(mrc_params);
+ }
+
+ LEAVEFN();
+ return;
+}
+
+// Lock MCU registers at the end of initialisation sequence.
+static void lock_registers(
+ MRCParams_t *mrc_params)
+{
+ RegDCO Dco;
+
+ ENTERFN();
+
+ Dco.raw = isbR32m(MCU, DCO);
+ Dco.field.PMIDIS = 0; //0 - PRI enabled
+ Dco.field.PMICTL = 0; //0 - PRI owned by MEMORY_MANAGER
+ Dco.field.DRPLOCK = 1;
+ Dco.field.REUTLOCK = 1;
+ isbW32m(MCU, DCO, Dco.raw);
+
+ LEAVEFN();
+
+}
+
+#ifdef MRC_SV
+
+// cache write back invalidate
+static void asm_wbinvd(void)
+{
+#if defined (SIM) || defined (GCC)
+ asm(
+ "wbinvd;"
+ );
+#else
+ __asm wbinvd;
+#endif
+}
+
+// cache invalidate
+static void asm_invd(void)
+{
+#if defined (SIM) || defined (GCC)
+ asm(
+ "invd;"
+ );
+#else
+ __asm invd;
+#endif
+}
+
+
+static void cpu_read(void)
+{
+ uint32_t adr, dat, limit;
+
+ asm_invd();
+
+ limit = 8 * 1024;
+ for (adr = 0; adr < limit; adr += 4)
+ {
+ dat = *(uint32_t*) adr;
+ if ((adr & 0x0F) == 0)
+ {
+ DPF(D_INFO, "\n%x : ", adr);
+ }
+ DPF(D_INFO, "%x ", dat);
+ }
+ DPF(D_INFO, "\n");
+
+ DPF(D_INFO, "CPU read done\n");
+}
+
+
+static void cpu_write(void)
+{
+ uint32_t adr, limit;
+
+ limit = 8 * 1024;
+ for (adr = 0; adr < limit; adr += 4)
+ {
+ *(uint32_t*) adr = 0xDEAD0000 + adr;
+ }
+
+ asm_wbinvd();
+
+ DPF(D_INFO, "CPU write done\n");
+}
+
+
+static void cpu_memory_test(
+ MRCParams_t *mrc_params)
+{
+ uint32_t result = 0;
+ uint32_t val, dat, adr, adr0, step, limit;
+ uint64_t my_tsc;
+
+ ENTERFN();
+
+ asm_invd();
+
+ adr0 = 1 * 1024 * 1024;
+ limit = 256 * 1024 * 1024;
+
+ for (step = 0; step <= 4; step++)
+ {
+ DPF(D_INFO, "Mem test step %d starting from %xh\n", step, adr0);
+
+ my_tsc = read_tsc();
+ for (adr = adr0; adr < limit; adr += sizeof(uint32_t))
+ {
+ if (step == 0) dat = adr;
+ else if (step == 1) dat = (1 << ((adr >> 2) & 0x1f));
+ else if (step == 2) dat = ~(1 << ((adr >> 2) & 0x1f));
+ else if (step == 3) dat = 0x5555AAAA;
+ else if (step == 4) dat = 0xAAAA5555;
+
+ *(uint32_t*) adr = dat;
+ }
+ DPF(D_INFO, "Write time %llXh\n", read_tsc() - my_tsc);
+
+ my_tsc = read_tsc();
+ for (adr = adr0; adr < limit; adr += sizeof(uint32_t))
+ {
+ if (step == 0) dat = adr;
+ else if (step == 1) dat = (1 << ((adr >> 2) & 0x1f));
+ else if (step == 2) dat = ~(1 << ((adr >> 2) & 0x1f));
+ else if (step == 3) dat = 0x5555AAAA;
+ else if (step == 4) dat = 0xAAAA5555;
+
+ val = *(uint32_t*) adr;
+
+ if (val != dat)
+ {
+ DPF(D_INFO, "%x vs. %x@%x\n", dat, val, adr);
+ result = adr|BIT31;
+ }
+ }
+ DPF(D_INFO, "Read time %llXh\n", read_tsc() - my_tsc);
+ }
+
+ DPF( D_INFO, "Memory test result %x\n", result);
+ LEAVEFN();
+}
+#endif // MRC_SV
+
+
+// Execute memory test, if error dtected it is
+// indicated in mrc_params->status.
+static void memory_test(
+ MRCParams_t *mrc_params)
+{
+ uint32_t result = 0;
+
+ ENTERFN();
+
+ select_hte(mrc_params);
+ result = HteMemInit(mrc_params, MrcMemTest, MrcHaltHteEngineOnError);
+ select_memory_manager(mrc_params);
+
+ DPF(D_INFO, "Memory test result %x\n", result);
+ mrc_params->status = ((result == 0) ? MRC_SUCCESS : MRC_E_MEMTEST);
+ LEAVEFN();
+}
+
+
+// Force same timings as with backup settings
+static void static_timings(
+ MRCParams_t *mrc_params)
+
+{
+ uint8_t ch, rk, bl;
+
+ for (ch = 0; ch < NUM_CHANNELS; ch++)
+ {
+ for (rk = 0; rk < NUM_RANKS; rk++)
+ {
+ for (bl = 0; bl < NUM_BYTE_LANES; bl++)
+ {
+ set_rcvn(ch, rk, bl, 498); // RCVN
+ set_rdqs(ch, rk, bl, 24); // RDQS
+ set_wdqs(ch, rk, bl, 292); // WDQS
+ set_wdq( ch, rk, bl, 260); // WDQ
+ if (rk == 0)
+ {
+ set_vref(ch, bl, 32); // VREF (RANK0 only)
+ }
+ }
+ set_wctl(ch, rk, 217); // WCTL
+ }
+ set_wcmd(ch, 220); // WCMD
+ }
+
+ return;
+}
+
+//
+// Initialise system memory.
+//
+void MemInit(
+ MRCParams_t *mrc_params)
+{
+ static const MemInit_t init[] =
+ {
+ { 0x0101, bmCold|bmFast|bmWarm|bmS3, clear_self_refresh }, //0
+ { 0x0200, bmCold|bmFast|bmWarm|bmS3, prog_ddr_timing_control }, //1 initialise the MCU
+ { 0x0103, bmCold|bmFast , prog_decode_before_jedec }, //2
+ { 0x0104, bmCold|bmFast , perform_ddr_reset }, //3
+ { 0x0300, bmCold|bmFast |bmS3, ddrphy_init }, //4 initialise the DDRPHY
+ { 0x0400, bmCold|bmFast , perform_jedec_init }, //5 perform JEDEC initialisation of DRAMs
+ { 0x0105, bmCold|bmFast , set_ddr_init_complete }, //6
+ { 0x0106, bmFast|bmWarm|bmS3, restore_timings }, //7
+ { 0x0106, bmCold , default_timings }, //8
+ { 0x0500, bmCold , rcvn_cal }, //9 perform RCVN_CAL algorithm
+ { 0x0600, bmCold , wr_level }, //10 perform WR_LEVEL algorithm
+ { 0x0120, bmCold , prog_page_ctrl }, //11
+ { 0x0700, bmCold , rd_train }, //12 perform RD_TRAIN algorithm
+ { 0x0800, bmCold , wr_train }, //13 perform WR_TRAIN algorithm
+ { 0x010B, bmCold , store_timings }, //14
+ { 0x010C, bmCold|bmFast|bmWarm|bmS3, enable_scrambling }, //15
+ { 0x010D, bmCold|bmFast|bmWarm|bmS3, prog_ddr_control }, //16
+ { 0x010E, bmCold|bmFast|bmWarm|bmS3, prog_dra_drb }, //17
+ { 0x010F, bmWarm|bmS3, perform_wake }, //18
+ { 0x0110, bmCold|bmFast|bmWarm|bmS3, change_refresh_period }, //19
+ { 0x0111, bmCold|bmFast|bmWarm|bmS3, set_auto_refresh }, //20
+ { 0x0112, bmCold|bmFast|bmWarm|bmS3, ecc_enable }, //21
+ { 0x0113, bmCold|bmFast , memory_test }, //22
+ { 0x0114, bmCold|bmFast|bmWarm|bmS3, lock_registers } //23 set init done
+ };
+
+ uint32_t i;
+
+ ENTERFN();
+
+ DPF(D_INFO, "Meminit build %s %s\n", __DATE__, __TIME__);
+
+ // MRC started
+ post_code(0x01, 0x00);
+
+ if (mrc_params->boot_mode != bmCold)
+ {
+ if (mrc_params->ddr_speed != mrc_params->timings.ddr_speed)
+ {
+ // full training required as frequency changed
+ mrc_params->boot_mode = bmCold;
+ }
+ }
+
+ for (i = 0; i < MCOUNT(init); i++)
+ {
+ uint64_t my_tsc;
+
+#ifdef MRC_SV
+ if (mrc_params->menu_after_mrc && i > 14)
+ {
+ uint8_t ch;
+
+ mylop:
+
+ DPF(D_INFO, "-- c - continue --\n");
+ DPF(D_INFO, "-- j - move to jedec init --\n");
+ DPF(D_INFO, "-- m - memory test --\n");
+ DPF(D_INFO, "-- r - cpu read --\n");
+ DPF(D_INFO, "-- w - cpu write --\n");
+ DPF(D_INFO, "-- b - hte base test --\n");
+ DPF(D_INFO, "-- g - hte extended test --\n");
+
+ ch = mgetc();
+ switch (ch)
+ {
+ case 'c':
+ break;
+ case 'j': //move to jedec init
+ i = 5;
+ break;
+
+ case 'M':
+ case 'N':
+ {
+ uint32_t n, res, cnt=0;
+
+ for(n=0; mgetch()==0; n++)
+ {
+ if( ch == 'M' || n % 256 == 0)
+ {
+ DPF(D_INFO, "n=%d e=%d\n", n, cnt);
+ }
+
+ res = 0;
+
+ if( ch == 'M')
+ {
+ memory_test(mrc_params);
+ res |= mrc_params->status;
+ }
+
+ mrc_params->hte_setup = 1;
+ res |= check_bls_ex(mrc_params, 0x00000000);
+ res |= check_bls_ex(mrc_params, 0x00000000);
+ res |= check_bls_ex(mrc_params, 0x00000000);
+ res |= check_bls_ex(mrc_params, 0x00000000);
+
+ if( mrc_params->rank_enables & 2)
+ {
+ mrc_params->hte_setup = 1;
+ res |= check_bls_ex(mrc_params, 0x40000000);
+ res |= check_bls_ex(mrc_params, 0x40000000);
+ res |= check_bls_ex(mrc_params, 0x40000000);
+ res |= check_bls_ex(mrc_params, 0x40000000);
+ }
+
+ if( res != 0)
+ {
+ DPF(D_INFO, "###########\n");
+ DPF(D_INFO, "#\n");
+ DPF(D_INFO, "# Error count %d\n", ++cnt);
+ DPF(D_INFO, "#\n");
+ DPF(D_INFO, "###########\n");
+ }
+
+ } // for
+
+ select_memory_manager(mrc_params);
+ }
+ goto mylop;
+ case 'm':
+ memory_test(mrc_params);
+ goto mylop;
+ case 'n':
+ cpu_memory_test(mrc_params);
+ goto mylop;
+
+ case 'l':
+ ch = mgetc();
+ if (ch <= '9') DpfPrintMask ^= (ch - '0') << 3;
+ DPF(D_INFO, "Log mask %x\n", DpfPrintMask);
+ goto mylop;
+ case 'p':
+ print_timings(mrc_params);
+ goto mylop;
+ case 'R':
+ rd_train(mrc_params);
+ goto mylop;
+ case 'W':
+ wr_train(mrc_params);
+ goto mylop;
+
+ case 'r':
+ cpu_read();
+ goto mylop;
+ case 'w':
+ cpu_write();
+ goto mylop;
+
+ case 'g':
+ {
+ uint32_t result;
+ select_hte(mrc_params);
+ mrc_params->hte_setup = 1;
+ result = check_bls_ex(mrc_params, 0);
+ DPF(D_INFO, "Extended test result %x\n", result);
+ select_memory_manager(mrc_params);
+ }
+ goto mylop;
+ case 'b':
+ {
+ uint32_t result;
+ select_hte(mrc_params);
+ mrc_params->hte_setup = 1;
+ result = check_rw_coarse(mrc_params, 0);
+ DPF(D_INFO, "Base test result %x\n", result);
+ select_memory_manager(mrc_params);
+ }
+ goto mylop;
+ case 'B':
+ select_hte(mrc_params);
+ HteMemOp(0x2340, 1, 1);
+ select_memory_manager(mrc_params);
+ goto mylop;
+
+ case '3':
+ {
+ RegDPMC0 DPMC0reg;
+
+ DPF( D_INFO, "===>> Start suspend\n");
+ isbR32m(MCU, DSTAT);
+
+ DPMC0reg.raw = isbR32m(MCU, DPMC0);
+ DPMC0reg.field.DYNSREN = 0;
+ DPMC0reg.field.powerModeOpCode = 0x05; // Disable Master DLL
+ isbW32m(MCU, DPMC0, DPMC0reg.raw);
+
+ // Should be off for negative test case verification
+ #if 1
+ Wr32(MMIO, PCIADDR(0,0,0,SB_PACKET_REG),
+ (uint32_t)SB_COMMAND(SB_SUSPEND_CMND_OPCODE, MCU, 0));
+ #endif
+
+ DPF( D_INFO, "press key\n");
+ mgetc();
+ DPF( D_INFO, "===>> Start resume\n");
+ isbR32m(MCU, DSTAT);
+
+ mrc_params->boot_mode = bmS3;
+ i = 0;
+ }
+
+ } // switch
+
+ } // if( menu
+#endif //MRC_SV
+
+ if (mrc_params->boot_mode & init[i].boot_path)
+ {
+ uint8_t major = init[i].post_code >> 8 & 0xFF;
+ uint8_t minor = init[i].post_code >> 0 & 0xFF;
+ post_code(major, minor);
+
+ my_tsc = read_tsc();
+ init[i].init_fn(mrc_params);
+ DPF(D_TIME, "Execution time %llX", read_tsc() - my_tsc);
+ }
+ }
+
+ // display the timings
+ print_timings(mrc_params);
+
+ // MRC is complete.
+ post_code(0x01, 0xFF);
+
+ LEAVEFN();
+ return;
+}
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h
new file mode 100644
index 0000000000..e2c126672f
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit.h
@@ -0,0 +1,28 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+#ifndef _MEMINIT_H_
+#define _MEMINIT_H_
+
+// function prototypes
+void MemInit(MRCParams_t *mrc_params);
+
+typedef void (*MemInitFn_t)(MRCParams_t *mrc_params);
+
+typedef struct MemInit_s {
+ uint16_t post_code;
+ uint16_t boot_path;
+ MemInitFn_t init_fn;
+} MemInit_t;
+
+#endif // _MEMINIT_H_
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c
new file mode 100644
index 0000000000..f0c8757b22
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.c
@@ -0,0 +1,1580 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ***************************************************************************/
+
+#include "mrc.h"
+#include "memory_options.h"
+
+#include "meminit_utils.h"
+#include "hte.h"
+#include "io.h"
+
+void select_hte(
+ MRCParams_t *mrc_params);
+
+static uint8_t first_run = 0;
+
+const uint8_t vref_codes[64] =
+{ // lowest to highest
+ 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, // 00 - 15
+ 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, // 16 - 31
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 32 - 47
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F // 48 - 63
+};
+
+#ifdef EMU
+// Track current post code for debugging purpose
+uint32_t PostCode;
+#endif
+
+// set_rcvn:
+//
+// This function will program the RCVEN delays.
+// (currently doesn't comprehend rank)
+void set_rcvn(
+ uint8_t channel,
+ uint8_t rank,
+ uint8_t byte_lane,
+ uint32_t pi_count)
+{
+ uint32_t reg;
+ uint32_t msk;
+ uint32_t tempD;
+
+ ENTERFN();
+ DPF(D_TRN, "Rcvn ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);
+
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // BL0 -> B01PTRCTL0[11:08] (0x0-0xF)
+ // BL1 -> B01PTRCTL0[23:20] (0x0-0xF)
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+ msk = (byte_lane & BIT0) ? (BIT23 | BIT22 | BIT21 | BIT20) : (BIT11 | BIT10 | BIT9 | BIT8);
+ tempD = (byte_lane & BIT0) ? ((pi_count / HALF_CLK) << 20) : ((pi_count / HALF_CLK) << 8);
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // Adjust PI_COUNT
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+ // PI (1/64 MCLK, 1 PIs)
+ // BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)
+ // BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+ msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24);
+ tempD = pi_count << 24;
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // DEADBAND
+ // BL0/1 -> B01DBCTL1[08/11] (+1 select)
+ // BL0/1 -> B01DBCTL1[02/05] (enable)
+ reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+ msk = 0x00;
+ tempD = 0x00;
+ // enable
+ msk |= (byte_lane & BIT0) ? (BIT5) : (BIT2);
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+ {
+ tempD |= msk;
+ }
+ // select
+ msk |= (byte_lane & BIT0) ? (BIT11) : (BIT8);
+ if (pi_count < EARLY_DB)
+ {
+ tempD |= msk;
+ }
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // error check
+ if (pi_count > 0x3F)
+ {
+ training_message(channel, rank, byte_lane);
+ post_code(0xEE, 0xE0);
+ }
+
+ LEAVEFN();
+ return;
+}
+
+// get_rcvn:
+//
+// This function will return the current RCVEN delay on the given channel, rank, byte_lane as an absolute PI count.
+// (currently doesn't comprehend rank)
+uint32_t get_rcvn(
+ uint8_t channel,
+ uint8_t rank,
+ uint8_t byte_lane)
+{
+ uint32_t reg;
+ uint32_t tempD;
+ uint32_t pi_count;
+
+ ENTERFN();
+
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // BL0 -> B01PTRCTL0[11:08] (0x0-0xF)
+ // BL1 -> B01PTRCTL0[23:20] (0x0-0xF)
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= (byte_lane & BIT0) ? (20) : (8);
+ tempD &= 0xF;
+
+ // Adjust PI_COUNT
+ pi_count = tempD * HALF_CLK;
+
+ // PI (1/64 MCLK, 1 PIs)
+ // BL0 -> B0DLLPICODER0[29:24] (0x00-0x3F)
+ // BL1 -> B1DLLPICODER0[29:24] (0x00-0x3F)
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= 24;
+ tempD &= 0x3F;
+
+ // Adjust PI_COUNT
+ pi_count += tempD;
+
+ LEAVEFN();
+ return pi_count;
+}
+
+// set_rdqs:
+//
+// This function will program the RDQS delays based on an absolute amount of PIs.
+// (currently doesn't comprehend rank)
+void set_rdqs(
+ uint8_t channel,
+ uint8_t rank,
+ uint8_t byte_lane,
+ uint32_t pi_count)
+{
+ uint32_t reg;
+ uint32_t msk;
+ uint32_t tempD;
+
+ ENTERFN();
+ DPF(D_TRN, "Rdqs ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);
+
+ // PI (1/128 MCLK)
+ // BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)
+ // BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)
+ reg = (byte_lane & BIT0) ? (B1RXDQSPICODE) : (B0RXDQSPICODE);
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+ msk = (BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+ tempD = pi_count << 0;
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // error check (shouldn't go above 0x3F)
+ if (pi_count > 0x47)
+ {
+ training_message(channel, rank, byte_lane);
+ post_code(0xEE, 0xE1);
+ }
+
+ LEAVEFN();
+ return;
+}
+
+// get_rdqs:
+//
+// This function will return the current RDQS delay on the given channel, rank, byte_lane as an absolute PI count.
+// (currently doesn't comprehend rank)
+uint32_t get_rdqs(
+ uint8_t channel,
+ uint8_t rank,
+ uint8_t byte_lane)
+{
+ uint32_t reg;
+ uint32_t tempD;
+ uint32_t pi_count;
+
+ ENTERFN();
+
+ // PI (1/128 MCLK)
+ // BL0 -> B0RXDQSPICODE[06:00] (0x00-0x47)
+ // BL1 -> B1RXDQSPICODE[06:00] (0x00-0x47)
+ reg = (byte_lane & BIT0) ? (B1RXDQSPICODE) : (B0RXDQSPICODE);
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+ tempD = isbR32m(DDRPHY, reg);
+
+ // Adjust PI_COUNT
+ pi_count = tempD & 0x7F;
+
+ LEAVEFN();
+ return pi_count;
+}
+
+// set_wdqs:
+//
+// This function will program the WDQS delays based on an absolute amount of PIs.
+// (currently doesn't comprehend rank)
+void set_wdqs(
+ uint8_t channel,
+ uint8_t rank,
+ uint8_t byte_lane,
+ uint32_t pi_count)
+{
+ uint32_t reg;
+ uint32_t msk;
+ uint32_t tempD;
+
+ ENTERFN();
+ DPF(D_TRN, "Wdqs ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);
+
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // BL0 -> B01PTRCTL0[07:04] (0x0-0xF)
+ // BL1 -> B01PTRCTL0[19:16] (0x0-0xF)
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+ msk = (byte_lane & BIT0) ? (BIT19 | BIT18 | BIT17 | BIT16) : (BIT7 | BIT6 | BIT5 | BIT4);
+ tempD = pi_count / HALF_CLK;
+ tempD <<= (byte_lane & BIT0) ? (16) : (4);
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // Adjust PI_COUNT
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+ // PI (1/64 MCLK, 1 PIs)
+ // BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)
+ // BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+ msk = (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16);
+ tempD = pi_count << 16;
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // DEADBAND
+ // BL0/1 -> B01DBCTL1[07/10] (+1 select)
+ // BL0/1 -> B01DBCTL1[01/04] (enable)
+ reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+ msk = 0x00;
+ tempD = 0x00;
+ // enable
+ msk |= (byte_lane & BIT0) ? (BIT4) : (BIT1);
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+ {
+ tempD |= msk;
+ }
+ // select
+ msk |= (byte_lane & BIT0) ? (BIT10) : (BIT7);
+ if (pi_count < EARLY_DB)
+ {
+ tempD |= msk;
+ }
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // error check
+ if (pi_count > 0x3F)
+ {
+ training_message(channel, rank, byte_lane);
+ post_code(0xEE, 0xE2);
+ }
+
+ LEAVEFN();
+ return;
+}
+
+// get_wdqs:
+//
+// This function will return the amount of WDQS delay on the given channel, rank, byte_lane as an absolute PI count.
+// (currently doesn't comprehend rank)
+uint32_t get_wdqs(
+ uint8_t channel,
+ uint8_t rank,
+ uint8_t byte_lane)
+{
+ uint32_t reg;
+ uint32_t tempD;
+ uint32_t pi_count;
+
+ ENTERFN();
+
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // BL0 -> B01PTRCTL0[07:04] (0x0-0xF)
+ // BL1 -> B01PTRCTL0[19:16] (0x0-0xF)
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= (byte_lane & BIT0) ? (16) : (4);
+ tempD &= 0xF;
+
+ // Adjust PI_COUNT
+ pi_count = (tempD * HALF_CLK);
+
+ // PI (1/64 MCLK, 1 PIs)
+ // BL0 -> B0DLLPICODER0[21:16] (0x00-0x3F)
+ // BL1 -> B1DLLPICODER0[21:16] (0x00-0x3F)
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= 16;
+ tempD &= 0x3F;
+
+ // Adjust PI_COUNT
+ pi_count += tempD;
+
+ LEAVEFN();
+ return pi_count;
+}
+
+// set_wdq:
+//
+// This function will program the WDQ delays based on an absolute number of PIs.
+// (currently doesn't comprehend rank)
+void set_wdq(
+ uint8_t channel,
+ uint8_t rank,
+ uint8_t byte_lane,
+ uint32_t pi_count)
+{
+ uint32_t reg;
+ uint32_t msk;
+ uint32_t tempD;
+
+ ENTERFN();
+ DPF(D_TRN, "Wdq ch%d rnk%d ln%d : pi=%03X\n", channel, rank, byte_lane, pi_count);
+
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // BL0 -> B01PTRCTL0[03:00] (0x0-0xF)
+ // BL1 -> B01PTRCTL0[15:12] (0x0-0xF)
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+ msk = (byte_lane & BIT0) ? (BIT15 | BIT14 | BIT13 | BIT12) : (BIT3 | BIT2 | BIT1 | BIT0);
+ tempD = pi_count / HALF_CLK;
+ tempD <<= (byte_lane & BIT0) ? (12) : (0);
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // Adjust PI_COUNT
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+ // PI (1/64 MCLK, 1 PIs)
+ // BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)
+ // BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+ msk = (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8);
+ tempD = pi_count << 8;
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // DEADBAND
+ // BL0/1 -> B01DBCTL1[06/09] (+1 select)
+ // BL0/1 -> B01DBCTL1[00/03] (enable)
+ reg = B01DBCTL1 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+ msk = 0x00;
+ tempD = 0x00;
+ // enable
+ msk |= (byte_lane & BIT0) ? (BIT3) : (BIT0);
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+ {
+ tempD |= msk;
+ }
+ // select
+ msk |= (byte_lane & BIT0) ? (BIT9) : (BIT6);
+ if (pi_count < EARLY_DB)
+ {
+ tempD |= msk;
+ }
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // error check
+ if (pi_count > 0x3F)
+ {
+ training_message(channel, rank, byte_lane);
+ post_code(0xEE, 0xE3);
+ }
+
+ LEAVEFN();
+ return;
+}
+
+// get_wdq:
+//
+// This function will return the amount of WDQ delay on the given channel, rank, byte_lane as an absolute PI count.
+// (currently doesn't comprehend rank)
+uint32_t get_wdq(
+ uint8_t channel,
+ uint8_t rank,
+ uint8_t byte_lane)
+{
+ uint32_t reg;
+ uint32_t tempD;
+ uint32_t pi_count;
+
+ ENTERFN();
+
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // BL0 -> B01PTRCTL0[03:00] (0x0-0xF)
+ // BL1 -> B01PTRCTL0[15:12] (0x0-0xF)
+ reg = B01PTRCTL0 + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET);
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= (byte_lane & BIT0) ? (12) : (0);
+ tempD &= 0xF;
+
+ // Adjust PI_COUNT
+ pi_count = (tempD * HALF_CLK);
+
+ // PI (1/64 MCLK, 1 PIs)
+ // BL0 -> B0DLLPICODER0[13:08] (0x00-0x3F)
+ // BL1 -> B1DLLPICODER0[13:08] (0x00-0x3F)
+ reg = (byte_lane & BIT0) ? (B1DLLPICODER0) : (B0DLLPICODER0);
+ reg += (((byte_lane >> 1) * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET));
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= 8;
+ tempD &= 0x3F;
+
+ // Adjust PI_COUNT
+ pi_count += tempD;
+
+ LEAVEFN();
+ return pi_count;
+}
+
+// set_wcmd:
+//
+// This function will program the WCMD delays based on an absolute number of PIs.
+void set_wcmd(
+ uint8_t channel,
+ uint32_t pi_count)
+{
+ uint32_t reg;
+ uint32_t msk;
+ uint32_t tempD;
+
+ ENTERFN();
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // CMDPTRREG[11:08] (0x0-0xF)
+ reg = CMDPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+ msk = (BIT11 | BIT10 | BIT9 | BIT8);
+ tempD = pi_count / HALF_CLK;
+ tempD <<= 8;
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // Adjust PI_COUNT
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+ // PI (1/64 MCLK, 1 PIs)
+ // CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)
+ // CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)
+ // CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)
+ // CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)
+ // CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)
+ // CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)
+ // CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)
+ // CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)
+ reg = CMDDLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET);
+
+ msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24) | (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16)
+ | (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8) | (BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0);
+
+ tempD = (pi_count << 24) | (pi_count << 16) | (pi_count << 8) | (pi_count << 0);
+
+ isbM32m(DDRPHY, reg, tempD, msk);
+ reg = CMDDLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET); // PO
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // DEADBAND
+ // CMDCFGREG0[17] (+1 select)
+ // CMDCFGREG0[16] (enable)
+ reg = CMDCFGREG0 + (channel * DDRIOCCC_CH_OFFSET);
+ msk = 0x00;
+ tempD = 0x00;
+ // enable
+ msk |= BIT16;
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+ {
+ tempD |= msk;
+ }
+ // select
+ msk |= BIT17;
+ if (pi_count < EARLY_DB)
+ {
+ tempD |= msk;
+ }
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // error check
+ if (pi_count > 0x3F)
+ {
+ post_code(0xEE, 0xE4);
+ }
+
+ LEAVEFN();
+ return;
+}
+
+// get_wcmd:
+//
+// This function will return the amount of WCMD delay on the given channel as an absolute PI count.
+uint32_t get_wcmd(
+ uint8_t channel)
+{
+ uint32_t reg;
+ uint32_t tempD;
+ uint32_t pi_count;
+
+ ENTERFN();
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // CMDPTRREG[11:08] (0x0-0xF)
+ reg = CMDPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= 8;
+ tempD &= 0xF;
+
+ // Adjust PI_COUNT
+ pi_count = tempD * HALF_CLK;
+
+ // PI (1/64 MCLK, 1 PIs)
+ // CMDDLLPICODER0[29:24] -> CMDSLICE R3 (unused)
+ // CMDDLLPICODER0[21:16] -> CMDSLICE L3 (unused)
+ // CMDDLLPICODER0[13:08] -> CMDSLICE R2 (unused)
+ // CMDDLLPICODER0[05:00] -> CMDSLICE L2 (unused)
+ // CMDDLLPICODER1[29:24] -> CMDSLICE R1 (unused)
+ // CMDDLLPICODER1[21:16] -> CMDSLICE L1 (0x00-0x3F)
+ // CMDDLLPICODER1[13:08] -> CMDSLICE R0 (unused)
+ // CMDDLLPICODER1[05:00] -> CMDSLICE L0 (unused)
+ reg = CMDDLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET);
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= 16;
+ tempD &= 0x3F;
+
+ // Adjust PI_COUNT
+ pi_count += tempD;
+
+ LEAVEFN();
+ return pi_count;
+}
+
+// set_wclk:
+//
+// This function will program the WCLK delays based on an absolute number of PIs.
+void set_wclk(
+ uint8_t channel,
+ uint8_t rank,
+ uint32_t pi_count)
+{
+ uint32_t reg;
+ uint32_t msk;
+ uint32_t tempD;
+
+ ENTERFN();
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // CCPTRREG[15:12] -> CLK1 (0x0-0xF)
+ // CCPTRREG[11:08] -> CLK0 (0x0-0xF)
+ reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+ msk = (BIT15 | BIT14 | BIT13 | BIT12) | (BIT11 | BIT10 | BIT9 | BIT8);
+ tempD = ((pi_count / HALF_CLK) << 12) | ((pi_count / HALF_CLK) << 8);
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // Adjust PI_COUNT
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+ // PI (1/64 MCLK, 1 PIs)
+ // ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)
+ // ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)
+ reg = (rank) ? (ECCB1DLLPICODER0) : (ECCB1DLLPICODER0);
+ reg += (channel * DDRIOCCC_CH_OFFSET);
+ msk = (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16) | (BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8);
+ tempD = (pi_count << 16) | (pi_count << 8);
+ isbM32m(DDRPHY, reg, tempD, msk);
+ reg = (rank) ? (ECCB1DLLPICODER1) : (ECCB1DLLPICODER1);
+ reg += (channel * DDRIOCCC_CH_OFFSET);
+ isbM32m(DDRPHY, reg, tempD, msk);
+ reg = (rank) ? (ECCB1DLLPICODER2) : (ECCB1DLLPICODER2);
+ reg += (channel * DDRIOCCC_CH_OFFSET);
+ isbM32m(DDRPHY, reg, tempD, msk);
+ reg = (rank) ? (ECCB1DLLPICODER3) : (ECCB1DLLPICODER3);
+ reg += (channel * DDRIOCCC_CH_OFFSET);
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // DEADBAND
+ // CCCFGREG1[11:08] (+1 select)
+ // CCCFGREG1[03:00] (enable)
+ reg = CCCFGREG1 + (channel * DDRIOCCC_CH_OFFSET);
+ msk = 0x00;
+ tempD = 0x00;
+ // enable
+ msk |= (BIT3 | BIT2 | BIT1 | BIT0); // only ??? matters
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+ {
+ tempD |= msk;
+ }
+ // select
+ msk |= (BIT11 | BIT10 | BIT9 | BIT8); // only ??? matters
+ if (pi_count < EARLY_DB)
+ {
+ tempD |= msk;
+ }
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // error check
+ if (pi_count > 0x3F)
+ {
+ post_code(0xEE, 0xE5);
+ }
+
+ LEAVEFN();
+ return;
+}
+
+// get_wclk:
+//
+// This function will return the amout of WCLK delay on the given channel, rank as an absolute PI count.
+uint32_t get_wclk(
+ uint8_t channel,
+ uint8_t rank)
+{
+ uint32_t reg;
+ uint32_t tempD;
+ uint32_t pi_count;
+
+ ENTERFN();
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // CCPTRREG[15:12] -> CLK1 (0x0-0xF)
+ // CCPTRREG[11:08] -> CLK0 (0x0-0xF)
+ reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= (rank) ? (12) : (8);
+ tempD &= 0xF;
+
+ // Adjust PI_COUNT
+ pi_count = tempD * HALF_CLK;
+
+ // PI (1/64 MCLK, 1 PIs)
+ // ECCB1DLLPICODER0[13:08] -> CLK0 (0x00-0x3F)
+ // ECCB1DLLPICODER0[21:16] -> CLK1 (0x00-0x3F)
+ reg = (rank) ? (ECCB1DLLPICODER0) : (ECCB1DLLPICODER0);
+ reg += (channel * DDRIOCCC_CH_OFFSET);
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= (rank) ? (16) : (8);
+ tempD &= 0x3F;
+
+ pi_count += tempD;
+
+ LEAVEFN();
+ return pi_count;
+}
+
+// set_wctl:
+//
+// This function will program the WCTL delays based on an absolute number of PIs.
+// (currently doesn't comprehend rank)
+void set_wctl(
+ uint8_t channel,
+ uint8_t rank,
+ uint32_t pi_count)
+{
+ uint32_t reg;
+ uint32_t msk;
+ uint32_t tempD;
+
+ ENTERFN();
+
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // CCPTRREG[31:28] (0x0-0xF)
+ // CCPTRREG[27:24] (0x0-0xF)
+ reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+ msk = (BIT31 | BIT30 | BIT29 | BIT28) | (BIT27 | BIT26 | BIT25 | BIT24);
+ tempD = ((pi_count / HALF_CLK) << 28) | ((pi_count / HALF_CLK) << 24);
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // Adjust PI_COUNT
+ pi_count -= ((pi_count / HALF_CLK) & 0xF) * HALF_CLK;
+
+ // PI (1/64 MCLK, 1 PIs)
+ // ECCB1DLLPICODER?[29:24] (0x00-0x3F)
+ // ECCB1DLLPICODER?[29:24] (0x00-0x3F)
+ reg = ECCB1DLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET);
+ msk = (BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24);
+ tempD = (pi_count << 24);
+ isbM32m(DDRPHY, reg, tempD, msk);
+ reg = ECCB1DLLPICODER1 + (channel * DDRIOCCC_CH_OFFSET);
+ isbM32m(DDRPHY, reg, tempD, msk);
+ reg = ECCB1DLLPICODER2 + (channel * DDRIOCCC_CH_OFFSET);
+ isbM32m(DDRPHY, reg, tempD, msk);
+ reg = ECCB1DLLPICODER3 + (channel * DDRIOCCC_CH_OFFSET);
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // DEADBAND
+ // CCCFGREG1[13:12] (+1 select)
+ // CCCFGREG1[05:04] (enable)
+ reg = CCCFGREG1 + (channel * DDRIOCCC_CH_OFFSET);
+ msk = 0x00;
+ tempD = 0x00;
+ // enable
+ msk |= (BIT5 | BIT4); // only ??? matters
+ if ((pi_count < EARLY_DB) || (pi_count > LATE_DB))
+ {
+ tempD |= msk;
+ }
+ // select
+ msk |= (BIT13 | BIT12); // only ??? matters
+ if (pi_count < EARLY_DB)
+ {
+ tempD |= msk;
+ }
+ isbM32m(DDRPHY, reg, tempD, msk);
+
+ // error check
+ if (pi_count > 0x3F)
+ {
+ post_code(0xEE, 0xE6);
+ }
+
+ LEAVEFN();
+ return;
+}
+
+// get_wctl:
+//
+// This function will return the amount of WCTL delay on the given channel, rank as an absolute PI count.
+// (currently doesn't comprehend rank)
+uint32_t get_wctl(
+ uint8_t channel,
+ uint8_t rank)
+{
+ uint32_t reg;
+ uint32_t tempD;
+ uint32_t pi_count;
+
+ ENTERFN();
+
+ // RDPTR (1/2 MCLK, 64 PIs)
+ // CCPTRREG[31:28] (0x0-0xF)
+ // CCPTRREG[27:24] (0x0-0xF)
+ reg = CCPTRREG + (channel * DDRIOCCC_CH_OFFSET);
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= 24;
+ tempD &= 0xF;
+
+ // Adjust PI_COUNT
+ pi_count = tempD * HALF_CLK;
+
+ // PI (1/64 MCLK, 1 PIs)
+ // ECCB1DLLPICODER?[29:24] (0x00-0x3F)
+ // ECCB1DLLPICODER?[29:24] (0x00-0x3F)
+ reg = ECCB1DLLPICODER0 + (channel * DDRIOCCC_CH_OFFSET);
+ tempD = isbR32m(DDRPHY, reg);
+ tempD >>= 24;
+ tempD &= 0x3F;
+
+ // Adjust PI_COUNT
+ pi_count += tempD;
+
+ LEAVEFN();
+ return pi_count;
+}
+
+// set_vref:
+//
+// This function will program the internal Vref setting in a given byte lane in a given channel.
+void set_vref(
+ uint8_t channel,
+ uint8_t byte_lane,
+ uint32_t setting)
+{
+ uint32_t reg = (byte_lane & 0x1) ? (B1VREFCTL) : (B0VREFCTL);
+
+ ENTERFN();
+ DPF(D_TRN, "Vref ch%d ln%d : val=%03X\n", channel, byte_lane, setting);
+
+ isbM32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)),
+ (vref_codes[setting] << 2), (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2));
+ //isbM32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)), (setting<<2), (BIT7|BIT6|BIT5|BIT4|BIT3|BIT2));
+ // need to wait ~300ns for Vref to settle (check that this is necessary)
+ delay_n(300);
+ // ??? may need to clear pointers ???
+ LEAVEFN();
+ return;
+}
+
+// get_vref:
+//
+// This function will return the internal Vref setting for the given channel, byte_lane;
+uint32_t get_vref(
+ uint8_t channel,
+ uint8_t byte_lane)
+{
+ uint8_t j;
+ uint32_t ret_val = sizeof(vref_codes) / 2;
+ uint32_t reg = (byte_lane & 0x1) ? (B1VREFCTL) : (B0VREFCTL);
+
+ uint32_t tempD;
+
+ ENTERFN();
+ tempD = isbR32m(DDRPHY, (reg + (channel * DDRIODQ_CH_OFFSET) + ((byte_lane >> 1) * DDRIODQ_BL_OFFSET)));
+ tempD >>= 2;
+ tempD &= 0x3F;
+ for (j = 0; j < sizeof(vref_codes); j++)
+ {
+ if (vref_codes[j] == tempD)
+ {
+ ret_val = j;
+ break;
+ }
+ }
+ LEAVEFN();
+ return ret_val;
+}
+
+// clear_pointers:
+//
+// This function will be used to clear the pointers in a given byte lane in a given channel.
+void clear_pointers(
+ void)
+{
+ uint8_t channel_i;
+ uint8_t bl_i;
+
+ ENTERFN();
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ for (bl_i = 0; bl_i < NUM_BYTE_LANES; bl_i++)
+ {
+ isbM32m(DDRPHY, (B01PTRCTL1 + (channel_i * DDRIODQ_CH_OFFSET) + ((bl_i >> 1) * DDRIODQ_BL_OFFSET)), ~(BIT8),
+ (BIT8));
+ //delay_m(1); // DEBUG
+ isbM32m(DDRPHY, (B01PTRCTL1 + (channel_i * DDRIODQ_CH_OFFSET) + ((bl_i >> 1) * DDRIODQ_BL_OFFSET)), (BIT8),
+ (BIT8));
+ }
+ }
+ LEAVEFN();
+ return;
+}
+
+// void enable_cache:
+void enable_cache(
+ void)
+{
+ // Cache control not used in Quark MRC
+ return;
+}
+
+// void disable_cache:
+void disable_cache(
+ void)
+{
+ // Cache control not used in Quark MRC
+ return;
+}
+
+// Send DRAM command, data should be formated
+// using DCMD_Xxxx macro or emrsXCommand structure.
+static void dram_init_command(
+ uint32_t data)
+{
+ Wr32(DCMD, 0, data);
+}
+
+// find_rising_edge:
+//
+// This function will find the rising edge transition on RCVN or WDQS.
+void find_rising_edge(
+ MRCParams_t *mrc_params,
+ uint32_t delay[],
+ uint8_t channel,
+ uint8_t rank,
+ bool rcvn)
+{
+
+#define SAMPLE_CNT 3 // number of sample points
+#define SAMPLE_DLY 26 // number of PIs to increment per sample
+#define FORWARD true // indicates to increase delays when looking for edge
+#define BACKWARD false // indicates to decrease delays when looking for edge
+
+ bool all_edges_found; // determines stop condition
+ bool direction[NUM_BYTE_LANES]; // direction indicator
+ uint8_t sample_i; // sample counter
+ uint8_t bl_i; // byte lane counter
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+ uint32_t sample_result[SAMPLE_CNT]; // results of "sample_dqs()"
+ uint32_t tempD; // temporary DWORD
+ uint32_t transition_pattern;
+
+ ENTERFN();
+
+ // select hte and request initial configuration
+ select_hte(mrc_params);
+ first_run = 1;
+
+ // Take 3 sample points (T1,T2,T3) to obtain a transition pattern.
+ for (sample_i = 0; sample_i < SAMPLE_CNT; sample_i++)
+ {
+ // program the desired delays for sample
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ // increase sample delay by 26 PI (0.2 CLK)
+ if (rcvn)
+ {
+ set_rcvn(channel, rank, bl_i, delay[bl_i] + (sample_i * SAMPLE_DLY));
+ }
+ else
+ {
+ set_wdqs(channel, rank, bl_i, delay[bl_i] + (sample_i * SAMPLE_DLY));
+ }
+ } // bl_i loop
+ // take samples (Tsample_i)
+ sample_result[sample_i] = sample_dqs(mrc_params, channel, rank, rcvn);
+
+ DPF(D_TRN, "Find rising edge %s ch%d rnk%d: #%d dly=%d dqs=%02X\n",
+ (rcvn ? "RCVN" : "WDQS"), channel, rank,
+ sample_i, sample_i * SAMPLE_DLY, sample_result[sample_i]);
+
+ } // sample_i loop
+
+ // This pattern will help determine where we landed and ultimately how to place RCVEN/WDQS.
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ // build "transition_pattern" (MSB is 1st sample)
+ transition_pattern = 0x00;
+ for (sample_i = 0; sample_i < SAMPLE_CNT; sample_i++)
+ {
+ transition_pattern |= ((sample_result[sample_i] & (1 << bl_i)) >> bl_i) << (SAMPLE_CNT - 1 - sample_i);
+ } // sample_i loop
+
+ DPF(D_TRN, "=== transition pattern %d\n", transition_pattern);
+
+ // set up to look for rising edge based on "transition_pattern"
+ switch (transition_pattern)
+ {
+ case 0x00: // sampled 0->0->0
+ // move forward from T3 looking for 0->1
+ delay[bl_i] += 2 * SAMPLE_DLY;
+ direction[bl_i] = FORWARD;
+ break;
+ case 0x01: // sampled 0->0->1
+ case 0x05: // sampled 1->0->1 (bad duty cycle) *HSD#237503*
+ // move forward from T2 looking for 0->1
+ delay[bl_i] += 1 * SAMPLE_DLY;
+ direction[bl_i] = FORWARD;
+ break;
+// HSD#237503
+// case 0x02: // sampled 0->1->0 (bad duty cycle)
+// training_message(channel, rank, bl_i);
+// post_code(0xEE, 0xE8);
+// break;
+ case 0x02: // sampled 0->1->0 (bad duty cycle) *HSD#237503*
+ case 0x03: // sampled 0->1->1
+ // move forward from T1 looking for 0->1
+ delay[bl_i] += 0 * SAMPLE_DLY;
+ direction[bl_i] = FORWARD;
+ break;
+ case 0x04: // sampled 1->0->0 (assumes BL8, HSD#234975)
+ // move forward from T3 looking for 0->1
+ delay[bl_i] += 2 * SAMPLE_DLY;
+ direction[bl_i] = FORWARD;
+ break;
+// HSD#237503
+// case 0x05: // sampled 1->0->1 (bad duty cycle)
+// training_message(channel, rank, bl_i);
+// post_code(0xEE, 0xE9);
+// break;
+ case 0x06: // sampled 1->1->0
+ case 0x07: // sampled 1->1->1
+ // move backward from T1 looking for 1->0
+ delay[bl_i] += 0 * SAMPLE_DLY;
+ direction[bl_i] = BACKWARD;
+ break;
+ default:
+ post_code(0xEE, 0xEE);
+ break;
+ } // transition_pattern switch
+ // program delays
+ if (rcvn)
+ {
+ set_rcvn(channel, rank, bl_i, delay[bl_i]);
+ }
+ else
+ {
+ set_wdqs(channel, rank, bl_i, delay[bl_i]);
+ }
+ } // bl_i loop
+
+ // Based on the observed transition pattern on the byte lane,
+ // begin looking for a rising edge with single PI granularity.
+ do
+ {
+ all_edges_found = true; // assume all byte lanes passed
+ tempD = sample_dqs(mrc_params, channel, rank, rcvn); // take a sample
+ // check all each byte lane for proper edge
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ if (tempD & (1 << bl_i))
+ {
+ // sampled "1"
+ if (direction[bl_i] == BACKWARD)
+ {
+ // keep looking for edge on this byte lane
+ all_edges_found = false;
+ delay[bl_i] -= 1;
+ if (rcvn)
+ {
+ set_rcvn(channel, rank, bl_i, delay[bl_i]);
+ }
+ else
+ {
+ set_wdqs(channel, rank, bl_i, delay[bl_i]);
+ }
+ }
+ }
+ else
+ {
+ // sampled "0"
+ if (direction[bl_i] == FORWARD)
+ {
+ // keep looking for edge on this byte lane
+ all_edges_found = false;
+ delay[bl_i] += 1;
+ if (rcvn)
+ {
+ set_rcvn(channel, rank, bl_i, delay[bl_i]);
+ }
+ else
+ {
+ set_wdqs(channel, rank, bl_i, delay[bl_i]);
+ }
+ }
+ }
+ } // bl_i loop
+ } while (!all_edges_found);
+
+ // restore DDR idle state
+ dram_init_command(DCMD_PREA(rank));
+
+ DPF(D_TRN, "Delay %03X %03X %03X %03X\n",
+ delay[0], delay[1], delay[2], delay[3]);
+
+ LEAVEFN();
+ return;
+}
+
+// sample_dqs:
+//
+// This function will sample the DQTRAINSTS registers in the given channel/rank SAMPLE_SIZE times looking for a valid '0' or '1'.
+// It will return an encoded DWORD in which each bit corresponds to the sampled value on the byte lane.
+uint32_t sample_dqs(
+ MRCParams_t *mrc_params,
+ uint8_t channel,
+ uint8_t rank,
+ bool rcvn)
+{
+ uint8_t j; // just a counter
+ uint8_t bl_i; // which BL in the module (always 2 per module)
+ uint8_t bl_grp; // which BL module
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1; // byte lane divisor
+ uint32_t msk[2]; // BLx in module
+ uint32_t sampled_val[SAMPLE_SIZE]; // DQTRAINSTS register contents for each sample
+ uint32_t num_0s; // tracks the number of '0' samples
+ uint32_t num_1s; // tracks the number of '1' samples
+ uint32_t ret_val = 0x00; // assume all '0' samples
+ uint32_t address = get_addr(mrc_params, channel, rank);
+
+ // initialise "msk[]"
+ msk[0] = (rcvn) ? (BIT1) : (BIT9); // BL0
+ msk[1] = (rcvn) ? (BIT0) : (BIT8); // BL1
+
+
+ // cycle through each byte lane group
+ for (bl_grp = 0; bl_grp < (NUM_BYTE_LANES / bl_divisor) / 2; bl_grp++)
+ {
+ // take SAMPLE_SIZE samples
+ for (j = 0; j < SAMPLE_SIZE; j++)
+ {
+ HteMemOp(address, first_run, rcvn?0:1);
+ first_run = 0;
+
+ // record the contents of the proper DQTRAINSTS register
+ sampled_val[j] = isbR32m(DDRPHY, (DQTRAINSTS + (bl_grp * DDRIODQ_BL_OFFSET) + (channel * DDRIODQ_CH_OFFSET)));
+ }
+ // look for a majority value ( (SAMPLE_SIZE/2)+1 ) on the byte lane
+ // and set that value in the corresponding "ret_val" bit
+ for (bl_i = 0; bl_i < 2; bl_i++)
+ {
+ num_0s = 0x00; // reset '0' tracker for byte lane
+ num_1s = 0x00; // reset '1' tracker for byte lane
+ for (j = 0; j < SAMPLE_SIZE; j++)
+ {
+ if (sampled_val[j] & msk[bl_i])
+ {
+ num_1s++;
+ }
+ else
+ {
+ num_0s++;
+ }
+ }
+ if (num_1s > num_0s)
+ {
+ ret_val |= (1 << (bl_i + (bl_grp * 2)));
+ }
+ }
+ }
+
+ // "ret_val.0" contains the status of BL0
+ // "ret_val.1" contains the status of BL1
+ // "ret_val.2" contains the status of BL2
+ // etc.
+ return ret_val;
+}
+
+// get_addr:
+//
+// This function will return a 32 bit address in the desired channel and rank.
+uint32_t get_addr(
+ MRCParams_t *mrc_params,
+ uint8_t channel,
+ uint8_t rank)
+{
+ uint32_t offset = 0x02000000; // 32MB
+
+ // Begin product specific code
+ if (channel > 0)
+ {
+ DPF(D_ERROR, "ILLEGAL CHANNEL\n");
+ DEAD_LOOP();
+ }
+
+ if (rank > 1)
+ {
+ DPF(D_ERROR, "ILLEGAL RANK\n");
+ DEAD_LOOP();
+ }
+
+ // use 256MB lowest density as per DRP == 0x0003
+ offset += rank * (256 * 1024 * 1024);
+
+ return offset;
+}
+
+// byte_lane_mask:
+//
+// This function will return a 32 bit mask that will be used to check for byte lane failures.
+uint32_t byte_lane_mask(
+ MRCParams_t *mrc_params)
+{
+ uint32_t j;
+ uint32_t ret_val = 0x00;
+
+ // set "ret_val" based on NUM_BYTE_LANES such that you will check only BL0 in "result"
+ // (each bit in "result" represents a byte lane)
+ for (j = 0; j < MAX_BYTE_LANES; j += NUM_BYTE_LANES)
+ {
+ ret_val |= (1 << ((j / NUM_BYTE_LANES) * NUM_BYTE_LANES));
+ }
+
+ // HSD#235037
+ // need to adjust the mask for 16-bit mode
+ if (mrc_params->channel_width == x16)
+ {
+ ret_val |= (ret_val << 2);
+ }
+
+ return ret_val;
+}
+
+
+// read_tsc:
+//
+// This function will do some assembly to return TSC register contents as a uint64_t.
+uint64_t read_tsc(
+ void)
+{
+ volatile uint64_t tsc; // EDX:EAX
+
+#if defined (SIM) || defined (GCC)
+ volatile uint32_t tscH; // EDX
+ volatile uint32_t tscL;// EAX
+
+ asm("rdtsc":"=a"(tscL),"=d"(tscH));
+ tsc = tscH;
+ tsc = (tsc<<32)|tscL;
+#else
+ tsc = __rdtsc();
+#endif
+
+ return tsc;
+}
+
+// get_tsc_freq:
+//
+// This function returns the TSC frequency in MHz
+uint32_t get_tsc_freq(
+ void)
+{
+ static uint32_t freq[] =
+ { 533, 400, 200, 100 };
+ uint32_t fuse;
+#if 0
+ fuse = (isbR32m(FUSE, 0) >> 12) & (BIT1|BIT0);
+#else
+ // todo!!! Fixed 533MHz for emulation or debugging
+ fuse = 0;
+#endif
+ return freq[fuse];
+}
+
+#ifndef SIM
+// delay_n:
+//
+// This is a simple delay function.
+// It takes "nanoseconds" as a parameter.
+void delay_n(
+ uint32_t nanoseconds)
+{
+ // 1000 MHz clock has 1ns period --> no conversion required
+ uint64_t final_tsc = read_tsc();
+ final_tsc += ((get_tsc_freq() * (nanoseconds)) / 1000);
+
+ while (read_tsc() < final_tsc)
+ ;
+ return;
+}
+#endif
+
+// delay_u:
+//
+// This is a simple delay function.
+// It takes "microseconds as a parameter.
+void delay_u(
+ uint32_t microseconds)
+{
+ // 64 bit math is not an option, just use loops
+ while (microseconds--)
+ {
+ delay_n(1000);
+ }
+ return;
+}
+
+// delay_m:
+//
+// This is a simple delay function.
+// It takes "milliseconds" as a parameter.
+void delay_m(
+ uint32_t milliseconds)
+{
+ // 64 bit math is not an option, just use loops
+ while (milliseconds--)
+ {
+ delay_u(1000);
+ }
+ return;
+}
+
+// delay_s:
+//
+// This is a simple delay function.
+// It takes "seconds" as a parameter.
+void delay_s(
+ uint32_t seconds)
+{
+ // 64 bit math is not an option, just use loops
+ while (seconds--)
+ {
+ delay_m(1000);
+ }
+ return;
+}
+
+// post_code:
+//
+// This function will output the POST CODE to the four 7-Segment LED displays.
+void post_code(
+ uint8_t major,
+ uint8_t minor)
+{
+#ifdef EMU
+ // Update global variable for execution tracking in debug env
+ PostCode = ((major << 8) | minor);
+#endif
+
+ // send message to UART
+ DPF(D_INFO, "POST: 0x%01X%02X\n", major, minor);
+
+ // error check:
+ if (major == 0xEE)
+ {
+ // todo!!! Consider updating error status and exit MRC
+#ifdef SIM
+ // enable Ctrl-C handling
+ for(;;) delay_n(100);
+#else
+ DEAD_LOOP();
+#endif
+ }
+}
+
+void training_message(
+ uint8_t channel,
+ uint8_t rank,
+ uint8_t byte_lane)
+{
+ // send message to UART
+ DPF(D_INFO, "CH%01X RK%01X BL%01X\n", channel, rank, byte_lane);
+ return;
+}
+
+void print_timings(
+ MRCParams_t *mrc_params)
+{
+ uint8_t algo_i;
+ uint8_t channel_i;
+ uint8_t rank_i;
+ uint8_t bl_i;
+ uint8_t bl_divisor = (mrc_params->channel_width == x16) ? 2 : 1;
+
+ DPF(D_INFO, "\n---------------------------");
+ DPF(D_INFO, "\nALGO[CH:RK] BL0 BL1 BL2 BL3");
+ DPF(D_INFO, "\n===========================");
+ for (algo_i = 0; algo_i < eMAX_ALGOS; algo_i++)
+ {
+ for (channel_i = 0; channel_i < NUM_CHANNELS; channel_i++)
+ {
+ if (mrc_params->channel_enables & (1 << channel_i))
+ {
+ for (rank_i = 0; rank_i < NUM_RANKS; rank_i++)
+ {
+ if (mrc_params->rank_enables & (1 << rank_i))
+ {
+ switch (algo_i)
+ {
+ case eRCVN:
+ DPF(D_INFO, "\nRCVN[%02d:%02d]", channel_i, rank_i);
+ break;
+ case eWDQS:
+ DPF(D_INFO, "\nWDQS[%02d:%02d]", channel_i, rank_i);
+ break;
+ case eWDQx:
+ DPF(D_INFO, "\nWDQx[%02d:%02d]", channel_i, rank_i);
+ break;
+ case eRDQS:
+ DPF(D_INFO, "\nRDQS[%02d:%02d]", channel_i, rank_i);
+ break;
+ case eVREF:
+ DPF(D_INFO, "\nVREF[%02d:%02d]", channel_i, rank_i);
+ break;
+ case eWCMD:
+ DPF(D_INFO, "\nWCMD[%02d:%02d]", channel_i, rank_i);
+ break;
+ case eWCTL:
+ DPF(D_INFO, "\nWCTL[%02d:%02d]", channel_i, rank_i);
+ break;
+ case eWCLK:
+ DPF(D_INFO, "\nWCLK[%02d:%02d]", channel_i, rank_i);
+ break;
+ default:
+ break;
+ } // algo_i switch
+ for (bl_i = 0; bl_i < (NUM_BYTE_LANES / bl_divisor); bl_i++)
+ {
+ switch (algo_i)
+ {
+ case eRCVN:
+ DPF(D_INFO, " %03d", get_rcvn(channel_i, rank_i, bl_i));
+ break;
+ case eWDQS:
+ DPF(D_INFO, " %03d", get_wdqs(channel_i, rank_i, bl_i));
+ break;
+ case eWDQx:
+ DPF(D_INFO, " %03d", get_wdq(channel_i, rank_i, bl_i));
+ break;
+ case eRDQS:
+ DPF(D_INFO, " %03d", get_rdqs(channel_i, rank_i, bl_i));
+ break;
+ case eVREF:
+ DPF(D_INFO, " %03d", get_vref(channel_i, bl_i));
+ break;
+ case eWCMD:
+ DPF(D_INFO, " %03d", get_wcmd(channel_i));
+ break;
+ case eWCTL:
+ DPF(D_INFO, " %03d", get_wctl(channel_i, rank_i));
+ break;
+ case eWCLK:
+ DPF(D_INFO, " %03d", get_wclk(channel_i, rank_i));
+ break;
+ default:
+ break;
+ } // algo_i switch
+ } // bl_i loop
+ } // if rank_i enabled
+ } // rank_i loop
+ } // if channel_i enabled
+ } // channel_i loop
+ } // algo_i loop
+ DPF(D_INFO, "\n---------------------------");
+ DPF(D_INFO, "\n");
+ return;
+}
+
+// 32 bit LFSR with characteristic polynomial: X^32 + X^22 +X^2 + X^1
+// The function takes pointer to previous 32 bit value and modifies it to next value.
+void lfsr32(
+ uint32_t *lfsr_ptr)
+{
+ uint32_t bit;
+ uint32_t lfsr;
+ uint32_t i;
+
+ lfsr = *lfsr_ptr;
+
+ for (i = 0; i < 32; i++)
+ {
+ bit = 1 ^ (lfsr & BIT0);
+ bit = bit ^ ((lfsr & BIT1) >> 1);
+ bit = bit ^ ((lfsr & BIT2) >> 2);
+ bit = bit ^ ((lfsr & BIT22) >> 22);
+
+ lfsr = ((lfsr >> 1) | (bit << 31));
+ }
+
+ *lfsr_ptr = lfsr;
+ return;
+}
+
+// The purpose of this function is to ensure the SEC comes out of reset
+// and IA initiates the SEC enabling Memory Scrambling.
+void enable_scrambling(
+ MRCParams_t *mrc_params)
+{
+ uint32_t lfsr = 0;
+ uint8_t i;
+
+ if (mrc_params->scrambling_enables == 0)
+ return;
+
+ ENTERFN();
+
+ // 32 bit seed is always stored in BIOS NVM.
+ lfsr = mrc_params->timings.scrambler_seed;
+
+ if (mrc_params->boot_mode == bmCold)
+ {
+ // factory value is 0 and in first boot, a clock based seed is loaded.
+ if (lfsr == 0)
+ {
+ lfsr = read_tsc() & 0x0FFFFFFF; // get seed from system clock and make sure it is not all 1's
+ }
+ // need to replace scrambler
+ // get next 32bit LFSR 16 times which is the last part of the previous scrambler vector.
+ else
+ {
+ for (i = 0; i < 16; i++)
+ {
+ lfsr32(&lfsr);
+ }
+ }
+ mrc_params->timings.scrambler_seed = lfsr; // save new seed.
+ } // if (cold_boot)
+
+ // In warm boot or S3 exit, we have the previous seed.
+ // In cold boot, we have the last 32bit LFSR which is the new seed.
+ lfsr32(&lfsr); // shift to next value
+ isbW32m(MCU, SCRMSEED, (lfsr & 0x0003FFFF));
+ for (i = 0; i < 2; i++)
+ {
+ isbW32m(MCU, SCRMLO + i, (lfsr & 0xAAAAAAAA));
+ }
+
+ LEAVEFN();
+ return;
+}
+
+// This function will store relevant timing data
+// This data will be used on subsequent boots to speed up boot times
+// and is required for Suspend To RAM capabilities.
+void store_timings(
+ MRCParams_t *mrc_params)
+{
+ uint8_t ch, rk, bl;
+ MrcTimings_t *mt = &mrc_params->timings;
+
+ for (ch = 0; ch < NUM_CHANNELS; ch++)
+ {
+ for (rk = 0; rk < NUM_RANKS; rk++)
+ {
+ for (bl = 0; bl < NUM_BYTE_LANES; bl++)
+ {
+ mt->rcvn[ch][rk][bl] = get_rcvn(ch, rk, bl); // RCVN
+ mt->rdqs[ch][rk][bl] = get_rdqs(ch, rk, bl); // RDQS
+ mt->wdqs[ch][rk][bl] = get_wdqs(ch, rk, bl); // WDQS
+ mt->wdq[ch][rk][bl] = get_wdq(ch, rk, bl); // WDQ
+ if (rk == 0)
+ {
+ mt->vref[ch][bl] = get_vref(ch, bl); // VREF (RANK0 only)
+ }
+ }
+ mt->wctl[ch][rk] = get_wctl(ch, rk); // WCTL
+ }
+ mt->wcmd[ch] = get_wcmd(ch); // WCMD
+ }
+
+ // need to save for a case of changing frequency after warm reset
+ mt->ddr_speed = mrc_params->ddr_speed;
+
+ return;
+}
+
+// This function will retrieve relevant timing data
+// This data will be used on subsequent boots to speed up boot times
+// and is required for Suspend To RAM capabilities.
+void restore_timings(
+ MRCParams_t *mrc_params)
+{
+ uint8_t ch, rk, bl;
+ const MrcTimings_t *mt = &mrc_params->timings;
+
+ for (ch = 0; ch < NUM_CHANNELS; ch++)
+ {
+ for (rk = 0; rk < NUM_RANKS; rk++)
+ {
+ for (bl = 0; bl < NUM_BYTE_LANES; bl++)
+ {
+ set_rcvn(ch, rk, bl, mt->rcvn[ch][rk][bl]); // RCVN
+ set_rdqs(ch, rk, bl, mt->rdqs[ch][rk][bl]); // RDQS
+ set_wdqs(ch, rk, bl, mt->wdqs[ch][rk][bl]); // WDQS
+ set_wdq(ch, rk, bl, mt->wdq[ch][rk][bl]); // WDQ
+ if (rk == 0)
+ {
+ set_vref(ch, bl, mt->vref[ch][bl]); // VREF (RANK0 only)
+ }
+ }
+ set_wctl(ch, rk, mt->wctl[ch][rk]); // WCTL
+ }
+ set_wcmd(ch, mt->wcmd[ch]); // WCMD
+ }
+
+ return;
+}
+
+// Configure default settings normally set as part of read training
+// Some defaults have to be set earlier as they may affect earlier
+// training steps.
+void default_timings(
+ MRCParams_t *mrc_params)
+{
+ uint8_t ch, rk, bl;
+
+ for (ch = 0; ch < NUM_CHANNELS; ch++)
+ {
+ for (rk = 0; rk < NUM_RANKS; rk++)
+ {
+ for (bl = 0; bl < NUM_BYTE_LANES; bl++)
+ {
+ set_rdqs(ch, rk, bl, 24); // RDQS
+ if (rk == 0)
+ {
+ set_vref(ch, bl, 32); // VREF (RANK0 only)
+ }
+ }
+ }
+ }
+
+ return;
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h
new file mode 100644
index 0000000000..04c59f5af0
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/meminit_utils.h
@@ -0,0 +1,97 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ***************************************************************************/
+#ifndef _MEMINIT_UTILS_H_
+#define _MEMINIT_UTILS_H_
+
+// General Definitions:
+#ifdef QUICKSIM
+#define SAMPLE_SIZE 4 // reduce number of training samples in simulation env
+#else
+#define SAMPLE_SIZE 6 // must be odd number
+#endif
+
+#define EARLY_DB (0x12) // must be less than this number to enable early deadband
+#define LATE_DB (0x34) // must be greater than this number to enable late deadband
+#define CHX_REGS (11*4)
+#define FULL_CLK 128
+#define HALF_CLK 64
+#define QRTR_CLK 32
+
+
+
+#define MCEIL(num,den) ((uint8_t)((num+den-1)/den))
+#define MMAX(a,b) ((((int32_t)(a))>((int32_t)(b)))?(a):(b))
+#define MCOUNT(a) (sizeof(a)/sizeof(*a))
+
+typedef enum ALGOS_enum {
+ eRCVN = 0,
+ eWDQS,
+ eWDQx,
+ eRDQS,
+ eVREF,
+ eWCMD,
+ eWCTL,
+ eWCLK,
+ eMAX_ALGOS,
+} ALGOs_t;
+
+
+// Prototypes:
+void set_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
+void set_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
+void set_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
+void set_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane, uint32_t pi_count);
+void set_wcmd(uint8_t channel, uint32_t pi_count);
+void set_wclk(uint8_t channel, uint8_t grp, uint32_t pi_count);
+void set_wctl(uint8_t channel, uint8_t rank, uint32_t pi_count);
+void set_vref(uint8_t channel, uint8_t byte_lane, uint32_t setting);
+uint32_t get_rcvn(uint8_t channel, uint8_t rank, uint8_t byte_lane);
+uint32_t get_rdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane);
+uint32_t get_wdqs(uint8_t channel, uint8_t rank, uint8_t byte_lane);
+uint32_t get_wdq(uint8_t channel, uint8_t rank, uint8_t byte_lane);
+uint32_t get_wcmd(uint8_t channel);
+uint32_t get_wclk(uint8_t channel, uint8_t group);
+uint32_t get_wctl(uint8_t channel, uint8_t rank);
+uint32_t get_vref(uint8_t channel, uint8_t byte_lane);
+
+void clear_pointers(void);
+void enable_cache(void);
+void disable_cache(void);
+void find_rising_edge(MRCParams_t *mrc_params, uint32_t delay[], uint8_t channel, uint8_t rank, bool rcvn);
+uint32_t sample_dqs(MRCParams_t *mrc_params, uint8_t channel, uint8_t rank, bool rcvn);
+uint32_t get_addr(MRCParams_t *mrc_params, uint8_t channel, uint8_t rank);
+uint32_t byte_lane_mask(MRCParams_t *mrc_params);
+
+uint64_t read_tsc(void);
+uint32_t get_tsc_freq(void);
+void delay_n(uint32_t nanoseconds);
+void delay_u(uint32_t microseconds);
+void delay_m(uint32_t milliseconds);
+void delay_s(uint32_t seconds);
+
+void post_code(uint8_t major, uint8_t minor);
+void training_message(uint8_t channel, uint8_t rank, uint8_t byte_lane);
+void print_timings(MRCParams_t *mrc_params);
+
+void enable_scrambling(MRCParams_t *mrc_params);
+void store_timings(MRCParams_t *mrc_params);
+void restore_timings(MRCParams_t *mrc_params);
+void default_timings(MRCParams_t *mrc_params);
+
+#ifndef SIM
+void *memset(void *d, int c, size_t n);
+void *memcpy(void *d, const void *s, size_t n);
+#endif
+
+#endif // _MEMINIT_UTILS_H_
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h
new file mode 100644
index 0000000000..8452b98814
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/memory_options.h
@@ -0,0 +1,83 @@
+/** @file
+Common definitions and compilation switches for MRC
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef __MEMORY_OPTIONS_H
+#define __MEMORY_OPTIONS_H
+
+#include "core_types.h"
+
+// MRC COMPILE TIME SWITCHES:
+// ==========================
+
+
+
+//#define MRC_SV // enable some validation opitons
+
+#if defined (SIM) || defined(EMU)
+#define QUICKSIM // reduce execution time using shorter rd/wr sequences
+#endif
+
+#define CLT // required for Quark project
+
+
+
+//#define BACKUP_RCVN // enable STATIC timing settings for RCVN (BACKUP_MODE)
+//#define BACKUP_WDQS // enable STATIC timing settings for WDQS (BACKUP_MODE)
+//#define BACKUP_RDQS // enable STATIC timing settings for RDQS (BACKUP_MODE)
+//#define BACKUP_WDQ // enable STATIC timing settings for WDQ (BACKUP_MODE)
+
+
+
+//#define BACKUP_COMPS // enable *COMP overrides (BACKUP_MODE)
+//#define RX_EYE_CHECK // enable the RD_TRAIN eye check
+#define HMC_TEST // enable Host to Memory Clock Alignment
+#define R2R_SHARING // enable multi-rank support via rank2rank sharing
+
+#define FORCE_16BIT_DDRIO // disable signals not used in 16bit mode of DDRIO
+
+
+
+//
+// Debug support
+//
+
+#ifdef NDEBUG
+#define DPF if(0) dpf
+#else
+#define DPF dpf
+#endif
+
+void dpf( uint32_t mask, char_t *bla, ...);
+
+
+uint8_t mgetc(void);
+uint8_t mgetch(void);
+
+
+// Debug print type
+#define D_ERROR 0x0001
+#define D_INFO 0x0002
+#define D_REGRD 0x0004
+#define D_REGWR 0x0008
+#define D_FCALL 0x0010
+#define D_TRN 0x0020
+#define D_TIME 0x0040
+
+#define ENTERFN() DPF(D_FCALL, "<%s>\n", __FUNCTION__)
+#define LEAVEFN() DPF(D_FCALL, "</%s>\n", __FUNCTION__)
+#define REPORTFN() DPF(D_FCALL, "<%s/>\n", __FUNCTION__)
+
+extern uint32_t DpfPrintMask;
+
+#endif
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c
new file mode 100644
index 0000000000..ae7e239c8c
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.c
@@ -0,0 +1,46 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+#include "mrc.h"
+#include "memory_options.h"
+
+#include "meminit.h"
+#include "meminit_utils.h"
+#include "prememinit.h"
+#include "io.h"
+
+// Base address for UART registers
+extern uint32_t UartMmioBase;
+
+//
+// Memory Reference Code entry point when executing from BIOS
+//
+void Mrc( MRCParams_t *mrc_params)
+{
+ // configure uart base address assuming code relocated to eSRAM
+ UartMmioBase = mrc_params->uart_mmio_base;
+
+ ENTERFN();
+
+ DPF(D_INFO, "MRC Version %04X %s %s\n", MRC_VERSION, __DATE__, __TIME__);
+
+ // this will set up the data structures used by MemInit()
+ PreMemInit(mrc_params);
+
+ // this will initialize system memory
+ MemInit(mrc_params);
+
+ LEAVEFN();
+ return;
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h
new file mode 100644
index 0000000000..05055db57c
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/mrc.h
@@ -0,0 +1,166 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+#ifndef _MRC_H_
+#define _MRC_H_
+
+#include "core_types.h"
+
+// define the MRC Version
+#define MRC_VERSION 0x0112
+
+
+// architectural definitions
+#define NUM_CHANNELS 1 // number of channels
+#define NUM_RANKS 2 // number of ranks per channel
+#define NUM_BYTE_LANES 4 // number of byte lanes per channel
+
+// software limitations
+#define MAX_CHANNELS 1
+#define MAX_RANKS 2
+#define MAX_BYTE_LANES 4
+
+// only to mock MrcWrapper
+#define MAX_SOCKETS 1
+#define MAX_SIDES 1
+#define MAX_ROWS (MAX_SIDES * MAX_SOCKETS)
+// end
+
+
+// Specify DRAM of nenory channel width
+enum {
+ x8, // DRAM width
+ x16, // DRAM width & Channel Width
+ x32 // Channel Width
+};
+
+// Specify DRAM speed
+enum {
+ DDRFREQ_800,
+ DDRFREQ_1066
+};
+
+// Specify DRAM type
+enum {
+ DDR3,
+ DDR3L
+};
+
+// Delay configuration for individual signals
+// Vref setting
+// Scrambler seed
+typedef struct MrcTimings_s
+{
+ uint32_t rcvn[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
+ uint32_t rdqs[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
+ uint32_t wdqs[NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
+ uint32_t wdq [NUM_CHANNELS][NUM_RANKS][NUM_BYTE_LANES];
+ uint32_t vref[NUM_CHANNELS][NUM_BYTE_LANES];
+ uint32_t wctl[NUM_CHANNELS][NUM_RANKS];
+ uint32_t wcmd[NUM_CHANNELS];
+
+ uint32_t scrambler_seed;
+ uint8_t ddr_speed; // need to save for the case of frequency change
+} MrcTimings_t;
+
+
+// DENSITY: 0=512Mb, 1=Gb, 2=2Gb, 3=4Gb
+// tCL is DRAM CAS Latency in clocks.
+// All other timings are in picoseconds.
+// Refer to JEDEC spec (or DRAM datasheet) when changing these values.
+typedef struct DRAMParams_s {
+ uint8_t DENSITY;
+ uint8_t tCL; // CAS latency in clocks
+ uint32_t tRAS; // ACT to PRE command period
+ uint32_t tWTR; // Delay from start of internal write transaction to internal read command
+ uint32_t tRRD; // ACT to ACT command period (JESD79 specific to page size 1K/2K)
+ uint32_t tFAW; // Four activate window (JESD79 specific to page size 1K/2K)
+} DRAMParams_t;
+
+
+// Boot mode defined as bit mask (1<<n)
+#define bmCold 1 // full training
+#define bmFast 2 // restore timing parameters
+#define bmS3 4 // resume from S3
+#define bmWarm 8
+#define bmUnknown 0
+
+
+// MRC execution status
+#define MRC_SUCCESS 0 // initialization ok
+#define MRC_E_MEMTEST 1 // memtest failed
+
+
+//
+// Input/output/context parameters for Memory Reference Code
+//
+typedef struct MRCParams_s
+{
+ //
+ // Global settings
+ //
+
+ uint32_t boot_mode; // bmCold, bmFast, bmWarm, bmS3
+ uint32_t uart_mmio_base; // pcie serial port base address (force 0 to disable debug)
+
+ uint8_t dram_width; // x8, x16
+ uint8_t ddr_speed; // DDRFREQ_800, DDRFREQ_1066
+ uint8_t ddr_type; // DDR3, DDR3L
+ uint8_t ecc_enables; // 0, 1 (memory size reduced to 7/8)
+ uint8_t scrambling_enables; // 0, 1
+ uint32_t rank_enables; // 1, 3 (1'st rank has to be populated if 2'nd rank present)
+ uint32_t channel_enables; // 1 only
+ uint32_t channel_width; // x16 only
+ uint32_t address_mode; // 0, 1, 2 (mode 2 forced if ecc enabled)
+
+ // memConfig_t begin
+ uint8_t refresh_rate; // REFRESH_RATE : 1=1.95us, 2=3.9us, 3=7.8us, others=RESERVED
+ uint8_t sr_temp_range; // SR_TEMP_RANGE : 0=normal, 1=extended, others=RESERVED
+ uint8_t ron_value; // RON_VALUE : 0=34ohm, 1=40ohm, others=RESERVED (select MRS1.DIC driver impedance control)
+ uint8_t rtt_nom_value; // RTT_NOM_VALUE : 0=40ohm, 1=60ohm, 2=120ohm, others=RESERVED
+ uint8_t rd_odt_value; // RD_ODT_VALUE : 0=off, 1=60ohm, 2=120ohm, 3=180ohm, others=RESERVED
+ // memConfig_t end
+
+ DRAMParams_t params;
+
+ //
+ // Internally used
+ //
+
+ uint32_t board_id; // internally used for board layout (use x8 or x16 memory)
+ uint32_t hte_setup : 1; // when set hte reconfiguration requested
+ uint32_t menu_after_mrc : 1;
+ uint32_t power_down_disable :1;
+ uint32_t tune_rcvn :1;
+
+ uint32_t channel_size[NUM_CHANNELS];
+ uint32_t column_bits[NUM_CHANNELS];
+ uint32_t row_bits[NUM_CHANNELS];
+
+ uint32_t mrs1; // register content saved during training
+
+ //
+ // Output
+ //
+
+ uint32_t status; // initialization result (non zero specifies error code)
+ uint32_t mem_size; // total memory size in bytes (excludes ECC banks)
+
+ MrcTimings_t timings; // training results (also used on input)
+
+} MRCParams_t;
+
+// Alternative type name for consistent naming convention
+#define MRC_PARAMS MRCParams_t
+
+#endif // _MRC_H_
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c
new file mode 100644
index 0000000000..cb6eb99f74
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/platform.c
@@ -0,0 +1,192 @@
+/** @file
+The interface layer for memory controller access.
+It is supporting both real hardware platform and simulation environment.
+
+Copyright (c) 2013-2015 Intel Corporation.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "mrc.h"
+#include "memory_options.h"
+#include "meminit_utils.h"
+#include "io.h"
+
+#ifdef SIM
+
+void SimMmio32Write (
+ uint32_t be,
+ uint32_t address,
+ uint32_t data );
+
+void SimMmio32Read (
+ uint32_t be,
+ uint32_t address,
+ uint32_t *data );
+
+void SimDelayClk (
+ uint32_t x2clk );
+
+// This is a simple delay function.
+// It takes "nanoseconds" as a parameter.
+void delay_n(uint32_t nanoseconds)
+{
+ SimDelayClk( 800*nanoseconds/1000);
+}
+#endif
+
+/****
+ *
+ ***/
+uint32_t Rd32(
+ uint32_t unit,
+ uint32_t addr)
+{
+ uint32_t data;
+
+ switch (unit)
+ {
+ case MEM:
+ case MMIO:
+#ifdef SIM
+ SimMmio32Read( 1, addr, &data);
+#else
+ data = *PTR32(addr);
+#endif
+ break;
+
+ case MCU:
+ case HOST_BRIDGE:
+ case MEMORY_MANAGER:
+ case HTE:
+ // Handle case addr bigger than 8bit
+ pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
+ addr &= 0x00FF;
+
+ pciwrite32(0, 0, 0, SB_PACKET_REG,
+ SB_COMMAND(SB_REG_READ_OPCODE, unit, addr));
+ data = pciread32(0, 0, 0, SB_DATA_REG);
+ break;
+
+ case DDRPHY:
+ // Handle case addr bigger than 8bit
+ pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
+ addr &= 0x00FF;
+
+ pciwrite32(0, 0, 0, SB_PACKET_REG,
+ SB_COMMAND(SB_DDRIO_REG_READ_OPCODE, unit, addr));
+ data = pciread32(0, 0, 0, SB_DATA_REG);
+ break;
+
+ default:
+ DEAD_LOOP()
+ ;
+ }
+
+ if (unit < MEM)
+ DPF(D_REGRD, "RD32 %03X %08X %08X\n", unit, addr, data);
+
+ return data;
+}
+
+/****
+ *
+ ***/
+void Wr32(
+ uint32_t unit,
+ uint32_t addr,
+ uint32_t data)
+{
+ if (unit < MEM)
+ DPF(D_REGWR, "WR32 %03X %08X %08X\n", unit, addr, data);
+
+ switch (unit)
+ {
+ case MEM:
+ case MMIO:
+#ifdef SIM
+ SimMmio32Write( 1, addr, data);
+#else
+ *PTR32(addr) = data;
+#endif
+ break;
+
+ case MCU:
+ case HOST_BRIDGE:
+ case MEMORY_MANAGER:
+ case HTE:
+ // Handle case addr bigger than 8bit
+ pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
+ addr &= 0x00FF;
+
+ pciwrite32(0, 0, 0, SB_DATA_REG, data);
+ pciwrite32(0, 0, 0, SB_PACKET_REG,
+ SB_COMMAND(SB_REG_WRITE_OPCODE, unit, addr));
+ break;
+
+ case DDRPHY:
+ // Handle case addr bigger than 8bit
+ pciwrite32(0, 0, 0, SB_HADR_REG, addr & 0xFFF00);
+ addr &= 0x00FF;
+
+ pciwrite32(0, 0, 0, SB_DATA_REG, data);
+ pciwrite32(0, 0, 0, SB_PACKET_REG,
+ SB_COMMAND(SB_DDRIO_REG_WRITE_OPCODE, unit, addr));
+ break;
+
+ case DCMD:
+ pciwrite32(0, 0, 0, SB_HADR_REG, 0);
+ pciwrite32(0, 0, 0, SB_DATA_REG, data);
+ pciwrite32(0, 0, 0, SB_PACKET_REG,
+ SB_COMMAND(SB_DRAM_CMND_OPCODE, MCU, 0));
+ break;
+
+ default:
+ DEAD_LOOP()
+ ;
+ }
+}
+
+/****
+ *
+ ***/
+void WrMask32(
+ uint32_t unit,
+ uint32_t addr,
+ uint32_t data,
+ uint32_t mask)
+{
+ Wr32(unit, addr, ((Rd32(unit, addr) & ~mask) | (data & mask)));
+}
+
+/****
+ *
+ ***/
+void pciwrite32(
+ uint32_t bus,
+ uint32_t dev,
+ uint32_t fn,
+ uint32_t reg,
+ uint32_t data)
+{
+ Wr32(MMIO, PCIADDR(bus,dev,fn,reg), data);
+}
+
+/****
+ *
+ ***/
+uint32_t pciread32(
+ uint32_t bus,
+ uint32_t dev,
+ uint32_t fn,
+ uint32_t reg)
+{
+ return Rd32(MMIO, PCIADDR(bus,dev,fn,reg));
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c
new file mode 100644
index 0000000000..f34eb4a6c1
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.c
@@ -0,0 +1,193 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+
+#include "mrc.h"
+#include "memory_options.h"
+
+#include "meminit_utils.h"
+#include "prememinit.h"
+#include "io.h"
+
+// Read character from serial console
+uint8_t mgetc(void);
+
+extern uint32_t DpfPrintMask;
+
+// Adjust configuration parameters before initialisation
+// sequence.
+void PreMemInit(
+ MRCParams_t *mrc_params)
+{
+ const DRAMParams_t *dram_params;
+
+ uint8_t dram_width;
+ uint32_t dram_cfg_index;
+ uint32_t channel_i;
+
+ ENTERFN();
+
+#ifdef MRC_SV
+ {
+ uint8_t ch;
+
+ myloop:
+
+ DPF(D_INFO, "- c - continue\n");
+ DPF(D_INFO, "- f - boot mode [%d]\n", mrc_params->boot_mode);
+ DPF(D_INFO, "- r - rank enable [%d]\n", mrc_params->rank_enables);
+ DPF(D_INFO, "- e - ecc switch [%d]\n", mrc_params->ecc_enables);
+ DPF(D_INFO, "- b - scrambling switch [%d]\n", mrc_params->scrambling_enables);
+ DPF(D_INFO, "- a - adr mode [%d]\n", mrc_params->address_mode);
+ DPF(D_INFO, "- m - menu after mrc [%d]\n", mrc_params->menu_after_mrc);
+ DPF(D_INFO, "- t - tune to rcvn [%d]\n", mrc_params->tune_rcvn);
+ DPF(D_INFO, "- o - odt switch [%d]\n", mrc_params->rd_odt_value);
+ DPF(D_INFO, "- d - dram density [%d]\n", mrc_params->params.DENSITY);
+ DPF(D_INFO, "- p - power down disable [%d]\n", mrc_params->power_down_disable);
+ DPF(D_INFO, "- l - log switch 0x%x\n", DpfPrintMask);
+ ch = mgetc();
+
+ switch (ch)
+ {
+ case 'f':
+ mrc_params->boot_mode >>= 1;
+ if(mrc_params->boot_mode == bmUnknown)
+ {
+ mrc_params->boot_mode = bmWarm;
+ }
+ DPF(D_INFO, "Boot mode %d\n", mrc_params->boot_mode);
+ break;
+
+ case 'p':
+ mrc_params->power_down_disable ^= 1;
+ DPF(D_INFO, "Power down disable %d\n", mrc_params->power_down_disable);
+ break;
+
+ case 'r':
+ mrc_params->rank_enables ^= 2;
+ DPF(D_INFO, "Rank enable %d\n", mrc_params->rank_enables);
+ break;
+
+ case 'e':
+ mrc_params->ecc_enables ^= 1;
+ DPF(D_INFO, "Ecc enable %d\n", mrc_params->ecc_enables);
+ break;
+
+ case 'b':
+ mrc_params->scrambling_enables ^= 1;
+ DPF(D_INFO, "Scrambler enable %d\n", mrc_params->scrambling_enables);
+ break;
+
+ case 'a':
+ mrc_params->address_mode = (mrc_params->address_mode + 1) % 3;
+ DPF(D_INFO, "Adr mode %d\n", mrc_params->address_mode);
+ break;
+
+ case 'm':
+ mrc_params->menu_after_mrc ^= 1;
+ DPF(D_INFO, "Menu after mrc %d\n", mrc_params->menu_after_mrc);
+ break;
+
+ case 't':
+ mrc_params->tune_rcvn ^= 1;
+ DPF(D_INFO, "Tune to rcvn %d\n", mrc_params->tune_rcvn);
+ break;
+
+ case 'o':
+ mrc_params->rd_odt_value = (mrc_params->rd_odt_value + 1) % 4;
+ DPF(D_INFO, "Rd_odt_value %d\n", mrc_params->rd_odt_value);
+ break;
+
+ case 'd':
+ mrc_params->params.DENSITY = (mrc_params->params.DENSITY + 1) % 4;
+ DPF(D_INFO, "Dram density %d\n", mrc_params->params.DENSITY);
+ break;
+
+ case 'l':
+ DpfPrintMask ^= 0x30;
+ DPF(D_INFO, "Log mask %x\n", DpfPrintMask);
+ break;
+
+ default:
+ break;
+ }
+
+ if (ch != 'c')
+ goto myloop;
+
+ }
+#endif
+
+ // initially expect success
+ mrc_params->status = MRC_SUCCESS;
+
+ // todo!!! Setup board layout (must be reviewed as is selecting static timings)
+ // 0 == R0 (DDR3 x16), 1 == R1 (DDR3 x16), 2 == DV (DDR3 x8), 3 == SV (DDR3 x8)
+ if (mrc_params->dram_width == x8)
+ {
+ mrc_params->board_id = 2; // select x8 layout
+ }
+ else
+ {
+ mrc_params->board_id = 0; // select x16 layout
+ }
+
+ // initially no memory
+ mrc_params->mem_size = 0;
+ channel_i = 0;
+
+ // begin of channel settings
+ dram_width = mrc_params->dram_width;
+ dram_params = &mrc_params->params;
+ dram_cfg_index = 0;
+
+ // Determine Column & Row Bits:
+ // Column:
+ // 11 for 8Gbx8, else 10
+ mrc_params->column_bits[channel_i] = ((dram_params[dram_cfg_index].DENSITY == 4) && (dram_width == x8)) ? (11) : (10);
+
+ // Row:
+ // 512Mbx16=12 512Mbx8=13
+ // 1Gbx16=13 1Gbx8=14
+ // 2Gbx16=14 2Gbx8=15
+ // 4Gbx16=15 4Gbx8=16
+ // 8Gbx16=16 8Gbx8=16
+ mrc_params->row_bits[channel_i] = 12 + (dram_params[dram_cfg_index].DENSITY)
+ + (((dram_params[dram_cfg_index].DENSITY < 4) && (dram_width == x8)) ? (1) : (0));
+
+ // Determine Per Channel Memory Size:
+ // (For 2 RANKs, multiply by 2)
+ // (For 16 bit data bus, divide by 2)
+ // DENSITY WIDTH MEM_AVAILABLE
+ // 512Mb x16 0x008000000 ( 128MB)
+ // 512Mb x8 0x010000000 ( 256MB)
+ // 1Gb x16 0x010000000 ( 256MB)
+ // 1Gb x8 0x020000000 ( 512MB)
+ // 2Gb x16 0x020000000 ( 512MB)
+ // 2Gb x8 0x040000000 (1024MB)
+ // 4Gb x16 0x040000000 (1024MB)
+ // 4Gb x8 0x080000000 (2048MB)
+ mrc_params->channel_size[channel_i] = (1 << dram_params[dram_cfg_index].DENSITY);
+ mrc_params->channel_size[channel_i] *= ((dram_width == x8) ? (2) : (1));
+ mrc_params->channel_size[channel_i] *= (mrc_params->rank_enables == 0x3) ? (2) : (1);
+ mrc_params->channel_size[channel_i] *= (mrc_params->channel_width == x16) ? (1) : (2);
+
+ // Determine memory size (convert number of 64MB/512Mb units)
+ mrc_params->mem_size += mrc_params->channel_size[channel_i] << 26;
+
+ // end of channel settings
+
+ LEAVEFN();
+ return;
+}
+
diff --git a/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h
new file mode 100644
index 0000000000..78cca36f75
--- /dev/null
+++ b/QuarkSocPkg/QuarkNorthCluster/MemoryInit/Pei/prememinit.h
@@ -0,0 +1,21 @@
+/************************************************************************
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ *
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ *
+ ************************************************************************/
+#ifndef __PREMEMINIT_H_
+#define __PREMEMINIT_H_
+
+// Function prototypes
+void PreMemInit(MRCParams_t *mrc_params);
+
+
+#endif // _PREMEMINIT_H_