From 650fda93c89bcac54ff69603d879ea45f81987f9 Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Fri, 29 Dec 2017 11:47:48 +0530 Subject: [PATCH] arm: emif-common: Add suppport for enabling ECC For data integrity, the EMIF1 supports ECC on the data written or read from the SDRAM. Add support for enabling ECC support in EMIF1. Signed-off-by: Lokesh Vutla Signed-off-by: Krunal Bhargav --- arch/arm/include/asm/emif.h | 31 ++++++++++++++ arch/arm/mach-omap2/emif-common.c | 89 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/emif.h b/arch/arm/include/asm/emif.h index a661ba9..1924f04 100644 --- a/arch/arm/include/asm/emif.h +++ b/arch/arm/include/asm/emif.h @@ -604,6 +604,34 @@ #define EMIF_EXT_PHY_CTRL_TIMING_REG 0x5 +/* EMIF ECC CTRL reg */ +#define EMIF_ECC_CTRL_REG_ECC_EN_SHIFT 31 +#define EMIF_ECC_CTRL_REG_ECC_EN_MASK (1 << 31) +#define EMIF_ECC_CTRL_REG_ECC_ADDR_RGN_PROT_SHIFT 30 +#define EMIF_ECC_CTRL_REG_ECC_ADDR_RGN_PROT_MASK (1 << 30) +#define EMIF_ECC_CTRL_REG_ECC_VERIFY_DIS_SHIFT 29 +#define EMIF_ECC_CTRL_REG_ECC_VERIFY_DIS_MASK (1 << 29) +#define EMIF_ECC_REG_RMW_EN_SHIFT 28 +#define EMIF_ECC_REG_RMW_EN_MASK (1 << 28) +#define EMIF_ECC_REG_ECC_ADDR_RGN_2_EN_SHIFT 1 +#define EMIF_ECC_REG_ECC_ADDR_RGN_2_EN_MASK (1 << 1) +#define EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_SHIFT 0 +#define EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK (1 << 0) + +/* EMIF ECC ADDRESS RANGE */ +#define EMIF_ECC_REG_ECC_END_ADDR_SHIFT 16 +#define EMIF_ECC_REG_ECC_END_ADDR_MASK (0xffff << 16) +#define EMIF_ECC_REG_ECC_START_ADDR_SHIFT 0 +#define EMIF_ECC_REG_ECC_START_ADDR_MASK (0xffff << 0) + +/* EMIF_SYSTEM_OCP_INTERRUPT_RAW_STATUS */ +#define EMIF_INT_ONEBIT_ECC_ERR_SYS_SHIFT 5 +#define EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK (1 << 5) +#define EMIF_INT_TWOBIT_ECC_ERR_SYS_SHIFT 4 +#define EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK (1 << 4) +#define EMIF_INT_WR_ECC_ERR_SYS_SHIFT 3 +#define EMIF_INT_WR_ECC_ERR_SYS_MASK (1 << 3) + /* Reg mapping structure */ struct emif_reg_struct { u32 emif_mod_id_rev; @@ -1205,6 +1233,9 @@ struct emif_regs { u32 emif_connect_id_serv_1_map; u32 emif_connect_id_serv_2_map; u32 emif_cos_config; + u32 emif_ecc_ctrl_reg; + u32 emif_ecc_address_range_1; + u32 emif_ecc_address_range_2; }; struct lpddr2_mr_regs { diff --git a/arch/arm/mach-omap2/emif-common.c b/arch/arm/mach-omap2/emif-common.c index 2b03dbe..e3ef37b 100644 --- a/arch/arm/mach-omap2/emif-common.c +++ b/arch/arm/mach-omap2/emif-common.c @@ -17,6 +17,7 @@ #include #include #include +#include static int emif1_enabled = -1, emif2_enabled = -1; @@ -332,6 +333,71 @@ static void dra7_ddr3_leveling(u32 base, const struct emif_regs *regs) update_hwleveling_output(base, regs); } +static void dra7_reset_ddr_data(u32 base, u32 size) +{ +#if defined(CONFIG_TI_EDMA3) && !defined(CONFIG_DMA) + enable_edma3_clocks(); + + edma3_fill(EDMA3_BASE, 1, (void *)base, 0, size); + + disable_edma3_clocks(); +#else + memset((void *)base, 0, size); +#endif +} + +static void dra7_enable_ecc(u32 base, const struct emif_regs *regs) +{ + struct emif_reg_struct *emif = (struct emif_reg_struct *)base; + u32 rgn, size; + + /* ECC available only on dra76x EMIF1 */ + if ((base != EMIF1_BASE) || !is_dra76x()) + return; + + if (regs->emif_ecc_ctrl_reg & EMIF_ECC_CTRL_REG_ECC_EN_MASK) { + writel(regs->emif_ecc_address_range_1, + &emif->emif_ecc_address_range_1); + writel(regs->emif_ecc_address_range_2, + &emif->emif_ecc_address_range_2); + writel(regs->emif_ecc_ctrl_reg, &emif->emif_ecc_ctrl_reg); + + /* Set region1 memory with 0 */ + rgn = ((regs->emif_ecc_address_range_1 & + EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16) + + CONFIG_SYS_SDRAM_BASE; + size = (regs->emif_ecc_address_range_1 & + EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0x10000; + + if (regs->emif_ecc_ctrl_reg & + EMIF_ECC_REG_ECC_ADDR_RGN_1_EN_MASK) + dra7_reset_ddr_data(rgn, size); + + /* Set region2 memory with 0 */ + rgn = ((regs->emif_ecc_address_range_2 & + EMIF_ECC_REG_ECC_START_ADDR_MASK) << 16) + + CONFIG_SYS_SDRAM_BASE; + size = (regs->emif_ecc_address_range_2 & + EMIF_ECC_REG_ECC_END_ADDR_MASK) + 0x10000; + + if (regs->emif_ecc_ctrl_reg & + EMIF_ECC_REG_ECC_ADDR_RGN_2_EN_MASK) + dra7_reset_ddr_data(rgn, size); + +#ifdef CONFIG_DRA7XX + /* Clear the status flags and other history */ + writel(readl(&emif->emif_1b_ecc_err_cnt), + &emif->emif_1b_ecc_err_cnt); + writel(0xffffffff, &emif->emif_1b_ecc_err_dist_1); + writel(0x1, &emif->emif_2b_ecc_err_addr_log); + writel(EMIF_INT_WR_ECC_ERR_SYS_MASK | + EMIF_INT_TWOBIT_ECC_ERR_SYS_MASK | + EMIF_INT_ONEBIT_ECC_ERR_SYS_MASK, + &emif->emif_irqstatus_sys); +#endif + } +} + static void dra7_ddr3_init(u32 base, const struct emif_regs *regs) { struct emif_reg_struct *emif = (struct emif_reg_struct *)base; @@ -368,8 +434,29 @@ static void dra7_ddr3_init(u32 base, const struct emif_regs *regs) writel(regs->ref_ctrl_final, &emif->emif_sdram_ref_ctrl); - if (regs->emif_rd_wr_lvl_rmp_ctl & EMIF_REG_RDWRLVL_EN_MASK) + if (regs->emif_rd_wr_lvl_rmp_ctl & EMIF_REG_RDWRLVL_EN_MASK) { + /* + * Perform Dummy ECC setup just to allow hardware + * leveling of ECC memories + */ + if (is_dra76x() && (base == EMIF1_BASE) && + (regs->emif_ecc_ctrl_reg & EMIF_ECC_CTRL_REG_ECC_EN_MASK)) { + writel(0, &emif->emif_ecc_address_range_1); + writel(0, &emif->emif_ecc_address_range_2); + writel(EMIF_ECC_CTRL_REG_ECC_EN_MASK | + EMIF_ECC_CTRL_REG_ECC_ADDR_RGN_PROT_MASK, + &emif->emif_ecc_ctrl_reg); + } + dra7_ddr3_leveling(base, regs); + + /* Disable ECC */ + if (is_dra76x()) + writel(0, &emif->emif_ecc_ctrl_reg); + } + + /* Enable ECC as necessary */ + dra7_enable_ecc(base, regs); } static void omap5_ddr3_init(u32 base, const struct emif_regs *regs)