Exynos5: DDR3: Add DDR3 memory setup for Exynos5250 Rev 1.0
authorRajeshwari Shinde <rajeshwari.s@samsung.com>
Tue, 3 Jul 2012 20:02:56 +0000 (20:02 +0000)
committerAlbert ARIBAUD <albert.u.boot@aribaud.net>
Sat, 1 Sep 2012 12:58:23 +0000 (14:58 +0200)
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>
arch/arm/include/asm/arch-exynos/dmc.h
board/samsung/smdk5250/Makefile
board/samsung/smdk5250/dmc_common.c [new file with mode: 0644]
board/samsung/smdk5250/dmc_init.c [deleted file]
board/samsung/smdk5250/dmc_init_ddr3.c [new file with mode: 0644]
board/samsung/smdk5250/setup.h

index bd52d16c9d40c748e545b6ebf6374c5fa0ae9b77..f65c676cc590d301ed144266a206b77bb6ef8214 100644 (file)
@@ -251,5 +251,70 @@ struct exynos5_phy_control {
        unsigned int phy_con41;
        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
index 3675fadd5ae81ef3184aadba521ba90f9033e15f..1474fa8a15a7b3825c356a843f5626a1851765e2 100644 (file)
@@ -27,7 +27,7 @@ LIB   = $(obj)lib$(BOARD).o
 SOBJS  := lowlevel_init.o
 
 COBJS  := clock_init.o
-COBJS  += dmc_init.o
+COBJS  += dmc_common.o dmc_init_ddr3.o
 COBJS  += tzpc_init.o
 COBJS  += smdk5250_spl.o
 
diff --git a/board/samsung/smdk5250/dmc_common.c b/board/samsung/smdk5250/dmc_common.c
new file mode 100644 (file)
index 0000000..109602a
--- /dev/null
@@ -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)
+                       ;
+       }
+}
diff --git a/board/samsung/smdk5250/dmc_init.c b/board/samsung/smdk5250/dmc_init.c
deleted file mode 100644 (file)
index 7881074..0000000
+++ /dev/null
@@ -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);
-}
diff --git a/board/samsung/smdk5250/dmc_init_ddr3.c b/board/samsung/smdk5250/dmc_init_ddr3.c
new file mode 100644 (file)
index 0000000..e050790
--- /dev/null
@@ -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;
+}
index 4bdd0955c8fc55d0b226b4a038fbb8760b8549a0..a15960121ce4deffad6dfc39bd085a5833806b05 100644 (file)
@@ -529,9 +529,66 @@ enum {
        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 mem_ctrl_init(void);
 void system_clock_init(void);
 void tzpc_init(void);
-
 #endif