summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/cpu/armv7/omap-common/emif-common.c42
-rw-r--r--arch/arm/cpu/armv7/omap4/sdram_elpida.c5
-rw-r--r--arch/arm/cpu/armv7/omap5/sdram.c68
-rw-r--r--arch/arm/include/asm/emif.h10
4 files changed, 124 insertions, 1 deletions
diff --git a/arch/arm/cpu/armv7/omap-common/emif-common.c b/arch/arm/cpu/armv7/omap-common/emif-common.c
index dc1ea1d96d..5a3f2858cd 100644
--- a/arch/arm/cpu/armv7/omap-common/emif-common.c
+++ b/arch/arm/cpu/armv7/omap-common/emif-common.c
@@ -1286,6 +1286,42 @@ void dmm_init(u32 base)
}
+static void do_bug0039_workaround(u32 base)
+{
+ u32 val, i, clkctrl;
+ struct emif_reg_struct *emif_base = (struct emif_reg_struct *)base;
+ const struct read_write_regs *bug_00339_regs;
+ u32 iterations;
+ u32 *phy_status_base = &emif_base->emif_ddr_phy_status[0];
+ u32 *phy_ctrl_base = &emif_base->emif_ddr_ext_phy_ctrl_1;
+
+ if (is_dra7xx())
+ phy_status_base++;
+
+ bug_00339_regs = get_bug_regs(&iterations);
+
+ /* Put EMIF in to idle */
+ clkctrl = __raw_readl((*prcm)->cm_memif_clkstctrl);
+ __raw_writel(0x0, (*prcm)->cm_memif_clkstctrl);
+
+ /* Copy the phy status registers in to phy ctrl shadow registers */
+ for (i = 0; i < iterations; i++) {
+ val = __raw_readl(phy_status_base +
+ bug_00339_regs[i].read_reg - 1);
+
+ __raw_writel(val, phy_ctrl_base +
+ ((bug_00339_regs[i].write_reg - 1) << 1));
+
+ __raw_writel(val, phy_ctrl_base +
+ (bug_00339_regs[i].write_reg << 1) - 1);
+ }
+
+ /* Disable leveling */
+ writel(0x0, &emif_base->emif_rd_wr_lvl_rmp_ctl);
+
+ __raw_writel(clkctrl, (*prcm)->cm_memif_clkstctrl);
+}
+
/*
* SDRAM initialization:
* SDRAM initialization has two parts:
@@ -1361,5 +1397,11 @@ void sdram_init(void)
debug("get_ram_size() successful");
}
+ if (sdram_type == EMIF_SDRAM_TYPE_DDR3 &&
+ (!in_sdram && !warm_reset())) {
+ do_bug0039_workaround(EMIF1_BASE);
+ do_bug0039_workaround(EMIF2_BASE);
+ }
+
debug("<<sdram_init()\n");
}
diff --git a/arch/arm/cpu/armv7/omap4/sdram_elpida.c b/arch/arm/cpu/armv7/omap4/sdram_elpida.c
index e4c8316370..811e7764c1 100644
--- a/arch/arm/cpu/armv7/omap4/sdram_elpida.c
+++ b/arch/arm/cpu/armv7/omap4/sdram_elpida.c
@@ -321,3 +321,8 @@ void get_lpddr2_mr_regs(const struct lpddr2_mr_regs **regs)
{
*regs = &mr_regs;
}
+
+__weak const struct read_write_regs *get_bug_regs(u32 *iterations)
+{
+ return 0;
+}
diff --git a/arch/arm/cpu/armv7/omap5/sdram.c b/arch/arm/cpu/armv7/omap5/sdram.c
index 2aae3efb71..2e1870609a 100644
--- a/arch/arm/cpu/armv7/omap5/sdram.c
+++ b/arch/arm/cpu/armv7/omap5/sdram.c
@@ -569,6 +569,74 @@ static const struct lpddr2_device_timings dev_4G_S4_timings = {
.min_tck = &min_tck,
};
+/*
+ * List of status registers to be controlled back to control registers
+ * after initial leveling
+ * readreg, writereg
+ */
+const struct read_write_regs omap5_bug_00339_regs[] = {
+ { 8, 5 },
+ { 9, 6 },
+ { 10, 7 },
+ { 14, 8 },
+ { 15, 9 },
+ { 16, 10 },
+ { 11, 2 },
+ { 12, 3 },
+ { 13, 4 },
+ { 17, 11 },
+ { 18, 12 },
+ { 19, 13 },
+};
+
+const struct read_write_regs dra_bug_00339_regs[] = {
+ { 7, 7 },
+ { 8, 8 },
+ { 9, 9 },
+ { 10, 10 },
+ { 11, 11 },
+ { 12, 2 },
+ { 13, 3 },
+ { 14, 4 },
+ { 15, 5 },
+ { 16, 6 },
+ { 17, 12 },
+ { 18, 13 },
+ { 19, 14 },
+ { 20, 15 },
+ { 21, 16 },
+ { 22, 17 },
+ { 23, 18 },
+ { 24, 19 },
+ { 25, 20 },
+ { 26, 21}
+};
+
+const struct read_write_regs *get_bug_regs(u32 *iterations)
+{
+ const struct read_write_regs *bug_00339_regs_ptr = NULL;
+
+ switch (omap_revision()) {
+ case OMAP5430_ES1_0:
+ case OMAP5430_ES2_0:
+ case OMAP5432_ES1_0:
+ case OMAP5432_ES2_0:
+ bug_00339_regs_ptr = omap5_bug_00339_regs;
+ *iterations = sizeof(omap5_bug_00339_regs)/
+ sizeof(omap5_bug_00339_regs[0]);
+ break;
+ case DRA752_ES1_0:
+ bug_00339_regs_ptr = dra_bug_00339_regs;
+ *iterations = sizeof(dra_bug_00339_regs)/
+ sizeof(dra_bug_00339_regs[0]);
+ break;
+ default:
+ printf("\n Error: UnKnown SOC");
+ }
+
+ return bug_00339_regs_ptr;
+}
+
void emif_get_device_timings_sdp(u32 emif_nr,
const struct lpddr2_device_timings **cs0_device_timings,
const struct lpddr2_device_timings **cs1_device_timings)
diff --git a/arch/arm/include/asm/emif.h b/arch/arm/include/asm/emif.h
index c12beea0ca..d9d521a515 100644
--- a/arch/arm/include/asm/emif.h
+++ b/arch/arm/include/asm/emif.h
@@ -640,7 +640,9 @@ struct emif_reg_struct {
u32 emif_ddr_phy_ctrl_2;
u32 padding7[12];
u32 emif_rd_wr_exec_thresh;
- u32 padding8[55];
+ u32 padding8[7];
+ u32 emif_ddr_phy_status[21];
+ u32 padding9[27];
u32 emif_ddr_ext_phy_ctrl_1;
u32 emif_ddr_ext_phy_ctrl_1_shdw;
u32 emif_ddr_ext_phy_ctrl_2;
@@ -1141,6 +1143,11 @@ struct lpddr2_mr_regs {
s8 mr16;
};
+struct read_write_regs {
+ u32 read_reg;
+ u32 write_reg;
+};
+
/* assert macros */
#if defined(DEBUG)
#define emif_assert(c) ({ if (!(c)) for (;;); })
@@ -1169,4 +1176,5 @@ extern u32 *const T_den;
void config_data_eye_leveling_samples(u32 emif_base);
u32 emif_sdram_type(void);
+const struct read_write_regs *get_bug_regs(u32 *iterations);
#endif
OpenPOWER on IntegriCloud