ARM: AM43xx: EPOS_EVM: Add support for LPDDR2
authorLokesh Vutla <lokeshvutla@ti.com>
Tue, 10 Dec 2013 09:32:22 +0000 (15:02 +0530)
committerTom Rini <trini@ti.com>
Thu, 19 Dec 2013 02:14:44 +0000 (21:14 -0500)
AM4372 EPOS EVM has 1GB LPDDR2(Part no: MT42L256M32D2LG-25 WT:A)
Adding LPDDR2 init sequence and register details for the same.
Below is the brief description of LPDDR2 init sequence:
-> Configure VTP
-> Configure DDR IO settings
-> Disable initialization and refreshes until EMIF registers are programmed.
-> Program Timing registers
-> Program PHY control and Temp alert and ZQ config registers.
-> Enable initialization and refreshes and configure SDRAM CONFIG register
-> Wait till initialization is complete and the configure MR registers.

Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
arch/arm/cpu/armv7/am33xx/ddr.c
arch/arm/cpu/armv7/am33xx/emif4.c
arch/arm/include/asm/arch-am33xx/clocks_am33xx.h
arch/arm/include/asm/arch-am33xx/cpu.h
arch/arm/include/asm/arch-am33xx/ddr_defs.h
arch/arm/include/asm/arch-am33xx/hardware_am43xx.h
arch/arm/include/asm/emif.h
board/ti/am43xx/board.c

index 255f333b692bb1e0ac66b8ae5e8b3965264acc84..1abbb07c961987eddded78dbf1dd44885a633e1f 100644 (file)
@@ -36,6 +36,71 @@ static struct ddr_data_regs *ddr_data_reg[2] = {
 static struct ddr_cmdtctrl *ioctrl_reg = {
                        (struct ddr_cmdtctrl *)DDR_CONTROL_BASE_ADDR};
 
+static inline u32 get_mr(int nr, u32 cs, u32 mr_addr)
+{
+       u32 mr;
+
+       mr_addr |= cs << EMIF_REG_CS_SHIFT;
+       writel(mr_addr, &emif_reg[nr]->emif_lpddr2_mode_reg_cfg);
+
+       mr = readl(&emif_reg[nr]->emif_lpddr2_mode_reg_data);
+       debug("get_mr: EMIF1 cs %d mr %08x val 0x%x\n", cs, mr_addr, mr);
+       if (((mr & 0x0000ff00) >>  8) == (mr & 0xff) &&
+           ((mr & 0x00ff0000) >> 16) == (mr & 0xff) &&
+           ((mr & 0xff000000) >> 24) == (mr & 0xff))
+               return mr & 0xff;
+       else
+               return mr;
+}
+
+static inline void set_mr(int nr, u32 cs, u32 mr_addr, u32 mr_val)
+{
+       mr_addr |= cs << EMIF_REG_CS_SHIFT;
+       writel(mr_addr, &emif_reg[nr]->emif_lpddr2_mode_reg_cfg);
+       writel(mr_val, &emif_reg[nr]->emif_lpddr2_mode_reg_data);
+}
+
+static void configure_mr(int nr, u32 cs)
+{
+       u32 mr_addr;
+
+       while (get_mr(nr, cs, LPDDR2_MR0) & LPDDR2_MR0_DAI_MASK)
+               ;
+       set_mr(nr, cs, LPDDR2_MR10, 0x56);
+
+       set_mr(nr, cs, LPDDR2_MR1, 0x43);
+       set_mr(nr, cs, LPDDR2_MR2, 0x2);
+
+       mr_addr = LPDDR2_MR2 | EMIF_REG_REFRESH_EN_MASK;
+       set_mr(nr, cs, mr_addr, 0x2);
+}
+
+/*
+ * Configure EMIF4D5 registers and MR registers
+ */
+void config_sdram_emif4d5(const struct emif_regs *regs, int nr)
+{
+       writel(0x0, &emif_reg[nr]->emif_pwr_mgmt_ctrl);
+       writel(0x0, &emif_reg[nr]->emif_pwr_mgmt_ctrl_shdw);
+       writel(0x1, &emif_reg[nr]->emif_iodft_tlgc);
+       writel(regs->zq_config, &emif_reg[nr]->emif_zq_config);
+
+       writel(regs->temp_alert_config, &emif_reg[nr]->emif_temp_alert_config);
+       writel(regs->emif_rd_wr_lvl_rmp_win,
+              &emif_reg[nr]->emif_rd_wr_lvl_rmp_win);
+       writel(regs->emif_rd_wr_lvl_rmp_ctl,
+              &emif_reg[nr]->emif_rd_wr_lvl_rmp_ctl);
+       writel(regs->emif_rd_wr_lvl_ctl, &emif_reg[nr]->emif_rd_wr_lvl_ctl);
+       writel(regs->emif_rd_wr_exec_thresh,
+              &emif_reg[nr]->emif_rd_wr_exec_thresh);
+
+       writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl);
+       writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config);
+
+       configure_mr(nr, 0);
+       configure_mr(nr, 1);
+}
+
 /**
  * Configure SDRAM
  */
@@ -72,15 +137,67 @@ void set_sdram_timings(const struct emif_regs *regs, int nr)
        writel(regs->sdram_tim3, &emif_reg[nr]->emif_sdram_tim_3_shdw);
 }
 
+void __weak emif_get_ext_phy_ctrl_const_regs(const u32 **regs, u32 *size)
+{
+}
+
+/*
+ * Configure EXT PHY registers
+ */
+static void ext_phy_settings(const struct emif_regs *regs, int nr)
+{
+       u32 *ext_phy_ctrl_base = 0;
+       u32 *emif_ext_phy_ctrl_base = 0;
+       const u32 *ext_phy_ctrl_const_regs;
+       u32 i = 0;
+       u32 size;
+
+       ext_phy_ctrl_base = (u32 *)&(regs->emif_ddr_ext_phy_ctrl_1);
+       emif_ext_phy_ctrl_base =
+                       (u32 *)&(emif_reg[nr]->emif_ddr_ext_phy_ctrl_1);
+
+       /* Configure external phy control timing registers */
+       for (i = 0; i < EMIF_EXT_PHY_CTRL_TIMING_REG; i++) {
+               writel(*ext_phy_ctrl_base, emif_ext_phy_ctrl_base++);
+               /* Update shadow registers */
+               writel(*ext_phy_ctrl_base++, emif_ext_phy_ctrl_base++);
+       }
+
+       /*
+        * external phy 6-24 registers do not change with
+        * ddr frequency
+        */
+       emif_get_ext_phy_ctrl_const_regs(&ext_phy_ctrl_const_regs, &size);
+
+       if (!size)
+               return;
+
+       for (i = 0; i < size; i++) {
+               writel(ext_phy_ctrl_const_regs[i], emif_ext_phy_ctrl_base++);
+               /* Update shadow registers */
+               writel(ext_phy_ctrl_const_regs[i], emif_ext_phy_ctrl_base++);
+       }
+}
+
 /**
  * Configure DDR PHY
  */
 void config_ddr_phy(const struct emif_regs *regs, int nr)
 {
+       /*
+        * disable initialization and refreshes for now until we
+        * finish programming EMIF regs.
+        */
+       setbits_le32(&emif_reg[nr]->emif_sdram_ref_ctrl,
+                    EMIF_REG_INITREF_DIS_MASK);
+
        writel(regs->emif_ddr_phy_ctlr_1,
                &emif_reg[nr]->emif_ddr_phy_ctrl_1);
        writel(regs->emif_ddr_phy_ctlr_1,
                &emif_reg[nr]->emif_ddr_phy_ctrl_1_shdw);
+
+       if (get_emif_rev((u32)emif_reg[nr]) == EMIF_4D5)
+               ext_phy_settings(regs, nr);
 }
 
 /**
index adda650fe8d2cffce2d49cebf150ee5d614657d5..d28fceb75cf78c118f1487891ca0f8b345a96c16 100644 (file)
@@ -48,6 +48,11 @@ static struct vtp_reg *vtpreg[2] = {
 #ifdef CONFIG_AM33XX
 static struct ddr_ctrl *ddrctrl = (struct ddr_ctrl *)DDR_CTRL_ADDR;
 #endif
+#ifdef CONFIG_AM43XX
+static struct ddr_ctrl *ddrctrl = (struct ddr_ctrl *)DDR_CTRL_ADDR;
+static struct cm_device_inst *cm_device =
+                               (struct cm_device_inst *)CM_DEVICE_INST;
+#endif
 
 #ifdef CONFIG_TI81XX
 void config_dmm(const struct dmm_lisa_map_regs *regs)
@@ -104,9 +109,24 @@ void config_ddr(unsigned int pll, const struct ctrl_ioregs *ioregs,
        /* Set CKE to be controlled by EMIF/DDR PHY */
        writel(DDR_CKE_CTRL_NORMAL, &ddrctrl->ddrckectrl);
 #endif
+#ifdef CONFIG_AM43XX
+       writel(readl(&cm_device->cm_dll_ctrl) & ~0x1, &cm_device->cm_dll_ctrl);
+       while ((readl(&cm_device->cm_dll_ctrl) && CM_DLL_READYST) == 0)
+               ;
+       writel(0x0, &ddrctrl->ddrioctrl);
+
+       config_io_ctrl(ioregs);
+
+       /* Set CKE to be controlled by EMIF/DDR PHY */
+       writel(DDR_CKE_CTRL_NORMAL, &ddrctrl->ddrckectrl);
+#endif
+
        /* Program EMIF instance */
        config_ddr_phy(regs, nr);
        set_sdram_timings(regs, nr);
-       config_sdram(regs, nr);
+       if (get_emif_rev(EMIF1_BASE) == EMIF_4D5)
+               config_sdram_emif4d5(regs, nr);
+       else
+               config_sdram(regs, nr);
 }
 #endif
index 02ed5957e985af5fa879c9c2f048fef54dd6c4e7..4c9352a2ed768f29bcec1ff5678807ccbb396464 100644 (file)
@@ -28,6 +28,9 @@
 #define UART_CLK_RUNNING_MASK  0x1
 #define UART_SMART_IDLE_EN     (0x1 << 0x3)
 
+#define CM_DLL_CTRL_NO_OVERRIDE        0x0
+#define CM_DLL_READYST         0x4
+
 extern void enable_dmm_clocks(void);
 extern const struct dpll_params dpll_core_opp100;
 extern struct dpll_params dpll_mpu_opp100;
index 3ee37dc4e7960a61836ce9bae98523064b2a7bf9..9febfa2719a94273efc8d90911ff38d302ba4535 100644 (file)
@@ -401,6 +401,11 @@ struct cm_perpll {
        unsigned int cpgmac0clkctrl;    /* offset 0xB20 */
 };
 
+struct cm_device_inst {
+       unsigned int cm_clkout1_ctrl;
+       unsigned int cm_dll_ctrl;
+};
+
 struct cm_dpll {
        unsigned int resv1;
        unsigned int clktimer2clk;      /* offset 0x04 */
index 2278358ab200ecc26fc7500e01b11268fe7d43f5..6af4b84e568bca75c8e3c5dee6fb8a524c08ada4 100644 (file)
 #define VTP_CTRL_READY         (0x1 << 5)
 #define VTP_CTRL_ENABLE                (0x1 << 6)
 #define VTP_CTRL_START_EN      (0x1)
+#ifdef CONFIG_AM43XX
+#define DDR_CKE_CTRL_NORMAL    0x3
+#else
 #define DDR_CKE_CTRL_NORMAL    0x1
+#endif
 #define PHY_EN_DYN_PWRDN       (0x1 << 20)
 
 /* Micron MT47H128M16RT-25E */
 #define K4B2G1646EBIH9_PHY_WR_DATA             0x76
 #define K4B2G1646EBIH9_IOCTRL_VALUE            0x18B
 
+#define  LPDDR2_ADDRCTRL_IOCTRL_VALUE   0x294
+#define  LPDDR2_ADDRCTRL_WD0_IOCTRL_VALUE 0x00000000
+#define  LPDDR2_ADDRCTRL_WD1_IOCTRL_VALUE 0x00000000
+#define  LPDDR2_DATA0_IOCTRL_VALUE   0x20000294
+#define  LPDDR2_DATA1_IOCTRL_VALUE   0x20000294
+#define  LPDDR2_DATA2_IOCTRL_VALUE   0x20000294
+#define  LPDDR2_DATA3_IOCTRL_VALUE   0x20000294
+
 /**
  * Configure DMM
  */
@@ -133,6 +145,7 @@ void config_dmm(const struct dmm_lisa_map_regs *regs);
  * Configure SDRAM
  */
 void config_sdram(const struct emif_regs *regs, int nr);
+void config_sdram_emif4d5(const struct emif_regs *regs, int nr);
 
 /**
  * Set SDRAM timings
@@ -278,12 +291,27 @@ struct ddr_cmdtctrl {
        unsigned int resv2[12];
        unsigned int dt0ioctl;
        unsigned int dt1ioctl;
+       unsigned int dt2ioctrl;
+       unsigned int dt3ioctrl;
+       unsigned int resv3[4];
+       unsigned int emif_sdram_config_ext;
+};
+
+struct ctrl_ioregs {
+       unsigned int cm0ioctl;
+       unsigned int cm1ioctl;
+       unsigned int cm2ioctl;
+       unsigned int dt0ioctl;
+       unsigned int dt1ioctl;
+       unsigned int dt2ioctrl;
+       unsigned int dt3ioctrl;
+       unsigned int emif_sdram_config_ext;
 };
 
 /**
  * Configure DDR io control registers
  */
-void config_io_ctrl(unsigned long val);
+void config_io_ctrl(const struct ctrl_ioregs *ioregs);
 
 struct ddr_ctrl {
        unsigned int ddrioctrl;
@@ -291,8 +319,9 @@ struct ddr_ctrl {
        unsigned int ddrckectrl;
 };
 
-void config_ddr(unsigned int pll, unsigned int ioctrl,
+void config_ddr(unsigned int pll, const struct ctrl_ioregs *ioregs,
                const struct ddr_data *data, const struct cmd_control *ctrl,
                const struct emif_regs *regs, int nr);
+void emif_get_ext_phy_ctrl_const_regs(const u32 **regs, u32 *size);
 
 #endif  /* _DDR_DEFS_H */
index 468521bf34b026bad8529fadfe86b09a74bbbc5d..15399dcc747df4742510ef6a2e9006d604b62b67 100644 (file)
@@ -62,6 +62,7 @@
 #define PRM_PER_USBPHYOCP2SCP0_CLKCTRL (CM_PER + 0x5b8)
 #define PRM_PER_USBPHYOCP2SCP1_CLKCTRL (CM_PER + 0x5c0)
 #define USBPHYOCPSCP_MODULE_EN (1 << 1)
+#define CM_DEVICE_INST                 0x44df4100
 
 /* Control status register */
 #define CTRL_CRYSTAL_FREQ_SRC_MASK             (1 << 31)
index d9d521a51505728eff9e04674516aba66ce3b222..e68c113e2800f7666190ca3afb262fbb9c0680b5 100644 (file)
 #define _EMIF_H_
 #include <asm/types.h>
 #include <common.h>
+#include <asm/io.h>
 
 /* Base address */
 #define EMIF1_BASE                             0x4c000000
 #define EMIF2_BASE                             0x4d000000
 
+#define EMIF_4D                                        0x4
+#define EMIF_4D5                               0x5
+
 /* Registers shifts, masks and values */
 
 /* EMIF_MOD_ID_REV */
@@ -1148,6 +1152,14 @@ struct read_write_regs {
        u32 write_reg;
 };
 
+static inline u32 get_emif_rev(u32 base)
+{
+       struct emif_reg_struct *emif = (struct emif_reg_struct *)base;
+
+       return (readl(&emif->emif_mod_id_rev) & EMIF_REG_MAJOR_REVISION_MASK)
+               >> EMIF_REG_MAJOR_REVISION_SHIFT;
+}
+
 /* assert macros */
 #if defined(DEBUG)
 #define emif_assert(c) ({ if (!(c)) for (;;); })
index 5c92ac7f30da9d2c3a6822df65a4333b1da27588..5a013e3384598d1b4e28fdb7f75b0ac8848ba855 100644 (file)
@@ -15,6 +15,8 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/sys_proto.h>
 #include <asm/arch/mux.h>
+#include <asm/arch/ddr_defs.h>
+#include <asm/emif.h>
 #include "board.h"
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -122,6 +124,69 @@ const struct dpll_params epos_evm_dpll_ddr = {
 const struct dpll_params gp_evm_dpll_ddr = {
                400, 23, 1, -1, 1, -1, -1};
 
+const struct ctrl_ioregs ioregs_lpddr2 = {
+       .cm0ioctl               = LPDDR2_ADDRCTRL_IOCTRL_VALUE,
+       .cm1ioctl               = LPDDR2_ADDRCTRL_WD0_IOCTRL_VALUE,
+       .cm2ioctl               = LPDDR2_ADDRCTRL_WD1_IOCTRL_VALUE,
+       .dt0ioctl               = LPDDR2_DATA0_IOCTRL_VALUE,
+       .dt1ioctl               = LPDDR2_DATA0_IOCTRL_VALUE,
+       .dt2ioctrl              = LPDDR2_DATA0_IOCTRL_VALUE,
+       .dt3ioctrl              = LPDDR2_DATA0_IOCTRL_VALUE,
+       .emif_sdram_config_ext  = 0x1,
+};
+
+const struct emif_regs emif_regs_lpddr2 = {
+       .sdram_config                   = 0x808012BA,
+       .ref_ctrl                       = 0x0000040D,
+       .sdram_tim1                     = 0xEA86B411,
+       .sdram_tim2                     = 0x103A094A,
+       .sdram_tim3                     = 0x0F6BA37F,
+       .read_idle_ctrl                 = 0x00050000,
+       .zq_config                      = 0x50074BE4,
+       .temp_alert_config              = 0x0,
+       .emif_rd_wr_lvl_rmp_win         = 0x0,
+       .emif_rd_wr_lvl_rmp_ctl         = 0x0,
+       .emif_rd_wr_lvl_ctl             = 0x0,
+       .emif_ddr_phy_ctlr_1            = 0x0E084006,
+       .emif_rd_wr_exec_thresh         = 0x00000405,
+       .emif_ddr_ext_phy_ctrl_1        = 0x04010040,
+       .emif_ddr_ext_phy_ctrl_2        = 0x00500050,
+       .emif_ddr_ext_phy_ctrl_3        = 0x00500050,
+       .emif_ddr_ext_phy_ctrl_4        = 0x00500050,
+       .emif_ddr_ext_phy_ctrl_5        = 0x00500050
+};
+
+const u32 ext_phy_ctrl_const_base_lpddr2[] = {
+       0x00500050,
+       0x00350035,
+       0x00350035,
+       0x00350035,
+       0x00350035,
+       0x00350035,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x40001000,
+       0x08102040
+};
+
+void emif_get_ext_phy_ctrl_const_regs(const u32 **regs, u32 *size)
+{
+       *regs = ext_phy_ctrl_const_base_lpddr2;
+       *size = ARRAY_SIZE(ext_phy_ctrl_const_base_lpddr2);
+
+       return;
+}
+
 const struct dpll_params *get_dpll_ddr_params(void)
 {
        struct am43xx_board_id header;
@@ -217,6 +282,7 @@ void set_mux_conf_regs(void)
 
 void sdram_init(void)
 {
+       config_ddr(0, &ioregs_lpddr2, NULL, NULL, &emif_regs_lpddr2, 0);
 }
 #endif