2015-12-15 20:22:23 +01:00
/************************************************************************
*
* Copyright ( c ) 2013 - 2015 Intel Corporation .
*
* This program and the accompanying materials
* are licensed and made available under the terms and conditions of the BSD License
* which accompanies this distribution . The full text of the license may be found at
* http : //opensource.org/licenses/bsd-license.php
*
* 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 ;
2016-03-18 21:28:03 +01:00
uint8_t TRP , TRCD , TRAS , TWR , TWTR , TRRD , TRTP , TFAW ;
2015-12-15 20:22:23 +01:00
uint32_t TCK ;
RegDTR0 Dtr0 ;
RegDTR1 Dtr1 ;
RegDTR2 Dtr2 ;
RegDTR3 Dtr3 ;
RegDTR4 Dtr4 ;
ENTERFN ( ) ;
// mcu_init starts
post_code ( 0x02 , 0x00 ) ;
Dtr0 . raw = isbR32m ( MCU , DTR0 ) ;
Dtr1 . raw = isbR32m ( MCU , DTR1 ) ;
Dtr2 . raw = isbR32m ( MCU , DTR2 ) ;
Dtr3 . raw = isbR32m ( MCU , DTR3 ) ;
Dtr4 . raw = isbR32m ( MCU , DTR4 ) ;
TCK = tCK [ mrc_params - > ddr_speed ] ; // Clock in picoseconds
TCL = mrc_params - > params . tCL ; // CAS latency in clocks
TRP = TCL ; // Per CAT MRC
TRCD = TCL ; // Per CAT MRC
TRAS = MCEIL ( mrc_params - > params . tRAS , TCK ) ;
TWR = MCEIL ( 15000 , TCK ) ; // Per JEDEC: tWR=15000ps DDR2/3 from 800-1600
TWTR = MCEIL ( mrc_params - > params . tWTR , TCK ) ;
TRRD = MCEIL ( mrc_params - > params . tRRD , TCK ) ;
TRTP = 4 ; // Valid for 800 and 1066, use 5 for 1333
TFAW = MCEIL ( mrc_params - > params . tFAW , TCK ) ;
WL = 5 + mrc_params - > ddr_speed ;
Dtr0 . field . dramFrequency = mrc_params - > ddr_speed ;
Dtr0 . field . tCL = TCL - 5 ; //Convert from TCL (DRAM clocks) to VLV indx
Dtr0 . field . tRP = TRP - 5 ; //5 bit DRAM Clock
Dtr0 . field . tRCD = TRCD - 5 ; //5 bit DRAM Clock
Dtr1 . field . tWCL = WL - 3 ; //Convert from WL (DRAM clocks) to VLV indx
Dtr1 . field . tWTP = WL + 4 + TWR - 14 ; //Change to tWTP
Dtr1 . field . tRTP = MMAX ( TRTP , 4 ) - 3 ; //4 bit DRAM Clock
Dtr1 . field . tRRD = TRRD - 4 ; //4 bit DRAM Clock
Dtr1 . field . tCMD = 1 ; //2N
Dtr1 . field . tRAS = TRAS - 14 ; //6 bit DRAM Clock
Dtr1 . field . tFAW = ( ( TFAW + 1 ) > > 1 ) - 5 ; //4 bit DRAM Clock
Dtr1 . field . tCCD = 0 ; //Set 4 Clock CAS to CAS delay (multi-burst)
Dtr2 . field . tRRDR = 1 ;
Dtr2 . field . tWWDR = 2 ;
Dtr2 . field . tRWDR = 2 ;
Dtr3 . field . tWRDR = 2 ;
Dtr3 . field . tWRDD = 2 ;
if ( mrc_params - > ddr_speed = = DDRFREQ_800 )
{
// Extended RW delay (+1)
Dtr3 . field . tRWSR = TCL - 5 + 1 ;
}
else if ( mrc_params - > ddr_speed = = DDRFREQ_1066 )
{
// Extended RW delay (+1)
Dtr3 . field . tRWSR = TCL - 5 + 1 ;
}
Dtr3 . field . tWRSR = 4 + WL + TWTR - 11 ;
if ( mrc_params - > ddr_speed = = DDRFREQ_800 )
{
Dtr3 . field . tXP = MMAX ( 0 , 1 - Dtr1 . field . tCMD ) ;
}
else
{
Dtr3 . field . tXP = MMAX ( 0 , 2 - Dtr1 . field . tCMD ) ;
}
Dtr4 . field . WRODTSTRT = Dtr1 . field . tCMD ;
Dtr4 . field . WRODTSTOP = Dtr1 . field . tCMD ;
Dtr4 . field . RDODTSTRT = Dtr1 . field . tCMD + Dtr0 . field . tCL - Dtr1 . field . tWCL + 2 ; //Convert from WL (DRAM clocks) to VLV indx
Dtr4 . field . RDODTSTOP = Dtr1 . field . tCMD + Dtr0 . field . tCL - Dtr1 . field . tWCL + 2 ;
Dtr4 . field . TRGSTRDIS = 0 ;
Dtr4 . field . ODTDIS = 0 ;
isbW32m ( MCU , DTR0 , Dtr0 . raw ) ;
isbW32m ( MCU , DTR1 , Dtr1 . raw ) ;
isbW32m ( MCU , DTR2 , Dtr2 . raw ) ;
isbW32m ( MCU , DTR3 , Dtr3 . raw ) ;
isbW32m ( MCU , DTR4 , Dtr4 . raw ) ;
LEAVEFN ( ) ;
}
// ddrphy_init:
// POST_CODE[major] == 0x03
//
// This function performs some initialisation on the DDRIO unit.
// This function is dependent on BOARD_ID, DDR_SPEED, and CHANNEL_ENABLES.
static void ddrphy_init ( MRCParams_t * mrc_params )
{
uint32_t tempD ; // temporary DWORD
uint8_t channel_i ; // channel counter
uint8_t rank_i ; // rank counter
uint8_t bl_grp_i ; // byte lane group counter (2 BLs per module)
uint8_t bl_divisor = /*(mrc_params->channel_width==x16)?2:*/ 1 ; // byte lane divisor
uint8_t speed = mrc_params - > ddr_speed & ( BIT1 | BIT0 ) ; // For DDR3 --> 0 == 800, 1 == 1066, 2 == 1333
uint8_t tCAS ;
uint8_t tCWL ;
ENTERFN ( ) ;
tCAS = mrc_params - > params . tCL ;
tCWL = 5 + mrc_params - > ddr_speed ;
// ddrphy_init starts
post_code ( 0x03 , 0x00 ) ;
// HSD#231531
// Make sure IOBUFACT is deasserted before initialising the DDR PHY.
// HSD#234845
// Make sure WRPTRENABLE is deasserted before initialising the DDR PHY.
for ( channel_i = 0 ; channel_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 1 x ) + 2 x 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 1 x + 2 x x 2 + PI / 128 ) - 1
//diffampen length x8C/x90 [13:8] -- B0ONDURCTL B1ONDURCTL
MAX OF 2 RANKS : roundup ( rcven 1 x + 2 x 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 , " \n Press 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 ;
}