mirror of
https://github.com/Stichting-MINIX-Research-Foundation/u-boot.git
synced 2025-09-10 12:39:22 -04:00
Exynos5: DDR3: Add DDR3 memory setup for Exynos5250 Rev 1.0
The patch adds the memory initialization sequence of DDR3. Signed-off-by: Hatim Ali <hatim.rv@samsung.com> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com> Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
This commit is contained in:
parent
998e5d393f
commit
87f2e079db
@ -251,5 +251,70 @@ struct exynos5_phy_control {
|
|||||||
unsigned int phy_con41;
|
unsigned int phy_con41;
|
||||||
unsigned int phy_con42;
|
unsigned int phy_con42;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ddr_mode {
|
||||||
|
DDR_MODE_DDR2,
|
||||||
|
DDR_MODE_DDR3,
|
||||||
|
DDR_MODE_LPDDR2,
|
||||||
|
DDR_MODE_LPDDR3,
|
||||||
|
|
||||||
|
DDR_MODE_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mem_manuf {
|
||||||
|
MEM_MANUF_AUTODETECT,
|
||||||
|
MEM_MANUF_ELPIDA,
|
||||||
|
MEM_MANUF_SAMSUNG,
|
||||||
|
|
||||||
|
MEM_MANUF_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* CONCONTROL register fields */
|
||||||
|
#define CONCONTROL_DFI_INIT_START_SHIFT 28
|
||||||
|
#define CONCONTROL_RD_FETCH_SHIFT 12
|
||||||
|
#define CONCONTROL_RD_FETCH_MASK (0x7 << CONCONTROL_RD_FETCH_SHIFT)
|
||||||
|
#define CONCONTROL_AREF_EN_SHIFT 5
|
||||||
|
|
||||||
|
/* PRECHCONFIG register field */
|
||||||
|
#define PRECHCONFIG_TP_CNT_SHIFT 24
|
||||||
|
|
||||||
|
/* PWRDNCONFIG register field */
|
||||||
|
#define PWRDNCONFIG_DPWRDN_CYC_SHIFT 0
|
||||||
|
#define PWRDNCONFIG_DSREF_CYC_SHIFT 16
|
||||||
|
|
||||||
|
/* PHY_CON0 register fields */
|
||||||
|
#define PHY_CON0_T_WRRDCMD_SHIFT 17
|
||||||
|
#define PHY_CON0_T_WRRDCMD_MASK (0x7 << PHY_CON0_T_WRRDCMD_SHIFT)
|
||||||
|
#define PHY_CON0_CTRL_DDR_MODE_SHIFT 11
|
||||||
|
|
||||||
|
/* PHY_CON1 register fields */
|
||||||
|
#define PHY_CON1_RDLVL_RDDATA_ADJ_SHIFT 0
|
||||||
|
|
||||||
|
/* PHY_CON12 register fields */
|
||||||
|
#define PHY_CON12_CTRL_START_POINT_SHIFT 24
|
||||||
|
#define PHY_CON12_CTRL_INC_SHIFT 16
|
||||||
|
#define PHY_CON12_CTRL_FORCE_SHIFT 8
|
||||||
|
#define PHY_CON12_CTRL_START_SHIFT 6
|
||||||
|
#define PHY_CON12_CTRL_START_MASK (1 << PHY_CON12_CTRL_START_SHIFT)
|
||||||
|
#define PHY_CON12_CTRL_DLL_ON_SHIFT 5
|
||||||
|
#define PHY_CON12_CTRL_DLL_ON_MASK (1 << PHY_CON12_CTRL_DLL_ON_SHIFT)
|
||||||
|
#define PHY_CON12_CTRL_REF_SHIFT 1
|
||||||
|
|
||||||
|
/* PHY_CON16 register fields */
|
||||||
|
#define PHY_CON16_ZQ_MODE_DDS_SHIFT 24
|
||||||
|
#define PHY_CON16_ZQ_MODE_DDS_MASK (0x7 << PHY_CON16_ZQ_MODE_DDS_SHIFT)
|
||||||
|
|
||||||
|
#define PHY_CON16_ZQ_MODE_TERM_SHIFT 21
|
||||||
|
#define PHY_CON16_ZQ_MODE_TERM_MASK (0x7 << PHY_CON16_ZQ_MODE_TERM_SHIFT)
|
||||||
|
|
||||||
|
#define PHY_CON16_ZQ_MODE_NOTERM_MASK (1 << 19)
|
||||||
|
|
||||||
|
/* PHY_CON42 register fields */
|
||||||
|
#define PHY_CON42_CTRL_BSTLEN_SHIFT 8
|
||||||
|
#define PHY_CON42_CTRL_BSTLEN_MASK (0xff << PHY_CON42_CTRL_BSTLEN_SHIFT)
|
||||||
|
|
||||||
|
#define PHY_CON42_CTRL_RDLAT_SHIFT 0
|
||||||
|
#define PHY_CON42_CTRL_RDLAT_MASK (0x1f << PHY_CON42_CTRL_RDLAT_SHIFT)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,7 +27,7 @@ LIB = $(obj)lib$(BOARD).o
|
|||||||
SOBJS := lowlevel_init.o
|
SOBJS := lowlevel_init.o
|
||||||
|
|
||||||
COBJS := clock_init.o
|
COBJS := clock_init.o
|
||||||
COBJS += dmc_init.o
|
COBJS += dmc_common.o dmc_init_ddr3.o
|
||||||
COBJS += tzpc_init.o
|
COBJS += tzpc_init.o
|
||||||
COBJS += smdk5250_spl.o
|
COBJS += smdk5250_spl.o
|
||||||
|
|
||||||
|
199
board/samsung/smdk5250/dmc_common.c
Normal file
199
board/samsung/smdk5250/dmc_common.c
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* Mem setup common file for different types of DDR present on SMDK5250 boards.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Samsung Electronics
|
||||||
|
*
|
||||||
|
* See file CREDITS for list of people who contributed to this
|
||||||
|
* project.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||||
|
* MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <asm/arch/spl.h>
|
||||||
|
|
||||||
|
#include "clock_init.h"
|
||||||
|
#include "setup.h"
|
||||||
|
|
||||||
|
#define ZQ_INIT_TIMEOUT 10000
|
||||||
|
|
||||||
|
int dmc_config_zq(struct mem_timings *mem,
|
||||||
|
struct exynos5_phy_control *phy0_ctrl,
|
||||||
|
struct exynos5_phy_control *phy1_ctrl)
|
||||||
|
{
|
||||||
|
unsigned long val = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ZQ Calibration:
|
||||||
|
* Select Driver Strength,
|
||||||
|
* long calibration for manual calibration
|
||||||
|
*/
|
||||||
|
val = PHY_CON16_RESET_VAL;
|
||||||
|
val |= mem->zq_mode_dds << PHY_CON16_ZQ_MODE_DDS_SHIFT;
|
||||||
|
val |= mem->zq_mode_term << PHY_CON16_ZQ_MODE_TERM_SHIFT;
|
||||||
|
val |= ZQ_CLK_DIV_EN;
|
||||||
|
writel(val, &phy0_ctrl->phy_con16);
|
||||||
|
writel(val, &phy1_ctrl->phy_con16);
|
||||||
|
|
||||||
|
/* Disable termination */
|
||||||
|
if (mem->zq_mode_noterm)
|
||||||
|
val |= PHY_CON16_ZQ_MODE_NOTERM_MASK;
|
||||||
|
writel(val, &phy0_ctrl->phy_con16);
|
||||||
|
writel(val, &phy1_ctrl->phy_con16);
|
||||||
|
|
||||||
|
/* ZQ_MANUAL_START: Enable */
|
||||||
|
val |= ZQ_MANUAL_STR;
|
||||||
|
writel(val, &phy0_ctrl->phy_con16);
|
||||||
|
writel(val, &phy1_ctrl->phy_con16);
|
||||||
|
|
||||||
|
/* ZQ_MANUAL_START: Disable */
|
||||||
|
val &= ~ZQ_MANUAL_STR;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since we are manaully calibrating the ZQ values,
|
||||||
|
* we are looping for the ZQ_init to complete.
|
||||||
|
*/
|
||||||
|
i = ZQ_INIT_TIMEOUT;
|
||||||
|
while ((readl(&phy0_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
|
||||||
|
sdelay(100);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
if (!i)
|
||||||
|
return -1;
|
||||||
|
writel(val, &phy0_ctrl->phy_con16);
|
||||||
|
|
||||||
|
i = ZQ_INIT_TIMEOUT;
|
||||||
|
while ((readl(&phy1_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
|
||||||
|
sdelay(100);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
if (!i)
|
||||||
|
return -1;
|
||||||
|
writel(val, &phy1_ctrl->phy_con16);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_reset_dll(struct exynos5_dmc *dmc, enum ddr_mode mode)
|
||||||
|
{
|
||||||
|
unsigned long val;
|
||||||
|
|
||||||
|
if (mode == DDR_MODE_DDR3) {
|
||||||
|
val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE;
|
||||||
|
writel(val, &dmc->phycontrol0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update DLL Information: Force DLL Resyncronization */
|
||||||
|
val = readl(&dmc->phycontrol0);
|
||||||
|
val |= FP_RSYNC;
|
||||||
|
writel(val, &dmc->phycontrol0);
|
||||||
|
|
||||||
|
/* Reset Force DLL Resyncronization */
|
||||||
|
val = readl(&dmc->phycontrol0);
|
||||||
|
val &= ~FP_RSYNC;
|
||||||
|
writel(val, &dmc->phycontrol0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc)
|
||||||
|
{
|
||||||
|
int channel, chip;
|
||||||
|
|
||||||
|
for (channel = 0; channel < mem->dmc_channels; channel++) {
|
||||||
|
unsigned long mask;
|
||||||
|
|
||||||
|
mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
|
||||||
|
for (chip = 0; chip < mem->chips_to_configure; chip++) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
mask |= chip << DIRECT_CMD_CHIP_SHIFT;
|
||||||
|
|
||||||
|
/* Sending NOP command */
|
||||||
|
writel(DIRECT_CMD_NOP | mask, &dmc->directcmd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO(alim.akhtar@samsung.com): Do we need these
|
||||||
|
* delays? This one and the next were not there for
|
||||||
|
* DDR3.
|
||||||
|
*/
|
||||||
|
sdelay(0x10000);
|
||||||
|
|
||||||
|
/* Sending EMRS/MRS commands */
|
||||||
|
for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) {
|
||||||
|
writel(mem->direct_cmd_msr[i] | mask,
|
||||||
|
&dmc->directcmd);
|
||||||
|
sdelay(0x10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mem->send_zq_init) {
|
||||||
|
/* Sending ZQINIT command */
|
||||||
|
writel(DIRECT_CMD_ZQINIT | mask,
|
||||||
|
&dmc->directcmd);
|
||||||
|
|
||||||
|
sdelay(10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc)
|
||||||
|
{
|
||||||
|
int channel, chip;
|
||||||
|
|
||||||
|
for (channel = 0; channel < mem->dmc_channels; channel++) {
|
||||||
|
unsigned long mask;
|
||||||
|
|
||||||
|
mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
|
||||||
|
for (chip = 0; chip < mem->chips_per_channel; chip++) {
|
||||||
|
mask |= chip << DIRECT_CMD_CHIP_SHIFT;
|
||||||
|
|
||||||
|
/* PALL (all banks precharge) CMD */
|
||||||
|
writel(DIRECT_CMD_PALL | mask, &dmc->directcmd);
|
||||||
|
sdelay(0x10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dmc_config_memory(struct mem_timings *mem, struct exynos5_dmc *dmc)
|
||||||
|
{
|
||||||
|
writel(mem->memconfig, &dmc->memconfig0);
|
||||||
|
writel(mem->memconfig, &dmc->memconfig1);
|
||||||
|
writel(DMC_MEMBASECONFIG0_VAL, &dmc->membaseconfig0);
|
||||||
|
writel(DMC_MEMBASECONFIG1_VAL, &dmc->membaseconfig1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_ctrl_init()
|
||||||
|
{
|
||||||
|
struct spl_machine_param *param = spl_get_machine_params();
|
||||||
|
struct mem_timings *mem;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mem = clock_get_mem_timings();
|
||||||
|
|
||||||
|
/* If there are any other memory variant, add their init call below */
|
||||||
|
if (param->mem_type == DDR_MODE_DDR3) {
|
||||||
|
ret = ddr3_mem_ctrl_init(mem, param->mem_iv_size);
|
||||||
|
if (ret) {
|
||||||
|
/* will hang if failed to init memory control */
|
||||||
|
while (1)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* will hang if unknow memory type */
|
||||||
|
while (1)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
@ -1,462 +0,0 @@
|
|||||||
/*
|
|
||||||
* Memory setup for SMDK5250 board based on EXYNOS5
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012 Samsung Electronics
|
|
||||||
*
|
|
||||||
* See file CREDITS for list of people who contributed to this
|
|
||||||
* project.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
||||||
* MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <asm/io.h>
|
|
||||||
#include <asm/arch/dmc.h>
|
|
||||||
#include <asm/arch/clock.h>
|
|
||||||
#include <asm/arch/cpu.h>
|
|
||||||
#include "setup.h"
|
|
||||||
|
|
||||||
/* APLL : 1GHz */
|
|
||||||
/* MCLK_CDREX: MCLK_CDREX_533*/
|
|
||||||
/* LPDDR support: LPDDR2 */
|
|
||||||
static void reset_phy_ctrl(void);
|
|
||||||
static void config_zq(struct exynos5_phy_control *,
|
|
||||||
struct exynos5_phy_control *);
|
|
||||||
static void update_reset_dll(struct exynos5_dmc *);
|
|
||||||
static void config_cdrex(void);
|
|
||||||
static void config_mrs(struct exynos5_dmc *);
|
|
||||||
static void sec_sdram_phy_init(struct exynos5_dmc *);
|
|
||||||
static void config_prech(struct exynos5_dmc *);
|
|
||||||
static void config_rdlvl(struct exynos5_dmc *,
|
|
||||||
struct exynos5_phy_control *,
|
|
||||||
struct exynos5_phy_control *);
|
|
||||||
static void config_memory(struct exynos5_dmc *);
|
|
||||||
|
|
||||||
static void config_offsets(unsigned int,
|
|
||||||
struct exynos5_phy_control *,
|
|
||||||
struct exynos5_phy_control *);
|
|
||||||
|
|
||||||
static void reset_phy_ctrl(void)
|
|
||||||
{
|
|
||||||
struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
|
|
||||||
|
|
||||||
writel(PHY_RESET_VAL, &clk->lpddr3phy_ctrl);
|
|
||||||
sdelay(0x10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void config_zq(struct exynos5_phy_control *phy0_ctrl,
|
|
||||||
struct exynos5_phy_control *phy1_ctrl)
|
|
||||||
{
|
|
||||||
unsigned long val = 0;
|
|
||||||
/*
|
|
||||||
* ZQ Calibration:
|
|
||||||
* Select Driver Strength,
|
|
||||||
* long calibration for manual calibration
|
|
||||||
*/
|
|
||||||
val = PHY_CON16_RESET_VAL;
|
|
||||||
SET_ZQ_MODE_DDS_VAL(val);
|
|
||||||
SET_ZQ_MODE_TERM_VAL(val);
|
|
||||||
val |= ZQ_CLK_DIV_EN;
|
|
||||||
writel(val, &phy0_ctrl->phy_con16);
|
|
||||||
writel(val, &phy1_ctrl->phy_con16);
|
|
||||||
|
|
||||||
/* Disable termination */
|
|
||||||
val |= ZQ_MODE_NOTERM;
|
|
||||||
writel(val, &phy0_ctrl->phy_con16);
|
|
||||||
writel(val, &phy1_ctrl->phy_con16);
|
|
||||||
|
|
||||||
/* ZQ_MANUAL_START: Enable */
|
|
||||||
val |= ZQ_MANUAL_STR;
|
|
||||||
writel(val, &phy0_ctrl->phy_con16);
|
|
||||||
writel(val, &phy1_ctrl->phy_con16);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
/* ZQ_MANUAL_START: Disable */
|
|
||||||
val &= ~ZQ_MANUAL_STR;
|
|
||||||
writel(val, &phy0_ctrl->phy_con16);
|
|
||||||
writel(val, &phy1_ctrl->phy_con16);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_reset_dll(struct exynos5_dmc *dmc)
|
|
||||||
{
|
|
||||||
unsigned long val;
|
|
||||||
/*
|
|
||||||
* Update DLL Information:
|
|
||||||
* Force DLL Resyncronization
|
|
||||||
*/
|
|
||||||
val = readl(&dmc->phycontrol0);
|
|
||||||
val |= FP_RSYNC;
|
|
||||||
writel(val, &dmc->phycontrol0);
|
|
||||||
|
|
||||||
/* Reset Force DLL Resyncronization */
|
|
||||||
val = readl(&dmc->phycontrol0);
|
|
||||||
val &= ~FP_RSYNC;
|
|
||||||
writel(val, &dmc->phycontrol0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void config_mrs(struct exynos5_dmc *dmc)
|
|
||||||
{
|
|
||||||
unsigned long channel, chip, mask = 0, val;
|
|
||||||
|
|
||||||
for (channel = 0; channel < CONFIG_DMC_CHANNELS; channel++) {
|
|
||||||
SET_CMD_CHANNEL(mask, channel);
|
|
||||||
for (chip = 0; chip < CONFIG_CHIPS_PER_CHANNEL; chip++) {
|
|
||||||
/*
|
|
||||||
* NOP CMD:
|
|
||||||
* Assert and hold CKE to logic high level
|
|
||||||
*/
|
|
||||||
SET_CMD_CHIP(mask, chip);
|
|
||||||
val = DIRECT_CMD_NOP | mask;
|
|
||||||
writel(val, &dmc->directcmd);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
/* EMRS, MRS Cmds(Mode Reg Settings) Using Direct Cmd */
|
|
||||||
val = DIRECT_CMD_MRS1 | mask;
|
|
||||||
writel(val, &dmc->directcmd);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
val = DIRECT_CMD_MRS2 | mask;
|
|
||||||
writel(val, &dmc->directcmd);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
/* MCLK_CDREX_533 */
|
|
||||||
val = DIRECT_CMD_MRS3 | mask;
|
|
||||||
writel(val, &dmc->directcmd);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
val = DIRECT_CMD_MRS4 | mask;
|
|
||||||
writel(val, &dmc->directcmd);
|
|
||||||
sdelay(0x10000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void config_prech(struct exynos5_dmc *dmc)
|
|
||||||
{
|
|
||||||
unsigned long channel, chip, mask = 0, val;
|
|
||||||
|
|
||||||
for (channel = 0; channel < CONFIG_DMC_CHANNELS; channel++) {
|
|
||||||
SET_CMD_CHANNEL(mask, channel);
|
|
||||||
for (chip = 0; chip < CONFIG_CHIPS_PER_CHANNEL; chip++) {
|
|
||||||
SET_CMD_CHIP(mask, chip);
|
|
||||||
/* PALL (all banks precharge) CMD */
|
|
||||||
val = DIRECT_CMD_PALL | mask;
|
|
||||||
writel(val, &dmc->directcmd);
|
|
||||||
sdelay(0x10000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sec_sdram_phy_init(struct exynos5_dmc *dmc)
|
|
||||||
{
|
|
||||||
unsigned long val;
|
|
||||||
val = readl(&dmc->concontrol);
|
|
||||||
val |= DFI_INIT_START;
|
|
||||||
writel(val, &dmc->concontrol);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
val = readl(&dmc->concontrol);
|
|
||||||
val &= ~DFI_INIT_START;
|
|
||||||
writel(val, &dmc->concontrol);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void config_offsets(unsigned int state,
|
|
||||||
struct exynos5_phy_control *phy0_ctrl,
|
|
||||||
struct exynos5_phy_control *phy1_ctrl)
|
|
||||||
{
|
|
||||||
unsigned long val;
|
|
||||||
/* Set Offsets to read DQS */
|
|
||||||
val = (state == SET) ? SET_DQS_OFFSET_VAL : RESET_DQS_OFFSET_VAL;
|
|
||||||
writel(val, &phy0_ctrl->phy_con4);
|
|
||||||
writel(val, &phy1_ctrl->phy_con4);
|
|
||||||
|
|
||||||
/* Set Offsets to read DQ */
|
|
||||||
val = (state == SET) ? SET_DQ_OFFSET_VAL : RESET_DQ_OFFSET_VAL;
|
|
||||||
writel(val, &phy0_ctrl->phy_con6);
|
|
||||||
writel(val, &phy1_ctrl->phy_con6);
|
|
||||||
|
|
||||||
/* Debug Offset */
|
|
||||||
val = (state == SET) ? SET_DEBUG_OFFSET_VAL : RESET_DEBUG_OFFSET_VAL;
|
|
||||||
writel(val, &phy0_ctrl->phy_con10);
|
|
||||||
writel(val, &phy1_ctrl->phy_con10);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void config_cdrex(void)
|
|
||||||
{
|
|
||||||
struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
|
|
||||||
writel(CLK_DIV_CDREX_VAL, &clk->div_cdrex);
|
|
||||||
writel(CLK_SRC_CDREX_VAL, &clk->src_cdrex);
|
|
||||||
sdelay(0x30000);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void config_ctrl_dll_on(unsigned int state,
|
|
||||||
unsigned int ctrl_force_val,
|
|
||||||
struct exynos5_phy_control *phy0_ctrl,
|
|
||||||
struct exynos5_phy_control *phy1_ctrl)
|
|
||||||
{
|
|
||||||
unsigned long val;
|
|
||||||
val = readl(&phy0_ctrl->phy_con12);
|
|
||||||
CONFIG_CTRL_DLL_ON(val, state);
|
|
||||||
SET_CTRL_FORCE_VAL(val, ctrl_force_val);
|
|
||||||
writel(val, &phy0_ctrl->phy_con12);
|
|
||||||
|
|
||||||
val = readl(&phy1_ctrl->phy_con12);
|
|
||||||
CONFIG_CTRL_DLL_ON(val, state);
|
|
||||||
SET_CTRL_FORCE_VAL(val, ctrl_force_val);
|
|
||||||
writel(val, &phy1_ctrl->phy_con12);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void config_ctrl_start(unsigned int state,
|
|
||||||
struct exynos5_phy_control *phy0_ctrl,
|
|
||||||
struct exynos5_phy_control *phy1_ctrl)
|
|
||||||
{
|
|
||||||
unsigned long val;
|
|
||||||
val = readl(&phy0_ctrl->phy_con12);
|
|
||||||
CONFIG_CTRL_START(val, state);
|
|
||||||
writel(val, &phy0_ctrl->phy_con12);
|
|
||||||
|
|
||||||
val = readl(&phy1_ctrl->phy_con12);
|
|
||||||
CONFIG_CTRL_START(val, state);
|
|
||||||
writel(val, &phy1_ctrl->phy_con12);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(CONFIG_RD_LVL)
|
|
||||||
static void config_rdlvl(struct exynos5_dmc *dmc,
|
|
||||||
struct exynos5_phy_control *phy0_ctrl,
|
|
||||||
struct exynos5_phy_control *phy1_ctrl)
|
|
||||||
{
|
|
||||||
unsigned long val;
|
|
||||||
|
|
||||||
/* Disable CTRL_DLL_ON and set ctrl_force */
|
|
||||||
config_ctrl_dll_on(RESET, 0x2D, phy0_ctrl, phy1_ctrl);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set ctrl_gateadj, ctrl_readadj
|
|
||||||
* ctrl_gateduradj, rdlvl_pass_adj
|
|
||||||
* rdlvl_rddataPadj
|
|
||||||
*/
|
|
||||||
val = SET_RDLVL_RDDATAPADJ;
|
|
||||||
writel(val, &phy0_ctrl->phy_con1);
|
|
||||||
writel(val, &phy1_ctrl->phy_con1);
|
|
||||||
|
|
||||||
/* LPDDR2 Address */
|
|
||||||
writel(LPDDR2_ADDR, &phy0_ctrl->phy_con22);
|
|
||||||
writel(LPDDR2_ADDR, &phy1_ctrl->phy_con22);
|
|
||||||
|
|
||||||
/* Enable Byte Read Leveling set ctrl_ddr_mode */
|
|
||||||
val = readl(&phy0_ctrl->phy_con0);
|
|
||||||
val |= BYTE_RDLVL_EN;
|
|
||||||
writel(val, &phy0_ctrl->phy_con0);
|
|
||||||
val = readl(&phy1_ctrl->phy_con0);
|
|
||||||
val |= BYTE_RDLVL_EN;
|
|
||||||
writel(val, &phy1_ctrl->phy_con0);
|
|
||||||
|
|
||||||
/* rdlvl_en: Use levelling offset instead ctrl_shiftc */
|
|
||||||
val = PHY_CON2_RESET_VAL | RDLVL_EN;
|
|
||||||
writel(val, &phy0_ctrl->phy_con2);
|
|
||||||
writel(val, &phy1_ctrl->phy_con2);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
/* Enable Data Eye Training */
|
|
||||||
val = readl(&dmc->rdlvl_config);
|
|
||||||
val |= CTRL_RDLVL_DATA_EN;
|
|
||||||
writel(val, &dmc->rdlvl_config);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
/* Disable Data Eye Training */
|
|
||||||
val = readl(&dmc->rdlvl_config);
|
|
||||||
val &= ~CTRL_RDLVL_DATA_EN;
|
|
||||||
writel(val, &dmc->rdlvl_config);
|
|
||||||
|
|
||||||
/* RdDeSkew_clear: Clear */
|
|
||||||
val = readl(&phy0_ctrl->phy_con2);
|
|
||||||
val |= RDDSKEW_CLEAR;
|
|
||||||
writel(val, &phy0_ctrl->phy_con2);
|
|
||||||
val = readl(&phy1_ctrl->phy_con2);
|
|
||||||
val |= RDDSKEW_CLEAR;
|
|
||||||
writel(val, &phy1_ctrl->phy_con2);
|
|
||||||
|
|
||||||
/* Enable CTRL_DLL_ON */
|
|
||||||
config_ctrl_dll_on(SET, 0x0, phy0_ctrl, phy1_ctrl);
|
|
||||||
|
|
||||||
update_reset_dll(dmc);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
/* ctrl_atgte: ctrl_gate_p*, ctrl_read_p* generated by PHY */
|
|
||||||
val = readl(&phy0_ctrl->phy_con0);
|
|
||||||
val &= ~CTRL_ATGATE;
|
|
||||||
writel(val, &phy0_ctrl->phy_con0);
|
|
||||||
val = readl(&phy1_ctrl->phy_con0);
|
|
||||||
val &= ~CTRL_ATGATE;
|
|
||||||
writel(val, &phy1_ctrl->phy_con0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void config_memory(struct exynos5_dmc *dmc)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Memory Configuration Chip 0
|
|
||||||
* Address Mapping: Interleaved
|
|
||||||
* Number of Column address Bits: 10 bits
|
|
||||||
* Number of Rows Address Bits: 14
|
|
||||||
* Number of Banks: 8
|
|
||||||
*/
|
|
||||||
writel(DMC_MEMCONFIG0_VAL, &dmc->memconfig0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Memory Configuration Chip 1
|
|
||||||
* Address Mapping: Interleaved
|
|
||||||
* Number of Column address Bits: 10 bits
|
|
||||||
* Number of Rows Address Bits: 14
|
|
||||||
* Number of Banks: 8
|
|
||||||
*/
|
|
||||||
writel(DMC_MEMCONFIG1_VAL, &dmc->memconfig1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Chip0: AXI
|
|
||||||
* AXI Base Address: 0x40000000
|
|
||||||
* AXI Base Address Mask: 0x780
|
|
||||||
*/
|
|
||||||
writel(DMC_MEMBASECONFIG0_VAL, &dmc->membaseconfig0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Chip1: AXI
|
|
||||||
* AXI Base Address: 0x80000000
|
|
||||||
* AXI Base Address Mask: 0x780
|
|
||||||
*/
|
|
||||||
writel(DMC_MEMBASECONFIG1_VAL, &dmc->membaseconfig1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mem_ctrl_init()
|
|
||||||
{
|
|
||||||
struct exynos5_phy_control *phy0_ctrl, *phy1_ctrl;
|
|
||||||
struct exynos5_dmc *dmc;
|
|
||||||
unsigned long val;
|
|
||||||
|
|
||||||
phy0_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY0_BASE;
|
|
||||||
phy1_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY1_BASE;
|
|
||||||
dmc = (struct exynos5_dmc *)EXYNOS5_DMC_CTRL_BASE;
|
|
||||||
|
|
||||||
/* Reset PHY Controllor: PHY_RESET[0] */
|
|
||||||
reset_phy_ctrl();
|
|
||||||
|
|
||||||
/*set Read Latancy and Burst Length for PHY0 and PHY1 */
|
|
||||||
writel(PHY_CON42_VAL, &phy0_ctrl->phy_con42);
|
|
||||||
writel(PHY_CON42_VAL, &phy1_ctrl->phy_con42);
|
|
||||||
|
|
||||||
/* ZQ Cofiguration */
|
|
||||||
config_zq(phy0_ctrl, phy1_ctrl);
|
|
||||||
|
|
||||||
/* Operation Mode : LPDDR2 */
|
|
||||||
val = PHY_CON0_RESET_VAL;
|
|
||||||
SET_CTRL_DDR_MODE(val, DDR_MODE_LPDDR2);
|
|
||||||
writel(val, &phy0_ctrl->phy_con0);
|
|
||||||
writel(val, &phy1_ctrl->phy_con0);
|
|
||||||
|
|
||||||
/* DQS, DQ: Signal, for LPDDR2: Always Set */
|
|
||||||
val = CTRL_PULLD_DQ | CTRL_PULLD_DQS;
|
|
||||||
writel(val, &phy0_ctrl->phy_con14);
|
|
||||||
writel(val, &phy1_ctrl->phy_con14);
|
|
||||||
|
|
||||||
/* Init SEC SDRAM PHY */
|
|
||||||
sec_sdram_phy_init(dmc);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
update_reset_dll(dmc);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dynamic Clock: Always Running
|
|
||||||
* Memory Burst length: 4
|
|
||||||
* Number of chips: 2
|
|
||||||
* Memory Bus width: 32 bit
|
|
||||||
* Memory Type: LPDDR2-S4
|
|
||||||
* Additional Latancy for PLL: 1 Cycle
|
|
||||||
*/
|
|
||||||
writel(DMC_MEMCONTROL_VAL, &dmc->memcontrol);
|
|
||||||
|
|
||||||
config_memory(dmc);
|
|
||||||
|
|
||||||
/* Precharge Configuration */
|
|
||||||
writel(DMC_PRECHCONFIG_VAL, &dmc->prechconfig);
|
|
||||||
|
|
||||||
/* Power Down mode Configuration */
|
|
||||||
writel(DMC_PWRDNCONFIG_VAL, &dmc->pwrdnconfig);
|
|
||||||
|
|
||||||
/* Periodic Refrese Interval */
|
|
||||||
writel(DMC_TIMINGREF_VAL, &dmc->timingref);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TimingRow, TimingData, TimingPower Setting:
|
|
||||||
* Values as per Memory AC Parameters
|
|
||||||
*/
|
|
||||||
writel(DMC_TIMINGROW_VAL, &dmc->timingrow);
|
|
||||||
|
|
||||||
writel(DMC_TIMINGDATA_VAL, &dmc->timingdata);
|
|
||||||
|
|
||||||
writel(DMC_TIMINGPOWER_VAL, &dmc->timingpower);
|
|
||||||
|
|
||||||
/* Memory Channel Inteleaving Size: 128 Bytes */
|
|
||||||
writel(CONFIG_IV_SIZE, &dmc->ivcontrol);
|
|
||||||
|
|
||||||
/* Set DQS, DQ and DEBUG offsets */
|
|
||||||
config_offsets(SET, phy0_ctrl, phy1_ctrl);
|
|
||||||
|
|
||||||
/* Disable CTRL_DLL_ON and set ctrl_force */
|
|
||||||
config_ctrl_dll_on(RESET, 0x7F, phy0_ctrl, phy1_ctrl);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
update_reset_dll(dmc);
|
|
||||||
|
|
||||||
/* Config MRS(Mode Register Settingg) */
|
|
||||||
config_mrs(dmc);
|
|
||||||
|
|
||||||
config_cdrex();
|
|
||||||
|
|
||||||
/* Reset DQS DQ and DEBUG offsets */
|
|
||||||
config_offsets(RESET, phy0_ctrl, phy1_ctrl);
|
|
||||||
|
|
||||||
/* Enable CTRL_DLL_ON */
|
|
||||||
config_ctrl_dll_on(SET, 0x0, phy0_ctrl, phy1_ctrl);
|
|
||||||
|
|
||||||
/* Stop DLL Locking */
|
|
||||||
config_ctrl_start(RESET, phy0_ctrl, phy1_ctrl);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
/* Start DLL Locking */
|
|
||||||
config_ctrl_start(SET, phy0_ctrl, phy1_ctrl);
|
|
||||||
sdelay(0x10000);
|
|
||||||
|
|
||||||
update_reset_dll(dmc);
|
|
||||||
|
|
||||||
#if defined(CONFIG_RD_LVL)
|
|
||||||
config_rdlvl(dmc, phy0_ctrl, phy1_ctrl);
|
|
||||||
#endif
|
|
||||||
config_prech(dmc);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dynamic Clock: Stops During Idle Period
|
|
||||||
* Dynamic Power Down: Enable
|
|
||||||
* Dynamic Self refresh: Enable
|
|
||||||
*/
|
|
||||||
val = readl(&dmc->memcontrol);
|
|
||||||
val |= CLK_STOP_EN | DPWRDN_EN | DSREF_EN;
|
|
||||||
writel(val, &dmc->memcontrol);
|
|
||||||
|
|
||||||
/* Start Auto refresh */
|
|
||||||
val = readl(&dmc->concontrol);
|
|
||||||
val |= AREF_EN;
|
|
||||||
writel(val, &dmc->concontrol);
|
|
||||||
}
|
|
228
board/samsung/smdk5250/dmc_init_ddr3.c
Normal file
228
board/samsung/smdk5250/dmc_init_ddr3.c
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
/*
|
||||||
|
* DDR3 mem setup file for SMDK5250 board based on EXYNOS5
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Samsung Electronics
|
||||||
|
*
|
||||||
|
* See file CREDITS for list of people who contributed to this
|
||||||
|
* project.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||||
|
* MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <asm/arch/clock.h>
|
||||||
|
#include <asm/arch/cpu.h>
|
||||||
|
#include <asm/arch/dmc.h>
|
||||||
|
#include "setup.h"
|
||||||
|
#include "clock_init.h"
|
||||||
|
|
||||||
|
#define RDLVL_COMPLETE_TIMEOUT 10000
|
||||||
|
|
||||||
|
static void reset_phy_ctrl(void)
|
||||||
|
{
|
||||||
|
struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
|
||||||
|
|
||||||
|
writel(DDR3PHY_CTRL_PHY_RESET_OFF, &clk->lpddr3phy_ctrl);
|
||||||
|
writel(DDR3PHY_CTRL_PHY_RESET, &clk->lpddr3phy_ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size)
|
||||||
|
{
|
||||||
|
unsigned int val;
|
||||||
|
struct exynos5_phy_control *phy0_ctrl, *phy1_ctrl;
|
||||||
|
struct exynos5_dmc *dmc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
phy0_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY0_BASE;
|
||||||
|
phy1_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY1_BASE;
|
||||||
|
dmc = (struct exynos5_dmc *)EXYNOS5_DMC_CTRL_BASE;
|
||||||
|
|
||||||
|
reset_phy_ctrl();
|
||||||
|
|
||||||
|
/* Set Impedance Output Driver */
|
||||||
|
val = (mem->impedance << CA_CK_DRVR_DS_OFFSET) |
|
||||||
|
(mem->impedance << CA_CKE_DRVR_DS_OFFSET) |
|
||||||
|
(mem->impedance << CA_CS_DRVR_DS_OFFSET) |
|
||||||
|
(mem->impedance << CA_ADR_DRVR_DS_OFFSET);
|
||||||
|
writel(val, &phy0_ctrl->phy_con39);
|
||||||
|
writel(val, &phy1_ctrl->phy_con39);
|
||||||
|
|
||||||
|
/* Set Read Latency and Burst Length for PHY0 and PHY1 */
|
||||||
|
val = (mem->ctrl_bstlen << PHY_CON42_CTRL_BSTLEN_SHIFT) |
|
||||||
|
(mem->ctrl_rdlat << PHY_CON42_CTRL_RDLAT_SHIFT);
|
||||||
|
writel(val, &phy0_ctrl->phy_con42);
|
||||||
|
writel(val, &phy1_ctrl->phy_con42);
|
||||||
|
|
||||||
|
/* ZQ Calibration */
|
||||||
|
if (dmc_config_zq(mem, phy0_ctrl, phy1_ctrl))
|
||||||
|
return SETUP_ERR_ZQ_CALIBRATION_FAILURE;
|
||||||
|
|
||||||
|
/* DQ Signal */
|
||||||
|
writel(mem->phy0_pulld_dqs, &phy0_ctrl->phy_con14);
|
||||||
|
writel(mem->phy1_pulld_dqs, &phy1_ctrl->phy_con14);
|
||||||
|
|
||||||
|
writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)
|
||||||
|
| (mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT),
|
||||||
|
&dmc->concontrol);
|
||||||
|
|
||||||
|
update_reset_dll(dmc, DDR_MODE_DDR3);
|
||||||
|
|
||||||
|
/* DQS Signal */
|
||||||
|
writel(mem->phy0_dqs, &phy0_ctrl->phy_con4);
|
||||||
|
writel(mem->phy1_dqs, &phy1_ctrl->phy_con4);
|
||||||
|
|
||||||
|
writel(mem->phy0_dq, &phy0_ctrl->phy_con6);
|
||||||
|
writel(mem->phy1_dq, &phy1_ctrl->phy_con6);
|
||||||
|
|
||||||
|
writel(mem->phy0_tFS, &phy0_ctrl->phy_con10);
|
||||||
|
writel(mem->phy1_tFS, &phy1_ctrl->phy_con10);
|
||||||
|
|
||||||
|
val = (mem->ctrl_start_point << PHY_CON12_CTRL_START_POINT_SHIFT) |
|
||||||
|
(mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
|
||||||
|
(mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) |
|
||||||
|
(mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
|
||||||
|
writel(val, &phy0_ctrl->phy_con12);
|
||||||
|
writel(val, &phy1_ctrl->phy_con12);
|
||||||
|
|
||||||
|
/* Start DLL locking */
|
||||||
|
writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
|
||||||
|
&phy0_ctrl->phy_con12);
|
||||||
|
writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
|
||||||
|
&phy1_ctrl->phy_con12);
|
||||||
|
|
||||||
|
update_reset_dll(dmc, DDR_MODE_DDR3);
|
||||||
|
|
||||||
|
writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),
|
||||||
|
&dmc->concontrol);
|
||||||
|
|
||||||
|
/* Memory Channel Inteleaving Size */
|
||||||
|
writel(mem->iv_size, &dmc->ivcontrol);
|
||||||
|
|
||||||
|
writel(mem->memconfig, &dmc->memconfig0);
|
||||||
|
writel(mem->memconfig, &dmc->memconfig1);
|
||||||
|
writel(mem->membaseconfig0, &dmc->membaseconfig0);
|
||||||
|
writel(mem->membaseconfig1, &dmc->membaseconfig1);
|
||||||
|
|
||||||
|
/* Precharge Configuration */
|
||||||
|
writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT,
|
||||||
|
&dmc->prechconfig);
|
||||||
|
|
||||||
|
/* Power Down mode Configuration */
|
||||||
|
writel(mem->dpwrdn_cyc << PWRDNCONFIG_DPWRDN_CYC_SHIFT |
|
||||||
|
mem->dsref_cyc << PWRDNCONFIG_DSREF_CYC_SHIFT,
|
||||||
|
&dmc->pwrdnconfig);
|
||||||
|
|
||||||
|
/* TimingRow, TimingData, TimingPower and Timingaref
|
||||||
|
* values as per Memory AC parameters
|
||||||
|
*/
|
||||||
|
writel(mem->timing_ref, &dmc->timingref);
|
||||||
|
writel(mem->timing_row, &dmc->timingrow);
|
||||||
|
writel(mem->timing_data, &dmc->timingdata);
|
||||||
|
writel(mem->timing_power, &dmc->timingpower);
|
||||||
|
|
||||||
|
/* Send PALL command */
|
||||||
|
dmc_config_prech(mem, dmc);
|
||||||
|
|
||||||
|
/* Send NOP, MRS and ZQINIT commands */
|
||||||
|
dmc_config_mrs(mem, dmc);
|
||||||
|
|
||||||
|
if (mem->gate_leveling_enable) {
|
||||||
|
val = PHY_CON0_RESET_VAL;
|
||||||
|
val |= P0_CMD_EN;
|
||||||
|
writel(val, &phy0_ctrl->phy_con0);
|
||||||
|
writel(val, &phy1_ctrl->phy_con0);
|
||||||
|
|
||||||
|
val = PHY_CON2_RESET_VAL;
|
||||||
|
val |= INIT_DESKEW_EN;
|
||||||
|
writel(val, &phy0_ctrl->phy_con2);
|
||||||
|
writel(val, &phy1_ctrl->phy_con2);
|
||||||
|
|
||||||
|
val = PHY_CON0_RESET_VAL;
|
||||||
|
val |= P0_CMD_EN;
|
||||||
|
val |= BYTE_RDLVL_EN;
|
||||||
|
writel(val, &phy0_ctrl->phy_con0);
|
||||||
|
writel(val, &phy1_ctrl->phy_con0);
|
||||||
|
|
||||||
|
val = (mem->ctrl_start_point <<
|
||||||
|
PHY_CON12_CTRL_START_POINT_SHIFT) |
|
||||||
|
(mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
|
||||||
|
(mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) |
|
||||||
|
(mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) |
|
||||||
|
(mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
|
||||||
|
writel(val, &phy0_ctrl->phy_con12);
|
||||||
|
writel(val, &phy1_ctrl->phy_con12);
|
||||||
|
|
||||||
|
val = PHY_CON2_RESET_VAL;
|
||||||
|
val |= INIT_DESKEW_EN;
|
||||||
|
val |= RDLVL_GATE_EN;
|
||||||
|
writel(val, &phy0_ctrl->phy_con2);
|
||||||
|
writel(val, &phy1_ctrl->phy_con2);
|
||||||
|
|
||||||
|
val = PHY_CON0_RESET_VAL;
|
||||||
|
val |= P0_CMD_EN;
|
||||||
|
val |= BYTE_RDLVL_EN;
|
||||||
|
val |= CTRL_SHGATE;
|
||||||
|
writel(val, &phy0_ctrl->phy_con0);
|
||||||
|
writel(val, &phy1_ctrl->phy_con0);
|
||||||
|
|
||||||
|
val = PHY_CON1_RESET_VAL;
|
||||||
|
val &= ~(CTRL_GATEDURADJ_MASK);
|
||||||
|
writel(val, &phy0_ctrl->phy_con1);
|
||||||
|
writel(val, &phy1_ctrl->phy_con1);
|
||||||
|
|
||||||
|
writel(CTRL_RDLVL_GATE_ENABLE, &dmc->rdlvl_config);
|
||||||
|
i = RDLVL_COMPLETE_TIMEOUT;
|
||||||
|
while ((readl(&dmc->phystatus) &
|
||||||
|
(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1)) !=
|
||||||
|
(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1) && i > 0) {
|
||||||
|
/*
|
||||||
|
* TODO(waihong): Comment on how long this take to
|
||||||
|
* timeout
|
||||||
|
*/
|
||||||
|
sdelay(100);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
if (!i)
|
||||||
|
return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
|
||||||
|
writel(CTRL_RDLVL_GATE_DISABLE, &dmc->rdlvl_config);
|
||||||
|
|
||||||
|
writel(0, &phy0_ctrl->phy_con14);
|
||||||
|
writel(0, &phy1_ctrl->phy_con14);
|
||||||
|
|
||||||
|
val = (mem->ctrl_start_point <<
|
||||||
|
PHY_CON12_CTRL_START_POINT_SHIFT) |
|
||||||
|
(mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
|
||||||
|
(mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) |
|
||||||
|
(mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) |
|
||||||
|
(mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) |
|
||||||
|
(mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
|
||||||
|
writel(val, &phy0_ctrl->phy_con12);
|
||||||
|
writel(val, &phy1_ctrl->phy_con12);
|
||||||
|
|
||||||
|
update_reset_dll(dmc, DDR_MODE_DDR3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send PALL command */
|
||||||
|
dmc_config_prech(mem, dmc);
|
||||||
|
|
||||||
|
writel(mem->memcontrol, &dmc->memcontrol);
|
||||||
|
|
||||||
|
/* Set DMC Concontrol and enable auto-refresh counter */
|
||||||
|
writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)
|
||||||
|
| (mem->aref_en << CONCONTROL_AREF_EN_SHIFT), &dmc->concontrol);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -529,9 +529,66 @@ enum {
|
|||||||
SETUP_ERR_ZQ_CALIBRATION_FAILURE = -2,
|
SETUP_ERR_ZQ_CALIBRATION_FAILURE = -2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Memory variant specific initialization code
|
||||||
|
*
|
||||||
|
* @param mem Memory timings for this memory type.
|
||||||
|
* @param mem_iv_size Memory interleaving size is a configurable parameter
|
||||||
|
* which the DMC uses to decide how to split a memory
|
||||||
|
* chunk into smaller chunks to support concurrent
|
||||||
|
* accesses; may vary across boards.
|
||||||
|
* @return 0 if ok, SETUP_ERR_... if there is a problem
|
||||||
|
*/
|
||||||
|
int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure ZQ I/O interface
|
||||||
|
*
|
||||||
|
* @param mem Memory timings for this memory type.
|
||||||
|
* @param phy0_ctrl Pointer to struct containing PHY0 control reg
|
||||||
|
* @param phy1_ctrl Pointer to struct containing PHY1 control reg
|
||||||
|
* @return 0 if ok, -1 on error
|
||||||
|
*/
|
||||||
|
int dmc_config_zq(struct mem_timings *mem,
|
||||||
|
struct exynos5_phy_control *phy0_ctrl,
|
||||||
|
struct exynos5_phy_control *phy1_ctrl);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send NOP and MRS/EMRS Direct commands
|
||||||
|
*
|
||||||
|
* @param mem Memory timings for this memory type.
|
||||||
|
* @param dmc Pointer to struct of DMC registers
|
||||||
|
*/
|
||||||
|
void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send PALL Direct commands
|
||||||
|
*
|
||||||
|
* @param mem Memory timings for this memory type.
|
||||||
|
* @param dmc Pointer to struct of DMC registers
|
||||||
|
*/
|
||||||
|
void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure the memconfig and membaseconfig registers
|
||||||
|
*
|
||||||
|
* @param mem Memory timings for this memory type.
|
||||||
|
* @param exynos5_dmc Pointer to struct of DMC registers
|
||||||
|
*/
|
||||||
|
void dmc_config_memory(struct mem_timings *mem, struct exynos5_dmc *dmc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset the DLL. This function is common between DDR3 and LPDDR2.
|
||||||
|
* However, the reset value is different. So we are passing a flag
|
||||||
|
* ddr_mode to distinguish between LPDDR2 and DDR3.
|
||||||
|
*
|
||||||
|
* @param exynos5_dmc Pointer to struct of DMC registers
|
||||||
|
* @param ddr_mode Type of DDR memory
|
||||||
|
*/
|
||||||
|
void update_reset_dll(struct exynos5_dmc *, enum ddr_mode);
|
||||||
|
|
||||||
void sdelay(unsigned long);
|
void sdelay(unsigned long);
|
||||||
void mem_ctrl_init(void);
|
void mem_ctrl_init(void);
|
||||||
void system_clock_init(void);
|
void system_clock_init(void);
|
||||||
void tzpc_init(void);
|
void tzpc_init(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user