blob: 30b926f128071582d23abfd275e48c3c62c99e63 [file] [log] [blame]
/*******************************************************************************
Copyright (C) Marvell International Ltd. and its affiliates
This software file (the "File") is owned and distributed by Marvell
International Ltd. and/or its affiliates ("Marvell") under the following
alternative licensing terms. Once you have made an election to distribute the
File under one of the following license alternatives, please (i) delete this
introductory statement regarding license alternatives, (ii) delete the two
license alternatives that you have not elected to use and (iii) preserve the
Marvell copyright notice above.
********************************************************************************
Marvell Commercial License Option
If you received this File from Marvell and you have entered into a commercial
license agreement (a "Commercial License") with Marvell, the File is licensed
to you under the terms of the applicable Commercial License.
********************************************************************************
Marvell GPL License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File in accordance with the terms and conditions of the General
Public License Version 2, June 1991 (the "GPL License"), a copy of which is
available along with the File in the license.txt file or by writing to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
DISCLAIMED. The GPL License provides additional details about this warranty
disclaimer.
********************************************************************************
Marvell BSD License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File under the following licensing terms.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Marvell nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "config_marvell.h" /* Required to identify SOC and Board */
#include "ddr3_init.h"
#include "ddr3_spd.h"
#include "bin_hdr_twsi.h"
#include "mvUart.h"
#include "printf.h"
#include "mvSysEnvLib.h"
#include "ddr3_hws_hw_training.h"
#include "mvSiliconIf.h"
#if defined(MV88F69XX)
#include "ddr3_a39x.h"
#include "ddr3_a39x_vars.h"
#include "ddr3_a39x_topology.h"
#include "ddr_a38x_dlb_config.h"
#elif defined(MV88F68XX)
#include "ddr3_a38x.h"
#include "ddr3_a38x_vars.h"
#include "ddr3_a38x_topology.h"
#include "ddr_a38x_dlb_config.h"
#elif defined(MV_MSYS_BC2)
#include "ddr3_msys_bc2.h"
#include "ddr3_msys_bc2_config.h"
#include "ddr3_msys_bc2_vars.h"
#include "ddr3_msys_bc2_topology.h"
#elif defined(MV_MSYS_AC3)
#include "ddr3_msys_ac3.h"
#include "ddr3_msys_ac3_config.h"
#include "ddr3_msys_ac3_vars.h"
#include "ddr3_msys_ac3_topology.h"
#endif
#include "bootstrap_os.h"
#if defined(MV_MSYS_BC2)
#define MARVELL_BOARD BC2_MARVELL_BOARD_ID_BASE
#elif defined(MV_MSYS_AC3)
#define MARVELL_BOARD AC3_MARVELL_BOARD_ID_BASE
#endif
/* translates topology map definitions to real memory size in bits */
MV_U32 mv_memSize[] = { ADDR_SIZE_512Mb, ADDR_SIZE_1Gb, ADDR_SIZE_2Gb, ADDR_SIZE_4Gb ,ADDR_SIZE_8Gb };
MV_STATUS ddr3LoadTopologyMap(void);
extern MV_STATUS ddr3TipInitSpecificRegConfig
(
MV_U32 devNum,
MV_DRAM_MC_INIT *regConfigArr
);
extern MV_VOID ddr3TipSetTopologyMap
(
MV_U32 devNum,
MV_HWS_TOPOLOGY_MAP *topology
);
extern MV_U32 ddr3TipGetInitFreq();
extern MV_VOID ddr3HwsSetLogLevel(
MV_DDR_LIB_DEBUG_BLOCK block,
MV_U8 level
);
extern MV_STATUS ddr3TipTuneTrainingParams
(
MV_U32 devNum,
MV_TUNE_TRAINING_PARAMS *params
);
#ifdef SUPPORT_STATIC_DUNIT_CONFIG
static MV_U32 ddr3GetStaticDdrMode(void);
#endif
/*Set 1 to use dynamic DUNIT configuration,
set 0(supported for A380 and AC3) to configure DUNIT in values set by ddr3TipInitSpecificRegConfig*/
MV_U8 genericInitController = 1;
MV_VOID getTargetFreq(MV_U32 uiFreqMode, MV_U32 *ddrFreq, MV_U32 *hclkPs);
MV_STATUS ddr3FastPathDynamicCsSizeConfig(MV_U32 uiCsEna);
MV_VOID ddr3FastPathStaticCsSizeConfig(MV_U32 uiCsEna);
MV_U32 ddr3GetDeviceWidth(MV_U32 uiCs);
MV_U32 mvBoardIdIndexGet(MV_U32 boardId);
MV_U32 mvBoardIdGet(MV_VOID);
MV_U32 ddr3GetBusWidth(void);
#ifdef MV_RUN_WIN_VALIDATION_TEST
extern MV_VOID mvHwsDdr3TipSweepTest(MV_BOOL enable);
#endif
extern MV_VOID ddr3SetLogLevel(MV_U32 nLogLevel);
static MV_U32 gLogLevel = 0;
static MV_STATUS ddr3HwsTuneTrainingParams(MV_U8 devNum);
MV_STATUS ddr3CalcMemCsSize(MV_U32 uiCs, MV_U32* puiCsSize);
#if defined(MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI)
static MV_STATUS ddr3UpdateTopologyMap(MV_HWS_TOPOLOGY_MAP* topologyMap);
#endif
#ifdef CONFIG_DDR4
char* ddrType = "DDR4";
#else
char* ddrType = "DDR3";
#endif
/************************************************************************************
* Name: levelLogPrintD
* Desc: This routine printing data in hex-decimal if gLogLevel>=eLogLevel
* Args: char *str,MV_LOG_LEVEL eLogLevel
* Notes:
* Returns: None.
*/
MV_VOID levelLogPrintD(MV_U32 dec_num, MV_U32 length, MV_LOG_LEVEL eLogLevel)
{
if (gLogLevel >= eLogLevel)
putdata(dec_num, length);
}
/************************************************************************************
* Name: levelLogPrintDD
* Desc: This routine printing data in decimal if gLogLevel>=eLogLevel
* Args: char *str,MV_LOG_LEVEL eLogLevel
* Notes:
* Returns: None.
*/
MV_VOID levelLogPrintDD(MV_U32 dec_num, MV_U32 length, MV_LOG_LEVEL eLogLevel)
{
if (gLogLevel >= eLogLevel)
putdataDec(dec_num, length);
}
/******************************************************************************
* Name: ddr3GetTopologyMap
* Desc: gets board Topology map
* Args: pointer to topology map structure
* Notes:
* Returns: MV_STATUS
*/
MV_STATUS ddr3GetTopologyMap(MV_HWS_TOPOLOGY_MAP** tMap)
{
MV_U32 boardIdIndex = mvBoardIdIndexGet(mvBoardIdGet());
/*Get topology data by board ID*/
if (sizeof(TopologyMap)/sizeof(MV_HWS_TOPOLOGY_MAP*) > boardIdIndex)
*tMap = &(TopologyMap[boardIdIndex]);
else {
mvPrintf("Failed get DDR3 Topology map (invalid board ID #d)\n",boardIdIndex);
return MV_NOT_SUPPORTED;
}
return MV_OK;
}
static MV_VOID ddr3RestoreAndSetFinalWindows(MV_U32 *auWinBackup)
{
MV_U32 winCtrlReg, numOfWinRegs;
MV_U32 uiCsEna = mvSysEnvGetCSEnaFromReg();
winCtrlReg = REG_XBAR_WIN_4_CTRL_ADDR;
numOfWinRegs = 16;
MV_U32 ui;
/* Return XBAR windows 4-7 or 16-19 init configuration */
for (ui = 0; ui < numOfWinRegs; ui++)
MV_REG_WRITE((winCtrlReg + 0x4 * ui), auWinBackup[ui]);
mvPrintf("%s Training Sequence - Switching XBAR Window to FastPath Window \n", ddrType);
#if defined DYNAMIC_CS_SIZE_CONFIG
if (ddr3FastPathDynamicCsSizeConfig(uiCsEna)!= MV_OK)
mvPrintf("ddr3FastPathDynamicCsSizeConfig FAILED\n");
#else
MV_U32 uiReg, uiCs;
uiReg = 0x1FFFFFE1;
for (uiCs = 0; uiCs < MAX_CS; uiCs++) {
if (uiCsEna & (1 << uiCs)) {
uiReg |= (uiCs << 2);
break;
}
}
MV_REG_WRITE(REG_FASTPATH_WIN_0_CTRL_ADDR, uiReg); /*Open fast path Window to - 0.5G */
#endif
}
static MV_STATUS ddr3SaveAndSetTrainingWindows(MV_U32 *auWinBackup)
{
MV_U32 uiCsEna;
MV_U32 uiReg, uiTempCount, uiCs, ui;
MV_U32 winCtrlReg, winBaseReg, winRemapReg;
MV_U32 numOfWinRegs, winJumpIndex;
winCtrlReg = REG_XBAR_WIN_4_CTRL_ADDR;
winBaseReg = REG_XBAR_WIN_4_BASE_ADDR;
winRemapReg = REG_XBAR_WIN_4_REMAP_ADDR;
winJumpIndex = 0x10;
numOfWinRegs = 16;
MV_HWS_TOPOLOGY_MAP* toplogyMap = NULL;
#ifdef DISABLE_L2_FILTERING_DURING_DDR_TRAINING
/* Disable L2 filtering during DDR training (when Cross Bar window is open)*/
MV_REG_WRITE(ADDRESS_FILTERING_END_REGISTER, 0);
#endif
CHECK_STATUS(ddr3GetTopologyMap(&toplogyMap));
uiCsEna = toplogyMap->interfaceParams[0].asBusParams[0].csBitmask;
/* Close XBAR Window 19 - Not needed */
/* {0x000200e8} - Open Mbus Window - 2G */
MV_REG_WRITE(REG_XBAR_WIN_19_CTRL_ADDR, 0);
/* Save XBAR Windows 4-19 init configurations */
for (ui = 0; ui < numOfWinRegs; ui++)
auWinBackup[ui] = MV_REG_READ(winCtrlReg + 0x4 * ui);
/* Open XBAR Windows 4-7 or 16-19 for other CS */
uiReg = 0;
uiTempCount = 0;
for (uiCs = 0; uiCs < MAX_CS; uiCs++) {
if (uiCsEna & (1 << uiCs)) {
switch (uiCs) {
case 0:
uiReg = 0x0E00;
break;
case 1:
uiReg = 0x0D00;
break;
case 2:
uiReg = 0x0B00;
break;
case 3:
uiReg = 0x0700;
break;
}
uiReg |= (1 << 0);
uiReg |= (SDRAM_CS_SIZE & 0xFFFF0000);
MV_REG_WRITE(winCtrlReg + winJumpIndex * uiTempCount, uiReg);
uiReg = (((SDRAM_CS_SIZE + 1) * (uiTempCount)) & 0xFFFF0000);
MV_REG_WRITE(winBaseReg + winJumpIndex * uiTempCount, uiReg);
if(winRemapReg <= REG_XBAR_WIN_7_REMAP_ADDR)
MV_REG_WRITE(winRemapReg + winJumpIndex * uiTempCount, 0);
uiTempCount++;
}
}
return MV_OK;
}
/************************************************************************************
* Name: ddr3Init - Main DDR3 Init function
* Desc: This routine initialize the DDR3 MC and runs HW training.
* Args: None.
* Notes:
* Returns: None.
*/
MV_U32 ddr3Init(void)
{
MV_U32 uiReg = 0;
MV_U32 socNum;
MV_STATUS status;
MV_U32 auWinBackup[16];
/* SoC/Board special Initializtions */
/*Get version from internal library*/
ddr3PrintVersion();
/*Add sub_version string*/
DEBUG_INIT_C("",SUB_VERSION,1);
/* Switching CPU to MRVL ID */
socNum = (MV_REG_READ(REG_SAMPLE_RESET_HIGH_ADDR) & SAR1_CPU_CORE_MASK) >> SAR1_CPU_CORE_OFFSET;
switch (socNum) {
case 0x3:
MV_REG_BIT_SET(CPU_CONFIGURATION_REG(3), CPU_MRVL_ID_OFFSET);
MV_REG_BIT_SET(CPU_CONFIGURATION_REG(2), CPU_MRVL_ID_OFFSET);
case 0x1:
MV_REG_BIT_SET(CPU_CONFIGURATION_REG(1), CPU_MRVL_ID_OFFSET);
case 0x0:
MV_REG_BIT_SET(CPU_CONFIGURATION_REG(0), CPU_MRVL_ID_OFFSET);
default:
break;
}
/* Set DRAM Reset Mask in case detected GPIO indication of wakeup from suspend
* i.e the DRAM values will not be overwritten / reset when waking from suspend*/
if (mvSysEnvSuspendWakeupCheck() == MV_SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED)
MV_REG_BIT_SET(REG_SDRAM_INIT_CTRL_ADDR, 1 << REG_SDRAM_INIT_RESET_MASK_OFFS);
/************************************************************************************/
/* Stage 0 - Set board configuration */
/************************************************************************************/
/* Check if DRAM is already initialized */
if (MV_REG_READ(REG_BOOTROM_ROUTINE_ADDR) & (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS)) {
mvPrintf("%s Training Sequence - 2nd boot - Skip \n", ddrType);
return MV_OK;
}
/************************************************************************************/
/* Stage 1 - Dunit Setup */
/************************************************************************************/
/* Fix read ready phases for all SOC in reg 0x15C8*/
uiReg = MV_REG_READ(REG_TRAINING_DEBUG_3_ADDR);
uiReg &= ~(REG_TRAINING_DEBUG_3_MASK);
uiReg |= 0x4; /* Phase 0 */
uiReg &= ~(REG_TRAINING_DEBUG_3_MASK << REG_TRAINING_DEBUG_3_OFFS);
uiReg |= (0x4 << (1 * REG_TRAINING_DEBUG_3_OFFS)); /* Phase 1 */
uiReg &= ~(REG_TRAINING_DEBUG_3_MASK << (3 * REG_TRAINING_DEBUG_3_OFFS));
uiReg |= (0x6 << (3 * REG_TRAINING_DEBUG_3_OFFS)); /* Phase 3 */
uiReg &= ~(REG_TRAINING_DEBUG_3_MASK << (4 * REG_TRAINING_DEBUG_3_OFFS));
uiReg |= (0x6 << (4 * REG_TRAINING_DEBUG_3_OFFS));
uiReg &= ~(REG_TRAINING_DEBUG_3_MASK << (5 * REG_TRAINING_DEBUG_3_OFFS));
uiReg |= (0x6 << (5 * REG_TRAINING_DEBUG_3_OFFS));
MV_REG_WRITE(REG_TRAINING_DEBUG_3_ADDR, uiReg);
/* AxiBrespMode[8] = Compliant, AxiAddrDecodeCntrl[11] = Internal, AxiDataBusWidth[0] = 128bit */
MV_REG_WRITE(REG_DRAM_AXI_CTRL_ADDR, 0); /* 0x14A8 - AXI Control Register */
/************************************************************************************/
/* Stage 2 - Training Values Setup */
/************************************************************************************/
/* Set X-BAR windows for the training sequence */
ddr3SaveAndSetTrainingWindows(auWinBackup);
#ifdef SUPPORT_STATIC_DUNIT_CONFIG
/* load static controller configuration (in case dynamic/geenric init is not enabled */
if( genericInitController == 0){
ddr3TipInitSpecificRegConfig(0, ddr_modes[ddr3GetStaticDdrMode()].regs);
}
#endif
/*Load topology for New Training IP*/
status = ddr3LoadTopologyMap();
if (MV_OK != status) {
mvPrintf("%s Training Sequence topology load - FAILED\n", ddrType);
return status;
}
/*Tune training algo paramteres*/
status = ddr3HwsTuneTrainingParams(0);
if (MV_OK != status) {
return status;
}
/*Set log level for training lib*/
ddr3HwsSetLogLevel(MV_DEBUG_BLOCK_ALL, DEBUG_LEVEL_ERROR);
/*ddr3HwsSetLogLevel(MV_DEBUG_TRAINING_MAIN, DEBUG_LEVEL_TRACE);*/
#ifdef MV_RUN_WIN_VALIDATION_TEST /* to run DDR viewer tool (to display DDR training results) */
mvHwsDdr3TipSweepTest(MV_TRUE);
#endif
/*Start New Training IP*/
status = ddr3HwsHwTraining();
if (MV_OK != status) {
mvPrintf("%s Training Sequence - FAILED\n", ddrType);
return status;
}
/************************************************************************************/
/* Stage 3 - Finish */
/************************************************************************************/
/* Restore and set windows */
ddr3RestoreAndSetFinalWindows(auWinBackup);
/* Update DRAM init indication in bootROM register */
uiReg = MV_REG_READ(REG_BOOTROM_ROUTINE_ADDR);
MV_REG_WRITE(REG_BOOTROM_ROUTINE_ADDR, uiReg | (1 << REG_BOOTROM_ROUTINE_DRAM_INIT_OFFS));
/* DLB config */
ddr3NewTipDlbConfig();
#if defined(ECC_SUPPORT)
if( (MV_TRUE == ddr3IfEccEnabled())/* &&
(mvSysEnvSuspendWakeupCheck() != MV_SUSPEND_WAKEUP_ENABLED_GPIO_DETECTED) &&
(mvSysEnvCheckWakeupDramEnable() != MV_SUSPEND_WAKEUP_ENABLED_MEM_DETECTED) */){
/*Scrub all DRAM area if ECC enabled (and Suspend wakeup state not detected - TBD)*/
/* Disabled SuspendWakeup support until debug*/
ddr3NewTipEccScrub();
}
#endif
mvPrintf("%s Training Sequence - Ended Successfully\n", ddrType);
return MV_OK;
}
/******************************************************************************
* Name: ddr3GetCpuFreq
* Desc: read S@R and return CPU frequency
* Args:
* Notes:
* Returns: required value
*/
MV_U32 ddr3GetCpuFreq(void)
{
return ddr3TipGetInitFreq();
}
/******************************************************************************
* Name: ddr3GetFabOpt
* Desc: read S@R and return CPU frequency
* Args:
* Notes:
* Returns: required value
*/
MV_U32 ddr3GetFabOpt(void)
{
return 0; /* No fabric */
}
/************************************************************************************
* Name: ddr3GetStaticMCValue - Init Memory controller with static parameters
* Desc: Use this routine to init the controller without the HW training procedure
* User must provide compatible header file with registers data.
* Args: None.
* Notes:
* Returns: None.
*/
MV_U32 ddr3GetStaticMCValue(MV_U32 regAddr, MV_U32 offset1, MV_U32 mask1, MV_U32 offset2, MV_U32 mask2)
{
MV_U32 uiReg, uiTemp;
uiReg = MV_REG_READ(regAddr);
uiTemp = (uiReg >> offset1) & mask1;
if (mask2)
uiTemp |= (uiReg >> offset2) & mask2;
return uiTemp;
}
/************************************************************************************
* Name: ddr3GetStaticDdrMode - Init Memory controller with static parameters
* Desc: Use this routine to init the controller without the HW training procedure
* User must provide compatible header file with registers data.
* Args: None.
* Notes:
* Returns: None.
*/
MV_U32 ddr3GetStaticDdrMode(void)
{
MV_U32 chipBoardRev, i;
MV_U32 size;
/*Valid only for A380 only, MSYS using dynamic controller config*/
#ifdef CONFIG_CUSTOMER_BOARD_SUPPORT
chipBoardRev = mvBoardIdGet(); /* Customer boards select DDR mode according to board ID & Sample@Reset*/
#else
chipBoardRev = MARVELL_BOARD; /* Marvell boards select DDR mode according to Sample@Reset only */
#endif
size = sizeof(ddr_modes) / sizeof(MV_DRAM_MODES);
for (i = 0; i < size; i++) {
if ((ddr3GetCpuFreq() == ddr_modes[i].cpuFreq) && (ddr3GetFabOpt() == ddr_modes[i].fabFreq) &&
(chipBoardRev == ddr_modes[i].chipBoardRev))
return i;
}
DEBUG_INIT_S("\n*** Error: ddr3GetStaticDdrMode: No match for requested DDR mode. ***\n\n");
return 0;
}
/******************************************************************************
* Name: ddr3GetCSNumFromReg
* Desc:
* Args:
* Notes:
* Returns:
*/
MV_U32 ddr3GetCSNumFromReg(void)
{
MV_U32 uiCsEna = mvSysEnvGetCSEnaFromReg();
MV_U32 uiCsCount = 0;
MV_U32 uiCs;
for (uiCs = 0; uiCs < MAX_CS; uiCs++)
if (uiCsEna & (1 << uiCs))
uiCsCount++;
return uiCsCount;
}
/******************************************************************************
* Name: ddr3LoadTopologyMap
* Desc:
* Args:
* Notes:
* Returns:
*/
MV_STATUS ddr3LoadTopologyMap(void)
{
MV_HWS_TOPOLOGY_MAP* toplogyMap = NULL;
MV_U8 devNum = 0;
CHECK_STATUS(ddr3GetTopologyMap(&toplogyMap));
#if defined(MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI)
/*Update topology data*/
if(MV_OK != ddr3UpdateTopologyMap(toplogyMap))
DEBUG_INIT_FULL_S("Failed update of DDR3 Topology map\n");
#endif
/*Set topology data for internal DDR training usage*/
ddr3TipSetTopologyMap(devNum, toplogyMap);
return MV_OK;
}
MV_VOID getTargetFreq(MV_U32 uiFreqMode, MV_U32 *ddrFreq, MV_U32 *hclkPs)
{
MV_U32 tmp, hclk = 200;
switch(uiFreqMode)
{
case 4:
tmp = 1; //DDR_400;
hclk = 200;
break;
case 0x8:
tmp = 1; //DDR_666;
hclk = 333;
break;
case 0xc:
tmp = 1; //DDR_800;
hclk = 400;
break;
default:
*ddrFreq = 0;
*hclkPs = 0;
break;
}
*ddrFreq = tmp; /* DDR freq define */
*hclkPs = 1000000/hclk; /* values are 1/HCLK in ps */
return;
}
MV_VOID ddr3NewTipDlbConfig()
{
MV_U32 uiReg, i = 0;
MV_DRAM_DLB_CONFIG *ConfigTablePtr= mvSysEnvDlbConfigPtrGet();
/*Write the configuration*/
while(ConfigTablePtr[i].regAddr != 0)
{
MV_REG_WRITE(ConfigTablePtr[i].regAddr, ConfigTablePtr[i].regData);
i++;
}
#ifdef CONFIG_DDR4
uiReg = MV_REG_READ(REG_DDR_CONT_HIGH_ADDR);
uiReg |= DLB_INTERJECTION_ENABLE;
MV_REG_WRITE(REG_DDR_CONT_HIGH_ADDR, uiReg);
#endif
/*Enable DLB*/
uiReg = MV_REG_READ(REG_STATIC_DRAM_DLB_CONTROL);
uiReg |= (DLB_ENABLE | DLB_WRITE_COALESING | DLB_AXI_PREFETCH_EN | DLB_MBUS_PREFETCH_EN | PreFetchNLnSzTr);
MV_REG_WRITE(REG_STATIC_DRAM_DLB_CONTROL, uiReg);
}
MV_STATUS ddr3FastPathDynamicCsSizeConfig(MV_U32 uiCsEna) {
MV_U32 uiReg, uiCs;
MV_U32 uiMemTotalSize = 0;
MV_U32 uiCsMemSize = 0;
MV_U32 uiMemTotalSize_c, uiCsMemSize_c;
#ifdef MV_DEVICE_MAX_DRAM_ADDRESS_SIZE
MV_U32 physicalMemSize;
MV_U32 maxMemSize = MV_DEVICE_MAX_DRAM_ADDRESS_SIZE;
MV_HWS_TOPOLOGY_MAP* toplogyMap = NULL;
#endif
/* Open fast path windows */
for (uiCs = 0; uiCs < MAX_CS; uiCs++) {
if (uiCsEna & (1 << uiCs)) {
/* get CS size */
if (ddr3CalcMemCsSize(uiCs, &uiCsMemSize) != MV_OK)
return MV_FAIL;
#ifdef MV_DEVICE_MAX_DRAM_ADDRESS_SIZE
/* if number of address pins doesn't allow to use max mem size that is defined in topology
mem size is defined by MV_DEVICE_MAX_DRAM_ADDRESS_SIZE*/
CHECK_STATUS(ddr3GetTopologyMap(&toplogyMap));
physicalMemSize = mv_memSize [toplogyMap->interfaceParams[0].memorySize];
if (ddr3GetDeviceWidth(uiCs) == 16)
maxMemSize = MV_DEVICE_MAX_DRAM_ADDRESS_SIZE * 2; /* 16bit mem device can be twice more - no need in less significant pin*/
if (physicalMemSize > maxMemSize ){
uiCsMemSize = maxMemSize * (ddr3GetBusWidth() / ddr3GetDeviceWidth(uiCs)) ;
mvPrintf ("Updated Physical Mem size is from 0x%x to %x\n", physicalMemSize, MV_DEVICE_MAX_DRAM_ADDRESS_SIZE);
}
#endif
/* set fast path window control for the cs */
uiReg = 0xFFFFE1;
uiReg |= (uiCs << 2);
uiReg |= (uiCsMemSize - 1) & 0xFFFF0000;
MV_REG_WRITE(REG_FASTPATH_WIN_CTRL_ADDR(uiCs), uiReg); /*Open fast path Window */
/* set fast path window base address for the cs */
uiReg = ((uiCsMemSize) * uiCs) & 0xFFFF0000;
MV_REG_WRITE(REG_FASTPATH_WIN_BASE_ADDR(uiCs), uiReg); /*Set base address */
/* since memory size may be bigger than 4G the summ may be more than 32 bit word,
so to estimate the result divide uiMemTotalSize and uiCsMemSize by 0x10000 (it is equal to >>16) */
uiMemTotalSize_c = uiMemTotalSize >> 16;
uiCsMemSize_c = uiCsMemSize >>16;
/*if the sum less than 2 G - calculate the value*/
if (uiMemTotalSize_c + uiCsMemSize_c < 0x10000)
uiMemTotalSize += uiCsMemSize;
else /* put max possible size */
uiMemTotalSize = L2_FILTER_FOR_MAX_MEMORY_SIZE;
}
}
/* Set L2 filtering to Max Memory size */
MV_REG_WRITE( ADDRESS_FILTERING_END_REGISTER, uiMemTotalSize);
return MV_OK;
}
MV_U32 ddr3GetBusWidth(void) {
MV_U32 uiBusWidth;
uiBusWidth = (MV_REG_READ(REG_SDRAM_CONFIG_ADDR) & 0x8000) >> REG_SDRAM_CONFIG_WIDTH_OFFS;
return (uiBusWidth == 0) ? 16 : 32;
}
MV_U32 ddr3GetDeviceWidth(MV_U32 uiCs) {
MV_U32 uiDeviceWidth;
uiDeviceWidth = (MV_REG_READ(REG_SDRAM_ADDRESS_CTRL_ADDR) & (0x3 << (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * uiCs))) >> (REG_SDRAM_ADDRESS_CTRL_STRUCT_OFFS * uiCs);
return (uiDeviceWidth == 0) ? 8 : 16;
}
MV_FLOAT ddr3GetDeviceSize(MV_U32 uiCs) {
MV_U32 uiDeviceSizeLow, uiDeviceSizeHigh, uiDeviceSize;
MV_U32 uiRegData, uiCsLowOffset, uiCsHighOffset;
uiCsLowOffset = REG_SDRAM_ADDRESS_SIZE_OFFS + uiCs * 4;
uiCsHighOffset = REG_SDRAM_ADDRESS_SIZE_OFFS + REG_SDRAM_ADDRESS_SIZE_HIGH_OFFS + uiCs;
uiRegData = MV_REG_READ(REG_SDRAM_ADDRESS_CTRL_ADDR);
uiDeviceSizeLow = (uiRegData >> uiCsLowOffset) & 0x3;
uiDeviceSizeHigh = (uiRegData >> uiCsHighOffset) & 0x1;
uiDeviceSize = uiDeviceSizeLow | (uiDeviceSizeHigh << 2);
switch(uiDeviceSize)
{
case 0:
return 2;
case 2:
return 0.5;
case 3:
return 1;
case 4:
return 4;
case 5:
return 8;
case 1:
default:
DEBUG_INIT_C("Error: Wrong device size of Cs: ", uiCs, 1);
return 0.01; /* small value will give wrong emem size in ddr3CalcMemCsSize */
}
}
MV_STATUS ddr3CalcMemCsSize(MV_U32 uiCs, MV_U32* puiCsSize){
MV_FLOAT uiCsMemSize;
uiCsMemSize = ((ddr3GetBusWidth() / ddr3GetDeviceWidth(uiCs)) * ddr3GetDeviceSize(uiCs)) / 8;/*calculate in Gbyte*/;
/*Multiple controller bus width, 2x for 64 bit
(SoC controller may be 32 or 64 bit,
so bit 15 in 0x1400, that means if whole bus used or only half, have a differnt meaning*/
uiCsMemSize *= MV_DDR_CONTROLLER_BUS_WIDTH_MULTIPLIER;
if (uiCsMemSize == 0.125) {
*puiCsSize = _128M;
} else if (uiCsMemSize == 0.25) {
*puiCsSize = _256M;
} else if (uiCsMemSize == 0.5) {
*puiCsSize = _512M;
} else if (uiCsMemSize == 1) {
*puiCsSize = _1G;
} else if (uiCsMemSize == 2) {
*puiCsSize = _2G;
} else {
DEBUG_INIT_C("Error: Wrong Memory size of Cs: ", uiCs, 1);
return MV_BAD_VALUE;
}
return MV_OK;
}
#if defined(MV_DDR_TOPOLOGY_UPDATE_FROM_TWSI)
/******************************************************************************
* Name: ddr3UpdateTopologyMap
* Desc:
* Args:
* Notes: Update topology map by SatR values
* Returns:
*/
static MV_STATUS ddr3UpdateTopologyMap(MV_HWS_TOPOLOGY_MAP* topologyMap)
{
MV_TOPOLOGY_UPDATE_INFO topologyUpdateInfo;
/* when booting from UART , skip reading DDR configuration from SW EEPROM, since EEPROM is not configured at 1st boot */
#if defined(MV_NO_PRINT)
return MV_OK;
#endif
topologyUpdateInfo.mvUpdateWidth = MV_FALSE;
topologyUpdateInfo.mvUpdateECC = MV_FALSE;
topologyUpdateInfo.mvUpdateECCPup3Mode = MV_FALSE;
mvSysEnvGetTopologyUpdateInfo(&topologyUpdateInfo);
if(topologyUpdateInfo.mvUpdateWidth == MV_TRUE)
{
topologyMap->activeBusMask &= ~(MV_TOPOLOGY_UPDATE_WIDTH_32BIT_MASK);
if(topologyUpdateInfo.mvWidth == MV_TOPOLOGY_UPDATE_WIDTH_16BIT)
topologyMap->activeBusMask = MV_TOPOLOGY_UPDATE_WIDTH_16BIT_MASK;
else
topologyMap->activeBusMask = MV_TOPOLOGY_UPDATE_WIDTH_32BIT_MASK;
}
if(topologyUpdateInfo.mvUpdateECC == MV_TRUE)
{
if(topologyUpdateInfo.mvECC == MV_TOPOLOGY_UPDATE_ECC_OFF){
topologyMap->activeBusMask &= ~(1<<topologyUpdateInfo.mvECCPupModeOffset);
}
else{
topologyMap->activeBusMask |= topologyUpdateInfo.mvECC << topologyUpdateInfo.mvECCPupModeOffset;
}
}
return MV_OK;
}
#endif
/******************************************************************************
* Name: ddr3HwsTuneTrainingParams
* Desc:
* Args:
* Notes: Tune internal training params
* Returns:
*/
static MV_STATUS ddr3HwsTuneTrainingParams(MV_U8 devNum)
{
MV_TUNE_TRAINING_PARAMS params;
MV_STATUS status;
/*NOTE: do not remove any field initilization*/
params.ckDelay = MV_TUNE_TRAINING_PARAMS_CK_DELAY;
params.PhyReg3Val = MV_TUNE_TRAINING_PARAMS_PHYREG3VAL;
params.gZpriData = MV_TUNE_TRAINING_PARAMS_PRI_DATA;
params.gZnriData = MV_TUNE_TRAINING_PARAMS_NRI_DATA;
params.gZpriCtrl = MV_TUNE_TRAINING_PARAMS_PRI_CTRL;
params.gZnriCtrl = MV_TUNE_TRAINING_PARAMS_NRI_CTRL;
params.gZpodtData = MV_TUNE_TRAINING_PARAMS_P_ODT_DATA;
params.gZnodtData = MV_TUNE_TRAINING_PARAMS_N_ODT_DATA;
params.gZpodtCtrl = MV_TUNE_TRAINING_PARAMS_P_ODT_CTRL;
params.gZnodtCtrl = MV_TUNE_TRAINING_PARAMS_N_ODT_CTRL;
params.gDic = MV_TUNE_TRAINING_PARAMS_DIC;
params.uiODTConfig = MV_TUNE_TRAINING_PARAMS_ODT_CONFIG;
params.gRttNom = MV_TUNE_TRAINING_PARAMS_RTT_NOM;
params.gRttWR = MV_TUNE_TRAINING_PARAMS_RTT_WR;
#ifdef CONFIG_DDR4
params.gZpodtData = MV_TUNE_TRAINING_PARAMS_P_ODT_DATA_DDR4;
params.uiODTConfig = MV_TUNE_TRAINING_PARAMS_ODT_CONFIG_DDR4;
params.gRttNom = MV_TUNE_TRAINING_PARAMS_RTT_NOM_DDR4;
params.gDic = MV_TUNE_TRAINING_PARAMS_DIC_DDR4;
#endif
status = ddr3TipTuneTrainingParams(devNum, &params);
if (MV_OK != status) {
mvPrintf("%s Training Sequence - FAILED\n", ddrType);
return status;
}
return MV_OK;
}