[U-Boot] [PATCH v3 0/5] Add DDR3 memory support for SMDK5250

SMDK5250 boards are available with different DDR memory variants like LPDDR2, LPDDR3 and DDR3. This patch series adds support for DDR3 memory @ 667Mhz for SMDK5250 board.
Changes in v2: * Replaced some hex values with macro definitions for readability in dmc_init_ddr3.c file. * Moved the clock initialization code from dmc_init_ddr3.c to clock_init.c * Made a separate patch for selecting DDR3 memory by default.
Changes in v1: In this patchset: * Renamed dmc_init.c file to dmc_init_lpddr2.c * Moved functions common to LPDDR2 and DDR3 memory setup from dmc_init_lpddr2.c to dmc_common.c * Replaced register hex values with macro values for clarity.
Hatim Ali (5): SMDK5250: LPDDR2: Renaming the dmc_init.c file to dmc_init_lpddr2.c SMDK5250: LPDDR2: Renaming the PHY_RESET_VAL macro and fixing a minor typo. SMDK5250: Creating a common file to be used by all variants of DDR SMDK5250: DDR3: Add memory initialization code for DDR3. SMDK5250: Selecting DDR3 memory by default.
board/samsung/smdk5250/Makefile | 9 +- board/samsung/smdk5250/clock_init.c | 15 + board/samsung/smdk5250/dmc_common.c | 133 +++++++++ board/samsung/smdk5250/dmc_init_ddr3.c | 297 ++++++++++++++++++++ .../smdk5250/{dmc_init.c => dmc_init_lpddr2.c} | 166 +----------- board/samsung/smdk5250/setup.h | 227 +++++++++++++-- include/configs/smdk5250.h | 6 + 7 files changed, 662 insertions(+), 191 deletions(-) create mode 100644 board/samsung/smdk5250/dmc_common.c create mode 100644 board/samsung/smdk5250/dmc_init_ddr3.c rename board/samsung/smdk5250/{dmc_init.c => dmc_init_lpddr2.c} (66%)

SMDK5250 board support different type of memory chips like DDR3, LPDDR2 and LPDDR3. Since the memory setup sequence for different types of chips are different, therefore, we will have different dmc_init_xxx.c files. Hence, renaming the dmc_init.c file (which is specific to LPDDR2) to dmc_init_lpddr2.c
Signed-off-by: Hatim Ali hatim.rv@samsung.com
diff --git a/board/samsung/smdk5250/Makefile b/board/samsung/smdk5250/Makefile index 226db1f..b18002a 100644 --- a/board/samsung/smdk5250/Makefile +++ b/board/samsung/smdk5250/Makefile @@ -27,7 +27,7 @@ LIB = $(obj)lib$(BOARD).o SOBJS := lowlevel_init.o
COBJS := clock_init.o -COBJS += dmc_init.o +COBJS += dmc_init_lpddr2.o COBJS += tzpc_init.o
ifndef CONFIG_SPL_BUILD diff --git a/board/samsung/smdk5250/dmc_init.c b/board/samsung/smdk5250/dmc_init_lpddr2.c similarity index 100% rename from board/samsung/smdk5250/dmc_init.c rename to board/samsung/smdk5250/dmc_init_lpddr2.c

The patch renames the macro PHY_RESET_VAL to LPDDR3PHY_CTRL_PHY_RESET for clarity and also fixes a minor typo error to make the bit description similar to as described in the Exynos user manual.
Signed-off-by: Hatim Ali hatim.rv@samsung.com
diff --git a/board/samsung/smdk5250/dmc_init_lpddr2.c b/board/samsung/smdk5250/dmc_init_lpddr2.c index 7881074..846469e 100644 --- a/board/samsung/smdk5250/dmc_init_lpddr2.c +++ b/board/samsung/smdk5250/dmc_init_lpddr2.c @@ -53,7 +53,7 @@ static void reset_phy_ctrl(void) { struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
- writel(PHY_RESET_VAL, &clk->lpddr3phy_ctrl); + writel(LPDDR3PHY_CTRL_PHY_RESET_OFF, &clk->lpddr3phy_ctrl); sdelay(0x10000); }
@@ -246,9 +246,9 @@ static void config_rdlvl(struct exynos5_dmc *dmc, /* * Set ctrl_gateadj, ctrl_readadj * ctrl_gateduradj, rdlvl_pass_adj - * rdlvl_rddataPadj + * rdlvl_rddata_adj */ - val = SET_RDLVL_RDDATAPADJ; + val = SET_RDLVL_RDDATA_ADJ; writel(val, &phy0_ctrl->phy_con1); writel(val, &phy1_ctrl->phy_con1);
diff --git a/board/samsung/smdk5250/setup.h b/board/samsung/smdk5250/setup.h index 1276fd3..cf572ac 100644 --- a/board/samsung/smdk5250/setup.h +++ b/board/samsung/smdk5250/setup.h @@ -353,7 +353,8 @@ /* (Memory Interleaving Size = 1 << IV_SIZE) */ #define CONFIG_IV_SIZE 0x07
-#define PHY_RESET_VAL (0 << 0) +#define LPDDR3PHY_CTRL_PHY_RESET (1 << 0) +#define LPDDR3PHY_CTRL_PHY_RESET_OFF (0 << 0)
/*ZQ Configurations */ #define PHY_CON16_RESET_VAL 0x08000304 @@ -397,9 +398,9 @@ #define SET_CTRL_DDR_MODE(x, y) (x = (x & ~(0x3 << 11)) | y << 11)
#define PHY_CON1_RESET_VAL 0x9210100 -#define RDLVL_RDDATAPADJ 0x1 -#define SET_RDLVL_RDDATAPADJ ((PHY_CON1_RESET_VAL & ~(0xFFFF << 0))\ - | RDLVL_RDDATAPADJ << 0) +#define RDLVL_RDDATA_ADJ 0x1 +#define SET_RDLVL_RDDATA_ADJ ((PHY_CON1_RESET_VAL & ~(0xFFFF << 0)) \ + | RDLVL_RDDATA_ADJ << 0)
#define PHY_CON2_RESET_VAL 0x00010004 #define RDLVL_EN (1 << 25)

The patch creates a common file containing functions which will be used by all variants of DDR.
Signed-off-by: Hatim Ali hatim.rv@samsung.com
diff --git a/board/samsung/smdk5250/Makefile b/board/samsung/smdk5250/Makefile index b18002a..3b4aa06 100644 --- a/board/samsung/smdk5250/Makefile +++ b/board/samsung/smdk5250/Makefile @@ -27,6 +27,7 @@ LIB = $(obj)lib$(BOARD).o SOBJS := lowlevel_init.o
COBJS := clock_init.o +COBJS += dmc_common.o COBJS += dmc_init_lpddr2.o COBJS += tzpc_init.o
diff --git a/board/samsung/smdk5250/dmc_common.c b/board/samsung/smdk5250/dmc_common.c new file mode 100644 index 0000000..e940340 --- /dev/null +++ b/board/samsung/smdk5250/dmc_common.c @@ -0,0 +1,133 @@ +/* + * 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 "setup.h" + +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); +} + +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); +} + +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++) { + SET_CMD_CHIP(mask, chip); + + /* Sending NOP command */ + val = DIRECT_CMD_NOP | mask; + writel(val, &dmc->directcmd); + sdelay(0x10000); + + /* Sending EMRS/MRS commands */ + val = DIRECT_CMD_MRS1 | mask; + writel(val, &dmc->directcmd); + sdelay(0x10000); + + val = DIRECT_CMD_MRS2 | mask; + writel(val, &dmc->directcmd); + sdelay(0x10000); + + val = DIRECT_CMD_MRS3 | mask; + writel(val, &dmc->directcmd); + sdelay(0x10000); + + val = DIRECT_CMD_MRS4 | mask; + writel(val, &dmc->directcmd); + sdelay(0x10000); + } + } +} + +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); + } + } +} + +void config_memory(struct exynos5_dmc *dmc) +{ + writel(DMC_MEMCONFIG0_VAL, &dmc->memconfig0); + writel(DMC_MEMCONFIG1_VAL, &dmc->memconfig1); + writel(DMC_MEMBASECONFIG0_VAL, &dmc->membaseconfig0); + writel(DMC_MEMBASECONFIG1_VAL, &dmc->membaseconfig1); +} diff --git a/board/samsung/smdk5250/dmc_init_lpddr2.c b/board/samsung/smdk5250/dmc_init_lpddr2.c index 846469e..9b07f21 100644 --- a/board/samsung/smdk5250/dmc_init_lpddr2.c +++ b/board/samsung/smdk5250/dmc_init_lpddr2.c @@ -1,5 +1,5 @@ /* - * Memory setup for SMDK5250 board based on EXYNOS5 + * LPDDR2 mem setup file for SMDK5250 board based on EXYNOS5 * * Copyright (C) 2012 Samsung Electronics * @@ -30,24 +30,8 @@ #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 *); +/* MCLK_CDREX: 533Mhz */ +/* Memory Type: LPDDR2 */
static void reset_phy_ctrl(void) { @@ -57,109 +41,6 @@ static void reset_phy_ctrl(void) 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; @@ -305,41 +186,6 @@ static void config_rdlvl(struct exynos5_dmc *dmc, } #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; diff --git a/board/samsung/smdk5250/setup.h b/board/samsung/smdk5250/setup.h index cf572ac..c061440 100644 --- a/board/samsung/smdk5250/setup.h +++ b/board/samsung/smdk5250/setup.h @@ -28,6 +28,7 @@ #include <config.h> #include <version.h> #include <asm/arch/cpu.h> +#include <asm/arch/dmc.h>
/* GPIO Offsets for UART: GPIO Contol Register */ #define EXYNOS5_GPIO_A0_CON_OFFSET 0x0 @@ -448,5 +449,10 @@ void sdelay(unsigned long); void mem_ctrl_init(void); void system_clock_init(void); void tzpc_init(void); +void config_zq(struct exynos5_phy_control *, struct exynos5_phy_control *); +void update_reset_dll(struct exynos5_dmc *); +void config_mrs(struct exynos5_dmc *); +void config_prech(struct exynos5_dmc *); +void config_memory(struct exynos5_dmc *);
#endif

The patch adds memory initialization sequence for DDR3 @667Mhz.
Signed-off-by: Hatim Ali hatim.rv@samsung.com
diff --git a/board/samsung/smdk5250/Makefile b/board/samsung/smdk5250/Makefile index 3b4aa06..291fcc6 100644 --- a/board/samsung/smdk5250/Makefile +++ b/board/samsung/smdk5250/Makefile @@ -28,7 +28,13 @@ SOBJS := lowlevel_init.o
COBJS := clock_init.o COBJS += dmc_common.o +ifdef CONFIG_DDR3 +COBJS += dmc_init_ddr3.o +else +ifdef CONFIG_LPDDR2 COBJS += dmc_init_lpddr2.o +endif +endif COBJS += tzpc_init.o
ifndef CONFIG_SPL_BUILD diff --git a/board/samsung/smdk5250/clock_init.c b/board/samsung/smdk5250/clock_init.c index 305842d..b6d3214 100644 --- a/board/samsung/smdk5250/clock_init.c +++ b/board/samsung/smdk5250/clock_init.c @@ -200,3 +200,18 @@ void system_clock_init() */ writel(CLK_SRC_TOP2_VAL, &clk->src_top2); } + +void mem_clk_setup(void) +{ + struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE; + + writel(0x0, &clk->src_cdrex); + writel(CLK_DIV_CDREX_VAL, &clk->div_cdrex); + + writel(MPLL_CON1_VAL, &clk->mpll_con1); + writel(MPLL_CON0_VAL, &clk->mpll_con0); + writel(BPLL_CON1_VAL, &clk->bpll_con1); + writel(BPLL_CON0_VAL, &clk->bpll_con0); + + writel(CLK_SRC_CDREX_VAL, &clk->src_cdrex); +} diff --git a/board/samsung/smdk5250/dmc_init_ddr3.c b/board/samsung/smdk5250/dmc_init_ddr3.c new file mode 100644 index 0000000..8aa3e26 --- /dev/null +++ b/board/samsung/smdk5250/dmc_init_ddr3.c @@ -0,0 +1,297 @@ +/* + * 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/dmc.h> +#include <asm/arch/clock.h> +#include <asm/arch/cpu.h> +#include "setup.h" + +/* + * APLL : 1GHz + * MCLK_CDREX : 667Mhz + * Memory Type : DDR3 + */ + +static void reset_phy_ctrl(void) +{ + struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE; + + writel(LPDDR3PHY_CTRL_PHY_RESET_OFF, &clk->lpddr3phy_ctrl); + sdelay(10000); /* approx 200us */ + writel(LPDDR3PHY_CTRL_PHY_RESET, &clk->lpddr3phy_ctrl); +} + +/* Sending ZQINIT command */ +static void config_zqinit(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); + val = DIRECT_CMD_ZQINIT | mask; + writel(val, &dmc->directcmd); + } + } +} + +static void config_ctrl_dll_on(unsigned int state, + struct exynos5_phy_control *phy0_ctrl, + struct exynos5_phy_control *phy1_ctrl) +{ + unsigned int val, tmp; + + val = readl(&phy0_ctrl->phy_con13); + + /* Reading ctrl_lock_value[8:2] */ + val &= (NR_DELAY_CELL_COARSE_LOCK_MASK << + NR_DELAY_CELL_COARSE_LOCK_OFFSET); + + /* Aligning 'val' to match 'ctrl_force' offset of PHY_CON12 */ + val >>= CTRL_CLOCK_OFFSET; + + /* Setting the PHY_CON12 register */ + tmp = PHY_CON12_RESET_VAL; + CONFIG_CTRL_DLL_ON(tmp, state); + + /* Writing 'val' in the 'ctrl_force' offset of PHY_CON12 */ + tmp |= val; + writel(tmp, &phy0_ctrl->phy_con12); + + val = readl(&phy1_ctrl->phy_con13); + + /* Reading ctrl_lock_value[8:2] */ + val &= (NR_DELAY_CELL_COARSE_LOCK_MASK << + NR_DELAY_CELL_COARSE_LOCK_OFFSET); + + /* Aligning 'val' to match 'ctrl_force' offset of PHY_CON12 */ + val >>= CTRL_CLOCK_OFFSET; + + /* Setting the PHY_CON12 register */ + tmp = PHY_CON12_RESET_VAL; + CONFIG_CTRL_DLL_ON(tmp, state); + + /* Writing 'val' in the 'ctrl_force' offset of PHY_CON12 */ + tmp |= val; + writel(tmp, &phy1_ctrl->phy_con12); +} + +void mem_ctrl_init() +{ + struct exynos5_phy_control *phy0_ctrl, *phy1_ctrl; + struct exynos5_dmc *dmc; + unsigned int 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_ctrl(); + + mem_clk_setup(); + + /* Setting Operation Mode as DDR3 and enabling byte_rdlvl */ + val = PHY_CON0_RESET_VAL; + SET_CTRL_DDR_MODE(val, DDR_MODE_DDR3); + val |= BYTE_RDLVL_EN; + writel(val, &phy0_ctrl->phy_con0); + writel(val, &phy1_ctrl->phy_con0); + + /* Enable Read Leveling */ + writel(SET_RDLVL_RDDATA_ADJ, &phy0_ctrl->phy_con1); + writel(SET_RDLVL_RDDATA_ADJ, &phy1_ctrl->phy_con1); + + /* DQS, DQ: Signal */ + val = CTRL_PULLD_DQ | CTRL_PULLD_DQS; + writel(val, &phy0_ctrl->phy_con14); + writel(val, &phy1_ctrl->phy_con14); + + /* Set Read Latency and Burst Length for PHY0 and PHY1 */ + writel(PHY_CON42_VAL, &phy0_ctrl->phy_con42); + writel(PHY_CON42_VAL, &phy1_ctrl->phy_con42); + + /* ZQ Calibration */ + config_zq(phy0_ctrl, phy1_ctrl); + + /* + * Set DMC Concontrol + * dfi_init_start = 1 + * rd_fetch = 0x3 + * empty = 0 + */ + val = DMC_CONCONTROL_RESET_VAL; + SET_RD_FETCH(val); + val |= DFI_INIT_START; + val &= ~EMPTY; + writel(val, &dmc->concontrol); + + /* + * Dynamic Clock: Always Running + * Memory Burst length: 8 + * Number of chips: 1 + * Memory Bus width: 32 bit + * Memory Type: DDR3 + * Additional Latancy for PLL: 0 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 Refresh 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 offsets */ + writel(DDR3_PHY0_DQS, &phy0_ctrl->phy_con4); + writel(DDR3_PHY1_DQS, &phy1_ctrl->phy_con4); + + /* Set DQS offsets */ + writel(DDR3_PHY0_DQ, &phy0_ctrl->phy_con6); + writel(DDR3_PHY1_DQ, &phy1_ctrl->phy_con6); + + /* Set Debug offsets */ + writel(RESET_DEBUG_OFFSET_VAL, &phy0_ctrl->phy_con10); + writel(RESET_DEBUG_OFFSET_VAL, &phy1_ctrl->phy_con10); + + config_ctrl_dll_on(RESET, phy0_ctrl, phy1_ctrl); + + sdelay(50); /* approx 10 PCLK cycle */ + + update_reset_dll(dmc); + + config_mrs(dmc); + config_zqinit(dmc); + + sdelay(50); /* approx 10 PCLK cycle */ + + /* Reset DLL Locking */ + val = PHY_CON12_RESET_VAL; + CONFIG_CTRL_START(val, RESET); + writel(val, &phy0_ctrl->phy_con12); + writel(val, &phy1_ctrl->phy_con12); + + /* Reset DLL Locking */ + val = PHY_CON12_RESET_VAL; + CONFIG_CTRL_START(val, SET); + writel(val, &phy0_ctrl->phy_con12); + writel(val, &phy1_ctrl->phy_con12); + + sdelay(50); /* approx 10 PCLK cycle */ + + /* + * Looping till SEC SDRAM PHY initialization completes + * for both channel-0 and channel-1 + */ + do { + val = readl(&dmc->phystatus); + val &= (DFI_INIT_COMPLETE_CHO | DFI_INIT_COMPLETE_CH1); + } while (val == 0); + + /* + * Set DMC Concontrol + * rd_fetch = 0x3 + * empty = 0 + * Basically here we are stopping dfi_init_start done above. + */ + val = DMC_CONCONTROL_RESET_VAL; + SET_RD_FETCH(val); + val &= ~EMPTY; + writel(val, &dmc->concontrol); + + update_reset_dll(dmc); + + writel(SET_RDLVL_RDDATA_ADJ, &phy0_ctrl->phy_con1); + writel(SET_RDLVL_RDDATA_ADJ, &phy1_ctrl->phy_con1); + + /* Enable Read Leveling */ + val = PHY_CON2_RESET_VAL | RDLVL_EN; + writel(val, &phy0_ctrl->phy_con2); + writel(val, &phy1_ctrl->phy_con2); + + /* Enable data eye training */ + val = RDLVL_CONFIG_RESET_VAL | CTRL_RDLVL_DATA_EN; + writel(val, &dmc->rdlvl_config); + + /* + * Looping till Read level completion happens + * for both channel-0 and channel-1 + */ + do { + val = readl(&dmc->phystatus); + val &= (RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1); + } while (val == 0); + + /* Disable data eye training */ + val = RDLVL_CONFIG_RESET_VAL & ~CTRL_RDLVL_DATA_EN; + writel(val, &dmc->rdlvl_config); + + config_ctrl_dll_on(SET, phy0_ctrl, phy1_ctrl); + + update_reset_dll(dmc); + + config_prech(dmc); + + /* + * Dynamic Clock: Always Running + * Memory Burst length: 8 + * Number of chips: 1 + * Memory Bus width: 32 bit + * Memory Type: DDR3 + * Additional Latancy for PLL: 0 Cycle + */ + writel(DMC_MEMCONTROL_VAL, &dmc->memcontrol); + + /* + * Set DMC Concontrol + * rd_fetch = 0x3 + * empty = 0 + * Auto refresh counter enable + */ + val = DMC_CONCONTROL_RESET_VAL; + SET_RD_FETCH(val); + val &= ~EMPTY; + val |= AREF_EN; + writel(val, &dmc->concontrol); +} diff --git a/board/samsung/smdk5250/setup.h b/board/samsung/smdk5250/setup.h index c061440..6260843 100644 --- a/board/samsung/smdk5250/setup.h +++ b/board/samsung/smdk5250/setup.h @@ -1,5 +1,5 @@ /* - * Machine Specific Values for SMDK5250 board based on S5PC520 + * Machine Specific Values for SMDK5250 board based on Exynos5 * * Copyright (C) 2012 Samsung Electronics * @@ -114,8 +114,13 @@ #define VPLL_CON1_VAL 0x00000000 #define VPLL_CON2_VAL 0x00000080
+#ifdef CONFIG_LPDDR2 #define BPLL_MDIV 0x215 #define BPLL_PDIV 0xC +#elif defined CONFIG_DDR3 +#define BPLL_MDIV 0x185 +#define BPLL_PDIV 0x7 +#endif #define BPLL_SDIV 0x1
#define BPLL_CON1_VAL 0x00203800 @@ -155,20 +160,26 @@ #define MCLK_CDREX_RATIO 0x0 #define ACLK_C2C_200_RATIO 0x1 #define C2C_CLK_400_RATIO 0x1 +#ifdef CONFIG_DDR3 +#define PCLK_CDREX_RATIO 0x4 +#else #define PCLK_CDREX_RATIO 0x3 +#endif #define ACLK_CDREX_RATIO 0x1 -#define CLK_DIV_CDREX_VAL ((MCLK_DPHY_RATIO << 20) \ - | (MCLK_CDREX_RATIO << 16) \ +#define CLK_DIV_CDREX_VAL ((MCLK_CDREX2_RATIO << 28) \ + | (ACLK_EFCON_RATIO << 24) \ + | (MCLK_DPHY_RATIO << 20) \ + | (MCLK_CDREX_RATIO << 16) \ | (ACLK_C2C_200_RATIO << 12) \ - | (C2C_CLK_400_RATIO << 8) \ - | (PCLK_CDREX_RATIO << 4) \ + | (C2C_CLK_400_RATIO << 8) \ + | (PCLK_CDREX_RATIO << 4) \ | (ACLK_CDREX_RATIO))
#define MCLK_EFPHY_RATIO 0x4 #define CLK_DIV_CDREX2_VAL MCLK_EFPHY_RATIO
/* CLK_DIV_ACP */ -#define CLK_DIV_ACP_VAL 0x12 +#define CLK_DIV_ACP_VAL 0x12
/* CLK_SRC_TOP0 */ #define MUX_ACLK_300_GSCL_SEL 0x1 @@ -360,8 +371,13 @@ /*ZQ Configurations */ #define PHY_CON16_RESET_VAL 0x08000304
+#ifdef CONFIG_LPDDR2 #define ZQ_MODE_DDS_VAL (0x5 << 24) #define ZQ_MODE_TERM_VAL (0x5 << 21) +#elif defined CONFIG_DDR3 +#define ZQ_MODE_DDS_VAL (0x7 << 24) +#define ZQ_MODE_TERM_VAL (0x2 << 21) +#endif #define SET_ZQ_MODE_DDS_VAL(x) (x = (x & ~(0x7 << 24)) | ZQ_MODE_DDS_VAL) #define SET_ZQ_MODE_TERM_VAL(x) (x = (x & ~(0x7 << 21)) | ZQ_MODE_TERM_VAL)
@@ -377,74 +393,218 @@ #define SET_CMD_CHIP(x, y) (x = (x & ~(1 << 20)) | y << 20)
/* Diret Command */ -#define DIRECT_CMD_NOP 0x07000000 +#define DIRECT_CMD_NOP 0x07000000 +#define DIRECT_CMD_PALL 0x01000000 +#define DIRECT_CMD_ZQINIT 0x0A000000 +#ifdef CONFIG_LPDDR2 #define DIRECT_CMD_MRS1 0x00071C00 #define DIRECT_CMD_MRS2 0x00010BFC #define DIRECT_CMD_MRS3 0x00000708 #define DIRECT_CMD_MRS4 0x00000818 -#define DIRECT_CMD_PALL 0x01000000 +#elif defined CONFIG_DDR3 +#define DIRECT_CMD_MRS1 0x00020010 +#define DIRECT_CMD_MRS2 0x00030000 +#define DIRECT_CMD_MRS3 0x00010042 +#define DIRECT_CMD_MRS4 0x00000B50 +#endif
-/* DLL Resync */ -#define FP_RSYNC (1 << 3) +/* DMC PHY Control0 register */ +#define PHY_CONTROL0_RESET_VAL 0x0 +#define MEM_TERM_EN (1 << 31) /* Termination enable for memory */ +#define PHY_TERM_EN (1 << 30) /* Termination enable for PHY */ +#define CTRL_SHGATE (1 << 29) /* Duration of DQS gating signal */ +#define FP_RSYNC (1 << 3) /* Force DLL resyncronization */
+/* MDLL control */ +#define PHY_CON12_RESET_VAL 0x10100070 #define CONFIG_CTRL_DLL_ON(x, y) (x = (x & ~(1 << 5)) | y << 5) #define CONFIG_CTRL_START(x, y) (x = (x & ~(1 << 6)) | y << 6) #define SET_CTRL_FORCE_VAL(x, y) (x = (x & ~(0x7F << 8)) | y << 8)
-/* RDLVL */ -#define PHY_CON0_RESET_VAL 0x17023240 +#define NR_DELAY_CELL_COARSE_LOCK_OFFSET 10 +#define NR_DELAY_CELL_COARSE_LOCK_MASK 0x7F +#define CTRL_CLOCK_OFFSET 2 + +/* PHY Control */ +#define PHY_CON0_RESET_VAL 0x17020A40 +#define DDR_MODE_DDR3 0x1 #define DDR_MODE_LPDDR2 0x2 +#define DDR_MODE_LPDDR3 0x3 #define BYTE_RDLVL_EN (1 << 13) #define CTRL_ATGATE (1 << 6) -#define SET_CTRL_DDR_MODE(x, y) (x = (x & ~(0x3 << 11)) | y << 11) +#define SET_CTRL_DDR_MODE(x, y) (x = (x & ~(0x3 << 11)) | y << 11) +#define SET_T_RDDATA_MARGIN(x, y) (x = (x & ~(0x7 << 17)) | y << 17)
#define PHY_CON1_RESET_VAL 0x9210100 +#ifdef CONFIG_DDR3 +#define RDLVL_RDDATA_ADJ 0xFF00 +#elif defined CONFIG_LPDDR2 #define RDLVL_RDDATA_ADJ 0x1 +#endif #define SET_RDLVL_RDDATA_ADJ ((PHY_CON1_RESET_VAL & ~(0xFFFF << 0)) \ | RDLVL_RDDATA_ADJ << 0)
+#define DDR3_ADDR 0x0208 + #define PHY_CON2_RESET_VAL 0x00010004 #define RDLVL_EN (1 << 25) #define RDDSKEW_CLEAR (1 << 13)
+#define RDLVL_CONFIG_RESET_VAL 0x0 #define CTRL_RDLVL_DATA_EN (1 << 1) #define LPDDR2_ADDR 0x00000208
-#define DMC_MEMCONFIG0_VAL 0x00001323 -#define DMC_MEMCONFIG1_VAL 0x00001323 -#define DMC_MEMBASECONFIG0_VAL 0x00400780 -#define DMC_MEMBASECONFIG1_VAL 0x00800780 -#define DMC_MEMCONTROL_VAL 0x00212500 +/* MEMCONTROL register bit fields */ +#define DMC_MEMCONTROL_CLK_STOP_DISABLE (0 << 0) +#define DMC_MEMCONTROL_DPWRDN_DISABLE (0 << 1) +#define DMC_MEMCONTROL_DPWRDN_ACTIVE_PRECHARGE (0 << 2) +#define DMC_MEMCONTROL_TP_DISABLE (0 << 4) +#define DMC_MEMCONTROL_DSREF_DISABLE (0 << 5) +#define DMC_MEMCONTROL_ADD_LAT_PALL_CYCLE(x) (x << 6) + +#define DMC_MEMCONTROL_MEM_TYPE_LPDDR3 (7 << 8) +#define DMC_MEMCONTROL_MEM_TYPE_DDR3 (6 << 8) +#define DMC_MEMCONTROL_MEM_TYPE_LPDDR2 (5 << 8) + +#define DMC_MEMCONTROL_MEM_WIDTH_32BIT (2 << 12) + +#define DMC_MEMCONTROL_NUM_CHIP_1 (0 << 16) +#define DMC_MEMCONTROL_NUM_CHIP_2 (1 << 16) + +#define DMC_MEMCONTROL_BL_8 (3 << 20) +#define DMC_MEMCONTROL_BL_4 (2 << 20) + +#define DMC_MEMCONTROL_PZQ_DISABLE (0 << 24) + +#define DMC_MEMCONTROL_MRR_BYTE_7_0 (0 << 25) +#define DMC_MEMCONTROL_MRR_BYTE_15_8 (1 << 25) +#define DMC_MEMCONTROL_MRR_BYTE_23_16 (2 << 25) +#define DMC_MEMCONTROL_MRR_BYTE_31_24 (3 << 25) + +/* MEMCONFIG0 register bit fields */ +#define DMC_MEMCONFIGx_CHIP_MAP_INTERLEAVED (1 << 12) +#define DMC_MEMCONFIGx_CHIP_COL_10 (3 << 8) +#define DMC_MEMCONFIGx_CHIP_ROW_14 (2 << 4) +#define DMC_MEMCONFIGx_CHIP_ROW_15 (3 << 4) +#define DMC_MEMCONFIGx_CHIP_BANK_8 (3 << 0) + + +#define DMC_MEMBASECONFIGx_CHIP_BASE(x) (x << 16) +#define DMC_MEMBASECONFIGx_CHIP_MASK(x) (x << 0) +#define DMC_MEMBASECONFIG_VAL(x) ( \ + DMC_MEMBASECONFIGx_CHIP_BASE(x) | \ + DMC_MEMBASECONFIGx_CHIP_MASK(0x780) \ +) + +#define DMC_MEMBASECONFIG0_VAL DMC_MEMBASECONFIG_VAL(0x40) +#define DMC_MEMBASECONFIG1_VAL DMC_MEMBASECONFIG_VAL(0x80) + +#ifdef CONFIG_LPDDR2 +#define DMC_MEMCONTROL_VAL ( \ + DMC_MEMCONTROL_CLK_STOP_DISABLE | \ + DMC_MEMCONTROL_DPWRDN_DISABLE | \ + DMC_MEMCONTROL_DPWRDN_ACTIVE_PRECHARGE | \ + DMC_MEMCONTROL_TP_DISABLE | \ + DMC_MEMCONTROL_DSREF_DISABLE | \ + DMC_MEMCONTROL_ADD_LAT_PALL_CYCLE(0) | \ + DMC_MEMCONTROL_MEM_TYPE_LPDDR2 | \ + DMC_MEMCONTROL_MEM_WIDTH_32BIT | \ + DMC_MEMCONTROL_NUM_CHIP_2 | \ + DMC_MEMCONTROL_BL_4 | \ + DMC_MEMCONTROL_PZQ_DISABLE | \ + DMC_MEMCONTROL_MRR_BYTE_7_0 \ +) +#define DMC_MEMCONFIG_VAL ( \ + DMC_MEMCONFIGx_CHIP_MAP_INTERLEAVED | DMC_MEMCONFIGx_CHIP_COL_10 | \ + DMC_MEMCONFIGx_CHIP_ROW_14 | DMC_MEMCONFIGx_CHIP_BANK_8) +#define DMC_MEMCONFIG1_VAL DMC_MEMCONFIG_VAL +#define DMC_MEMCONFIG0_VAL DMC_MEMCONFIG_VAL + +#elif defined CONFIG_DDR3 +#define DMC_MEMCONTROL_VAL ( \ + DMC_MEMCONTROL_CLK_STOP_DISABLE | \ + DMC_MEMCONTROL_DPWRDN_DISABLE | \ + DMC_MEMCONTROL_DPWRDN_ACTIVE_PRECHARGE | \ + DMC_MEMCONTROL_TP_DISABLE | \ + DMC_MEMCONTROL_DSREF_DISABLE | \ + DMC_MEMCONTROL_ADD_LAT_PALL_CYCLE(0) | \ + DMC_MEMCONTROL_MEM_TYPE_DDR3 | \ + DMC_MEMCONTROL_MEM_WIDTH_32BIT | \ + DMC_MEMCONTROL_NUM_CHIP_1 | \ + DMC_MEMCONTROL_BL_8 | \ + DMC_MEMCONTROL_PZQ_DISABLE | \ + DMC_MEMCONTROL_MRR_BYTE_7_0 \ +) +#define DMC_MEMCONFIG_VAL ( \ + DMC_MEMCONFIGx_CHIP_MAP_INTERLEAVED | DMC_MEMCONFIGx_CHIP_COL_10 | \ + DMC_MEMCONFIGx_CHIP_ROW_15 | DMC_MEMCONFIGx_CHIP_BANK_8) +#define DMC_MEMCONFIG1_VAL DMC_MEMCONFIG_VAL +#define DMC_MEMCONFIG0_VAL DMC_MEMCONFIG_VAL +#endif + #define DMC_PRECHCONFIG_VAL 0xFF000000 #define DMC_PWRDNCONFIG_VAL 0xFFFF00FF +#ifdef CONFIG_LPDDR2 #define DMC_TIMINGREF_VAL 0x0000005D #define DMC_TIMINGROW_VAL 0x2336544C #define DMC_TIMINGDATA_VAL 0x24202408 #define DMC_TIMINGPOWER_VAL 0x38260235 +#elif defined CONFIG_DDR3 +#define DMC_TIMINGREF_VAL 0x000000BB +#define DMC_TIMINGROW_VAL 0x7645644d +#define DMC_TIMINGDATA_VAL 0x45414709 +#define DMC_TIMINGPOWER_VAL 0x3a000a3c +#endif
+#ifdef CONFIG_LPDDR2 #define CTRL_BSTLEN 0x04 #define CTRL_RDLAT 0x08 +#elif defined CONFIG_DDR3 +#define CTRL_BSTLEN 0x08 +#define CTRL_RDLAT 0x09 +#endif #define PHY_CON42_VAL (CTRL_BSTLEN << 8 | CTRL_RDLAT << 0)
/* DQS, DQ, DEBUG offsets */ -#define SET_DQS_OFFSET_VAL 0x7F7F7F7F -#define SET_DQ_OFFSET_VAL 0x7F7F7F7F -#define SET_DEBUG_OFFSET_VAL 0x7F +#ifdef CONFIG_DDR3 +#define DDR3_PHY0_DQS 0x08080808 +#define DDR3_PHY1_DQS 0x08080808 +#define DDR3_PHY0_DQ 0x08080808 +#define DDR3_PHY1_DQ 0x00080808 +#endif + +#define SET_DQS_OFFSET_VAL 0x7F7F7F7F +#define SET_DQ_OFFSET_VAL 0x7F7F7F7F +#define SET_DEBUG_OFFSET_VAL 0x7F
-#define RESET_DQS_OFFSET_VAL 0x08080808 -#define RESET_DQ_OFFSET_VAL 0x08080808 -#define RESET_DEBUG_OFFSET_VAL 0x8 +#define RESET_DQS_OFFSET_VAL 0x08080808 +#define RESET_DQ_OFFSET_VAL 0x08080808 +#define RESET_DEBUG_OFFSET_VAL 0x8
#define CTRL_PULLD_DQ (0x0F << 8) #define CTRL_PULLD_DQS (0x0F << 0)
+#define DMC_CONCONTROL_RESET_VAL 0x0FFF1100 +#ifdef CONFIG_LPDDR2 +#define RD_FETCH 0x3 +#elif defined CONFIG_DDR3 +#define RD_FETCH 0x2 +#endif +#define SET_RD_FETCH(x) (x = (x & ~(0x7 << 12)) | RD_FETCH << 12) #define DFI_INIT_START (1 << 28) +#define EMPTY (1 << 8) +#define AREF_EN (1 << 5) + +#define DFI_INIT_COMPLETE_CHO (1 << 2) +#define DFI_INIT_COMPLETE_CH1 (1 << 3) + +#define RDLVL_COMPLETE_CHO (1 << 14) +#define RDLVL_COMPLETE_CH1 (1 << 15)
#define CLK_STOP_EN (1 << 0) #define DPWRDN_EN (1 << 1) #define DSREF_EN (1 << 5)
-#define AREF_EN (1 << 5) void sdelay(unsigned long); void mem_ctrl_init(void); void system_clock_init(void); @@ -454,5 +614,5 @@ void update_reset_dll(struct exynos5_dmc *); void config_mrs(struct exynos5_dmc *); void config_prech(struct exynos5_dmc *); void config_memory(struct exynos5_dmc *); - +void mem_clk_setup(void); #endif

The patch selects DDR3 memory for SMDK5250 by default.
Signed-off-by: Hatim Ali hatim.rv@samsung.com
diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h index 9659f9e..cc24be6 100644 --- a/include/configs/smdk5250.h +++ b/include/configs/smdk5250.h @@ -37,6 +37,12 @@ #define CONFIG_DISPLAY_CPUINFO #define CONFIG_DISPLAY_BOARDINFO
+/* Choose DDR Type below: + * Uncomment the type of DDR present on your board + */ +#define CONFIG_DDR3 +/* #define CONFIG_LPDDR2 */ + /* Keep L2 Cache Disabled */ #define CONFIG_SYS_DCACHE_OFF
participants (1)
-
Hatim Ali