diff options
Diffstat (limited to 'drivers/ddr')
| -rw-r--r-- | drivers/ddr/imx/imx8m/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/ddr/imx/imx8m/ddr_init.c | 72 | 
2 files changed, 79 insertions, 0 deletions
| diff --git a/drivers/ddr/imx/imx8m/Kconfig b/drivers/ddr/imx/imx8m/Kconfig index 5bf61eb2587..a5f5524fbec 100644 --- a/drivers/ddr/imx/imx8m/Kconfig +++ b/drivers/ddr/imx/imx8m/Kconfig @@ -29,4 +29,11 @@ config SAVED_DRAM_TIMING_BASE  	  info into memory for low power use. OCRAM_S is used for this  	  purpose on i.MX8MM.  	default 0x180000 + +config IMX8M_DRAM_INLINE_ECC +	bool "imx8mp inline ECC" +	depends on IMX8MP && IMX8M_LPDDR4 +	help +	  Select this config if you want to use inline ecc feature for +	  imx8mp-evk board.  endmenu diff --git a/drivers/ddr/imx/imx8m/ddr_init.c b/drivers/ddr/imx/imx8m/ddr_init.c index de302937d08..664966c41bf 100644 --- a/drivers/ddr/imx/imx8m/ddr_init.c +++ b/drivers/ddr/imx/imx8m/ddr_init.c @@ -21,6 +21,76 @@ void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)  	}  } +#ifdef CONFIG_IMX8M_DRAM_INLINE_ECC +void ddrc_inline_ecc_scrub(unsigned int start_address, +			   unsigned int range_address) +{ +	unsigned int tmp; + +	/* Step1: Enable quasi-dynamic programming */ +	reg32_write(DDRC_SWCTL(0), 0x00000000); +	/* Step2: Set ECCCFG1.ecc_parity_region_lock to 1 */ +	reg32setbit(DDRC_ECCCFG1(0), 0x4); +	/* Step3: Block the AXI ports from taking the transaction */ +	reg32_write(DDRC_PCTRL_0(0), 0x0); +	/* Step4: Set scrub start address */ +	reg32_write(DDRC_SBRSTART0(0), start_address); +	/* Step5: Set scrub range address */ +	reg32_write(DDRC_SBRRANGE0(0), range_address); +	/* Step6: Set scrub_mode to write */ +	reg32_write(DDRC_SBRCTL(0), 0x00000014); +	/* Step7: Set the desired pattern through SBRWDATA0 registers */ +	reg32_write(DDRC_SBRWDATA0(0), 0x55aa55aa); +	/* Step8: Enable the SBR by programming SBRCTL.scrub_en=1 */ +	reg32setbit(DDRC_SBRCTL(0), 0x0); +	/* Step9: Poll SBRSTAT.scrub_done=1 */ +	tmp = reg32_read(DDRC_SBRSTAT(0)); +	while (tmp != 0x00000002) +		tmp = reg32_read(DDRC_SBRSTAT(0)) & 0x2; +	/* Step10: Poll SBRSTAT.scrub_busy=0 */ +	tmp = reg32_read(DDRC_SBRSTAT(0)); +	while (tmp != 0x0) +		tmp = reg32_read(DDRC_SBRSTAT(0)) & 0x1; +	/* Step11: Disable SBR by programming SBRCTL.scrub_en=0 */ +	clrbits_le32(DDRC_SBRCTL(0), 0x1); +	/* Step12: Prepare for normal scrub operation(Read) and set scrub_interval*/ +	reg32_write(DDRC_SBRCTL(0), 0x100); +	/* Step13: Enable the SBR by programming SBRCTL.scrub_en=1 */ +	reg32_write(DDRC_SBRCTL(0), 0x101); +	/* Step14: Enable AXI ports by programming */ +	reg32_write(DDRC_PCTRL_0(0), 0x1); +	/* Step15: Disable quasi-dynamic programming */ +	reg32_write(DDRC_SWCTL(0), 0x00000001); +} + +void ddrc_inline_ecc_scrub_end(unsigned int start_address, +			       unsigned int range_address) +{ +	/* Step1: Enable quasi-dynamic programming */ +	reg32_write(DDRC_SWCTL(0), 0x00000000); +	/* Step2: Block the AXI ports from taking the transaction */ +	reg32_write(DDRC_PCTRL_0(0), 0x0); +	/* Step3: Set scrub start address */ +	reg32_write(DDRC_SBRSTART0(0), start_address); +	/* Step4: Set scrub range address */ +	reg32_write(DDRC_SBRRANGE0(0), range_address); +	/* Step5: Disable SBR by programming SBRCTL.scrub_en=0 */ +	clrbits_le32(DDRC_SBRCTL(0), 0x1); +	/* Step6: Prepare for normal scrub operation(Read) and set scrub_interval */ +	reg32_write(DDRC_SBRCTL(0), 0x100); +	/* Step7: Enable the SBR by programming SBRCTL.scrub_en=1 */ +	reg32_write(DDRC_SBRCTL(0), 0x101); +	/* Step8: Enable AXI ports by programming */ +	reg32_write(DDRC_PCTRL_0(0), 0x1); +	/* Step9: Disable quasi-dynamic programming */ +	reg32_write(DDRC_SWCTL(0), 0x00000001); +} +#endif + +void __weak board_dram_ecc_scrub(void) +{ +} +  int ddr_init(struct dram_timing_info *dram_timing)  {  	unsigned int tmp, initial_drate, target_freq; @@ -169,6 +239,8 @@ int ddr_init(struct dram_timing_info *dram_timing)  	reg32_write(DDRC_PCTRL_0(0), 0x00000001);  	debug("DDRINFO: ddrmix config done\n"); +	board_dram_ecc_scrub(); +  	/* save the dram timing config into memory */  	dram_config_save(dram_timing, CONFIG_SAVED_DRAM_TIMING_BASE); | 
