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 <lokeshvutla@ti.com>
Signed-off-by: Krunal Bhargav <k-bhargav@ti.com>
This commit is contained in:
Lokesh Vutla 2017-12-29 11:47:48 +05:30 committed by Tom Rini
parent e18cd3d796
commit 650fda93c8
2 changed files with 119 additions and 1 deletions

View file

@ -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 {

View file

@ -17,6 +17,7 @@
#include <asm/omap_sec_common.h>
#include <asm/utils.h>
#include <linux/compiler.h>
#include <asm/ti-common/ti-edma3.h>
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)