From e6db8a671bf8bbc107925243e394b6c5eb609fe2 Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Wed, 26 Sep 2018 16:34:20 +0800 Subject: imx8mm: Add ddr4 retention support for imx8m Add ddr4 retention flow for imx8m. Signed-off-by: Bai Ping --- plat/imx/common/imx8m/ddr4_retention.c | 185 +++++++++++++++++++++++++++++++++ plat/imx/common/imx8m/dram.c | 17 ++- plat/imx/common/include/dram.h | 3 + plat/imx/imx8mm/platform.mk | 1 + 4 files changed, 195 insertions(+), 11 deletions(-) create mode 100644 plat/imx/common/imx8m/ddr4_retention.c diff --git a/plat/imx/common/imx8m/ddr4_retention.c b/plat/imx/common/imx8m/ddr4_retention.c new file mode 100644 index 00000000..509b4a3e --- /dev/null +++ b/plat/imx/common/imx8m/ddr4_retention.c @@ -0,0 +1,185 @@ +/* + * copyright 2018 nxp + * + * spdx-license-identifier: bsd-3-clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SRC_IPS_BASE_ADDR IMX_SRC_BASE +#define SRC_DDRC_RCR_ADDR (SRC_IPS_BASE_ADDR + 0x1000) + +#define GPC_PU_PWRHSK (IMX_GPC_BASE + 0x01FC) +#define CCM_SRC_CTRL_OFFSET (IMX_CCM_BASE + 0x800) +#define CCM_CCGR_OFFSET (IMX_CCM_BASE + 0x4000) +#define CCM_SRC_CTRL(n) (CCM_SRC_CTRL_OFFSET + 0x10 * n) +#define CCM_CCGR(n) (CCM_CCGR_OFFSET + 0x10 * n) + +void ddr4_enter_retention(void) +{ + volatile unsigned int tmp; + + /* wait DBGCAM to be empty */ + do { + tmp = mmio_read_32(DDRC_DBGCAM(0)); + } while (tmp != 0x36000000); + + /* Blocks AXI ports from taking anymore transactions */ + mmio_write_32(DDRC_PCTRL_0(0), 0x00000000); + + /* Waits unit all AXI ports are idle */ + do { + tmp = mmio_read_32(DDRC_PSTAT(0)); + } while (tmp & 0x10001); + + /* enters self refresh */ + mmio_write_32(DDRC_PWRCTL(0), 0x000000aa); + + tmp=0; + /* self-refresh state */ + while (tmp!=0x23) { + tmp = 0x3f & (mmio_read_32((DDRC_STAT(0)))); + } + + mmio_write_32(DDRC_DFIMISC(0), 0x00000000); + + /* set SWCTL.sw_done to disable quasi-dynamic register programming outside reset. */ + mmio_write_32(DDRC_SWCTL(0), 0x00000000); + + mmio_write_32(DDRC_DFIMISC(0), 0x00001f00); + mmio_write_32(DDRC_DFIMISC(0), 0x00001f20); + + /* wait DFISTAT.dfi_init_complete to 0 */ + while (1 == (0x1 & mmio_read_32(DDRC_DFISTAT(0)))) + ; + + mmio_write_32(DDRC_DFIMISC(0), 0x00001f00); + + /* wait DFISTAT.dfi_init_complete to 1 */ + while (0 == (0x1 & mmio_read_32(DDRC_DFISTAT(0)))) + ; + + /* set SWCTL.sw_done to enable quasi-dynamic register programming outside reset. */ + mmio_write_32(DDRC_SWCTL(0), 0x00000001); + + /* should check PhyInLP3 pub reg */ + dwc_ddrphy_apb_wr(0xd0000,0x0); + tmp = mmio_read_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+4*0x00090028); + tmp = tmp & 0x1; + if(tmp) + printf("C: PhyInLP3 = 1\n"); + else + printf("vt_fail\n"); + dwc_ddrphy_apb_wr(0xd0000,0x1); + + /* pwrdnreqn_async adbm/adbs of ddr */ + mmio_clrbits_32(GPC_PU_PWRHSK, (1 << 2)); + do { + tmp = mmio_read_32(GPC_PU_PWRHSK); + } while (tmp & (0x1 << 20)); /* wait untill pwrdnackn_async=0 */ + mmio_setbits_32(GPC_PU_PWRHSK, (1 << 2)); + + /* remove PowerOk: assert [3]ddr1_phy_pwrokin_n */ + mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000008); + + mmio_write_32(CCM_CCGR(5), 0); + mmio_write_32(CCM_SRC_CTRL(15), 2); + + mmio_setbits_32(0x303A0D40, 1); + mmio_setbits_32(0x303A0104, (1 << 5)); +} + +void ddr4_exit_retention(void) +{ + volatile unsigned int tmp, tmp_t, i; + + for (i = 0; i < 20; i++){ + } + + /* assert all reset */ + mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F00003F); + + mmio_write_32(CCM_CCGR(5), 2); + mmio_write_32(CCM_SRC_CTRL(15), 2); + printf("C: enable all DRAM clocks \n"); + + mmio_write_32(0x303A00EC, 0x0000ffff); /* PGC_CPU_MAPPING */ + mmio_setbits_32(0x303A00F8, (1 << 5)); + + mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F00000F); /* release [4]src_system_rst_b! */ + mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000006); /* release [0]ddr1_preset_n, [3]ddr1_phy_pwrokin_n */ + /* RESET: ASSERTED (ACTIVE LOW) */ + /* RESET: ASSERTED (ACTIVE LOW) */ + /* RESET: for Port 0 ASSERTED (ACTIVE LOW) */ + /* RESET: DEASSERTED */ + + mmio_write_32(DDRC_DBG1(0), 0x00000001); + mmio_write_32(DDRC_PWRCTL(0), 0x00000001); + while (0 != (0x7 & mmio_read_32(DDRC_STAT(0)))) + ; + + /* ddrc init */ + dram_umctl2_init(); + + /* Skips the DRAM init routine and starts up in selfrefresh mode */ + /* Program INIT0.skip_dram_init = 2'b11 */ + mmio_write_32(DDRC_INIT0(0), 0xc0000000 | (mmio_read_32(DDRC_INIT0(0)))); + mmio_write_32(DDRC_MSTR2(0), 0x0); + + /* Keeps the controller in self-refresh mode */ + mmio_write_32(DDRC_PWRCTL(0), 0x000001a8); + mmio_clrbits_32(DDRC_DFIMISC(0), 1); + mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000004); + mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F000000); /* release all reset */ + + /* restore the ddr phy config */ + dram_phy_init(); + + do { + tmp_t = mmio_read_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4*0x00020097); + } while (tmp_t != 0); + + /* before write Dynamic reg, sw_done should be 0 */ + mmio_write_32(DDRC_SWCTL(0), 0x00000000); + mmio_write_32(DDRC_DFIMISC(0), 0x00000020); + + /* wait DFISTAT.dfi_init_complete to 1 */ + while(0 == (0x1 & mmio_read_32(DDRC_DFISTAT(0)))) + ; + + /* clear DFIMISC.dfi_init_complete_en */ + mmio_write_32(DDRC_DFIMISC(0), 0x00000000); + /* set DFIMISC.dfi_init_complete_en again */ + mmio_setbits_32(DDRC_DFIMISC(0), 1); + mmio_clrbits_32(DDRC_PWRCTL(0), (1 << 5)); + + /* set SWCTL.sw_done to enable quasi-dynamic register programming outside reset. */ + mmio_write_32(DDRC_SWCTL(0), 0x00000001); + /* wait SWSTAT.sw_done_ack to 1 */ + while(0 == (0x1 & mmio_read_32(DDRC_SWSTAT(0)))); + + /* wait STAT to normal state */ + while(0x1 != (0x7 & mmio_read_32(DDRC_STAT(0)))); + + mmio_write_32(DDRC_PCTRL_0(0), 0x00000001); + /* dis_auto-refresh is set to 0 */ + mmio_write_32(DDRC_RFSHCTL3(0), 0x00000010); + + /* should check PhyInLP3 pub reg */ + mmio_write_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4*0xd0000, 0x0); + tmp = mmio_read_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4*0x00090028); + tmp = tmp & 0x1; + if (!tmp) + printf("C: PhyInLP3 = 0\n"); + else + printf("vt_fail\n"); + mmio_write_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4*0xd0000, 0x1); +} diff --git a/plat/imx/common/imx8m/dram.c b/plat/imx/common/imx8m/dram.c index 26d464fe..e00ca96d 100644 --- a/plat/imx/common/imx8m/dram.c +++ b/plat/imx/common/imx8m/dram.c @@ -67,20 +67,13 @@ void dram_phy_init(void) } } - void dram_info_init(unsigned long dram_timing_base) { uint32_t current_fsp, ddr_type; /* get the dram type */ ddr_type = mmio_read_32(DDRC_MSTR(0)) & DDR_TYPE_MASK; - - if (ddr_type == DDRC_LPDDR4) { - dram_info.dram_type = ddr_type; - } else { - /* TODO DDR4 support will be added later */ - return; - } + dram_info.dram_type = ddr_type; /* init the boot_fsp & current_fsp */ current_fsp = mmio_read_32(DDRC_DFIMISC(0)); @@ -95,7 +88,7 @@ void dram_info_init(unsigned long dram_timing_base) dram_info.timing_info = (struct dram_timing_info *)dram_timing_base; /* switch to the highest frequency point */ - if(current_fsp != 0x0) { + if(ddr_type == DDRC_LPDDR4 && current_fsp != 0x0) { /* flush the L1/L2 cache */ dcsw_op_all(DCCSW); lpddr4_swffc(dev_fsp, 0x0); @@ -105,16 +98,18 @@ void dram_info_init(unsigned long dram_timing_base) void dram_enter_retention(void) { - /* TODO add the ddr4 support in the furture */ if (dram_info.dram_type == DDRC_LPDDR4) lpddr4_enter_retention(); + else if (dram_info.dram_type == DDRC_DDR4) + ddr4_enter_retention(); } void dram_exit_retention(void) { - /* TODO add the ddr4 support in the furture */ if (dram_info.dram_type == DDRC_LPDDR4) lpddr4_exit_retention(); + else if (dram_info.dram_type == DDRC_DDR4) + ddr4_exit_retention(); } int dram_dvfs_handler(uint32_t smc_fid, diff --git a/plat/imx/common/include/dram.h b/plat/imx/common/include/dram.h index fd606f57..fa203da2 100644 --- a/plat/imx/common/include/dram.h +++ b/plat/imx/common/include/dram.h @@ -28,6 +28,7 @@ #include #define DDRC_LPDDR4 BIT(5) +#define DDRC_DDR4 BIT(4) #define DDR_TYPE_MASK 0x3f #define DDRPHY_REG(x) (0x3c000000 + 4*x) @@ -73,6 +74,8 @@ void dram_phy_init(void); void lpddr4_enter_retention(void); void lpddr4_exit_retention(void); +void ddr4_enter_retention(void); +void ddr4_exit_retention(void); /* lpddr4 swffc for dvfs */ void lpddr4_swffc(unsigned int dev_fsp, unsigned int tgt_freq); diff --git a/plat/imx/imx8mm/platform.mk b/plat/imx/imx8mm/platform.mk index 4597fb96..ac9db97c 100644 --- a/plat/imx/imx8mm/platform.mk +++ b/plat/imx/imx8mm/platform.mk @@ -12,6 +12,7 @@ PLAT_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \ PLAT_DRAM_SOURCES := plat/imx/common/imx8m/dram.c \ plat/imx/common/imx8m/clock.c \ plat/imx/common/imx8m/lpddr4_retention.c \ + plat/imx/common/imx8m/ddr4_retention.c \ plat/imx/common/imx8m/lpddr4_helper.c \ plat/imx/common/imx8m/lpddr4_dvfs.c -- cgit v1.2.3