diff options
author | Bai Ping <ping.bai@nxp.com> | 2018-10-29 18:33:58 +0800 |
---|---|---|
committer | Bai Ping <ping.bai@nxp.com> | 2018-11-02 17:33:33 +0800 |
commit | c290a9e1664628a13a5e75e2400c5cc17882fbba (patch) | |
tree | 4d7eddc29a48943019ec178ad9dcff41af90496a /plat/imx/common | |
parent | b6e9e2d823b1ff5f4e83fa34541003df0e70e1c9 (diff) |
plat: imx8mq: refact the dram low power code
refact the dram low power related code to make it more
friendly for different dram config or different board.
Signed-off-by: Bai Ping <ping.bai@nxp.com>
Diffstat (limited to 'plat/imx/common')
-rw-r--r-- | plat/imx/common/imx8m/clock.c | 27 | ||||
-rw-r--r-- | plat/imx/common/imx8m/dram.c | 100 | ||||
-rw-r--r-- | plat/imx/common/imx8m/lpddr4_dvfs.c | 16 | ||||
-rw-r--r-- | plat/imx/common/imx8m/lpddr4_retention.c | 4 | ||||
-rw-r--r-- | plat/imx/common/include/dram.h | 6 | ||||
-rw-r--r-- | plat/imx/common/sip_svc.c | 9 |
6 files changed, 145 insertions, 17 deletions
diff --git a/plat/imx/common/imx8m/clock.c b/plat/imx/common/imx8m/clock.c index fee68218..86ebd9a9 100644 --- a/plat/imx/common/imx8m/clock.c +++ b/plat/imx/common/imx8m/clock.c @@ -61,3 +61,30 @@ void dram_clock_switch(unsigned int target_freq) ddr_pll_bypass_dis(); } } + +#if defined(PLAT_IMX8M) +void dram_pll_init(unsigned int drate) +{ + /* bypass the PLL */ + mmio_setbits_32(HW_DRAM_PLL_CFG0, 0x30); + + switch (drate) { + case 3200: + mmio_write_32(HW_DRAM_PLL_CFG2, 0x00ece580); + break; + case 1600: + mmio_write_32(HW_DRAM_PLL_CFG2, 0x00ec6984); + break; + case 667: + mmio_write_32(HW_DRAM_PLL_CFG2, 0x00f5a406); + break; + default: + break; + } + + /* bypass the PLL */ + mmio_clrbits_32(HW_DRAM_PLL_CFG0, 0x30); + while(!(mmio_read_32(HW_DRAM_PLL_CFG0) &(1 << 31))) + ; +} +#endif diff --git a/plat/imx/common/imx8m/dram.c b/plat/imx/common/imx8m/dram.c index df34c4b0..abb607ad 100644 --- a/plat/imx/common/imx8m/dram.c +++ b/plat/imx/common/imx8m/dram.c @@ -15,11 +15,81 @@ static struct dram_info dram_info; /* lock used for DDR DVFS */ spinlock_t dfs_lock; /* IRQ used for DDR DVFS */ +#if defined(PLAT_IMX8M) +static uint32_t irqs_used [] = {102, 109, 110, 111}; +/* ocram used to dram timing */ +static uint8_t dram_timing_saved[13 * 1024] __aligned(8); +#else static uint32_t irqs_used[] = {74, 75, 76, 77}; +#endif static volatile uint32_t wfe_done; static volatile bool wait_ddrc_hwffc_done = true; static unsigned int dev_fsp = 0x1; +bool bypass_mode_supported = true; + +#if defined (PLAT_IMX8M) +/* copy the dram timing info from DRAM to OCRAM */ +void imx8mq_dram_timing_copy(struct dram_timing_info *from, + struct dram_timing_info *to) +{ + struct dram_cfg_param *cfg1, *cfg2; + unsigned int num; + + /* copy the dram_timing info header */ + cfg1 = (struct dram_cfg_param *) ((unsigned long) to + sizeof(struct dram_timing_info)); + cfg2 = from->ddrc_cfg; + + /* copy the ddrc init config */ + to->ddrc_cfg_num = from->ddrc_cfg_num; + to->ddrphy_cfg_num = from->ddrphy_cfg_num; + to->ddrphy_trained_csr_num = from->ddrphy_trained_csr_num; + to->ddrphy_pie_num = from->ddrphy_pie_num; + + /* copy the fsp table */ + for (int i = 0; i < 4; i++) + to->fsp_table[i] = from->fsp_table[i]; + + /* copy the ddrc config */ + to->ddrc_cfg = cfg1; + num = from->ddrc_cfg_num; + for (int i = 0; i < num; i++) { + cfg1->reg = cfg2->reg; + cfg1->val = cfg2->val; + cfg1++; + cfg2++; + } + + /* copy the ddrphy init config */ + to->ddrphy_cfg = cfg1; + num = from->ddrphy_cfg_num; + for (int i = 0; i < num; i++) { + cfg1->reg = cfg2->reg; + cfg1->val = cfg2->val; + cfg1++; + cfg2++; + } + + /* copy the ddrphy csr */ + to->ddrphy_trained_csr = cfg1; + num = from->ddrphy_trained_csr_num; + for (int i = 0; i < num; i++) { + cfg1->reg = cfg2->reg; + cfg1->val = cfg2->val; + cfg1++; + cfg2++; + } + /* copy the PIE image */ + to->ddrphy_pie = cfg1; + num = from->ddrphy_pie_num; + for (int i = 0; i < num; i++) { + cfg1->reg = cfg2->reg; + cfg1->val = cfg2->val; + cfg1++; + cfg2++; + } +} +#endif /* restore the ddrc config */ void dram_umctl2_init(void) @@ -67,6 +137,19 @@ void dram_phy_init(void) } } +#define BYPASS_MODE_DRATE 666 +static bool is_bypass_mode_enabled(struct dram_timing_info *info) +{ + /* + * if there is a fsp drate is lower than 666, we assume + * that the bypass mode is enanbled. + */ + if(info->fsp_table[1] > BYPASS_MODE_DRATE || + info->fsp_table[2] > BYPASS_MODE_DRATE) + return false; + else + return true; +} void dram_info_init(unsigned long dram_timing_base) { @@ -85,6 +168,13 @@ void dram_info_init(unsigned long dram_timing_base) dram_info.boot_fsp = current_fsp; dram_info.current_fsp = current_fsp; +#if defined(PLAT_IMX8M) + imx8mq_dram_timing_copy((struct dram_timing_info *)dram_timing_base, + (struct dram_timing_info *)dram_timing_saved); + + dram_timing_base = (unsigned long) dram_timing_saved; +#endif + bypass_mode_supported = is_bypass_mode_enabled((struct dram_timing_info *)dram_timing_base); /* * No need to do save for ddrc and phy config register, * we have done it in SPL stage and save in memory @@ -95,7 +185,7 @@ void dram_info_init(unsigned long dram_timing_base) if(ddr_type == DDRC_LPDDR4 && current_fsp != 0x0) { /* flush the L1/L2 cache */ dcsw_op_all(DCCSW); - lpddr4_swffc(dev_fsp, 0x0); + lpddr4_swffc(&dram_info, dev_fsp, 0x0, bypass_mode_supported); dev_fsp = (~dev_fsp) & 0x1; } else if (ddr_type == DDRC_DDR4 && current_fsp != 0x0) { /* flush the L1/L2 cache */ @@ -156,15 +246,21 @@ int dram_dvfs_handler(uint32_t smc_fid, /* make sure all the core in WFE */ online_cores &= ~(0x1 << (cpu_id * 8)); while (1) { +#if defined(PLAT_IMX8M) + mmio_write_32(0x30340004, mmio_read_32(0x30340004) | (1 << 12)); +#endif if (online_cores == wfe_done) break; } +#if defined(PLAT_IMX8M) + mmio_write_32(0x30340004, mmio_read_32(0x30340004) & ~(1 << 12)); +#endif /* flush the L1/L2 cache */ dcsw_op_all(DCCSW); if (dram_info.dram_type == DDRC_LPDDR4) { - lpddr4_swffc(dev_fsp, target_freq); + lpddr4_swffc(&dram_info, dev_fsp, target_freq, bypass_mode_supported); dev_fsp = (~dev_fsp) & 0x1; } else if (dram_info.dram_type == DDRC_DDR4) { ddr4_swffc(&dram_info, target_freq); diff --git a/plat/imx/common/imx8m/lpddr4_dvfs.c b/plat/imx/common/imx8m/lpddr4_dvfs.c index 4cdbd52a..b3ea27bb 100644 --- a/plat/imx/common/imx8m/lpddr4_dvfs.c +++ b/plat/imx/common/imx8m/lpddr4_dvfs.c @@ -13,7 +13,8 @@ extern void dram_clock_switch(unsigned target_freq); -void lpddr4_swffc(unsigned int init_fsp, unsigned int tgt_freq) +void lpddr4_swffc(struct dram_info *info, unsigned int init_fsp, + unsigned int tgt_freq, bool bypass_mode) { unsigned int mr, emr, emr2, emr3; @@ -60,6 +61,9 @@ void lpddr4_swffc(unsigned int init_fsp, unsigned int tgt_freq) tmp &= ~0xf; mmio_write_32(DDRC_PWRCTL(0), tmp); + /* more safe */ + mmio_write_32(DDRC_DFIPHYMSTR(0), 0x00000000); + lpddr4_mr_write(3, 13, emr3); lpddr4_mr_write(3, 1, mr); lpddr4_mr_write(3, 2, emr); @@ -84,7 +88,6 @@ void lpddr4_swffc(unsigned int init_fsp, unsigned int tgt_freq) /* 6.disable SBRCTL.scrub_en, skip if never enable it */ /* 7.poll SBRSTAT.scrub_busy Q2: should skip phy master if never enable it */ /* Disable phy master */ - mmio_write_32(DDRC_DFIPHYMSTR(0),0x00000000); #ifdef DFILP_SPT /* 8. disable DFI LP */ @@ -214,7 +217,14 @@ void lpddr4_swffc(unsigned int init_fsp, unsigned int tgt_freq) } while ((tmp & 0x1) == 0x1); /* change the clock frequency */ +#if defined(PLAT_IMX8M) + if (bypass_mode) + dram_clock_switch(tgt_freq); + else + dram_pll_init(info->timing_info->fsp_table[tgt_freq]); +#else dram_clock_switch(tgt_freq); +#endif /* dfi_init_start de-assert */ tmp= mmio_read_32(DDRC_DFIMISC(0)); @@ -269,7 +279,6 @@ void lpddr4_swffc(unsigned int init_fsp, unsigned int tgt_freq) tmp= mmio_read_32(DDRC_DBGSTAT(0)); } while ((tmp & 0x10 ) != 0x0); -#if 1 /* 33. Reset ZQCTL0.dis_srx_zqcl=0 */ if (tgt_freq == 1) { tmp = mmio_read_32(DDRC_FREQ1_ZQCTL0(0)); @@ -346,5 +355,4 @@ void lpddr4_swffc(unsigned int init_fsp, unsigned int tgt_freq) mmio_write_32(DDRC_PCTRL_0(0), 0x1); /* 42. enable SBRCTL.scrub_en, skip if never enable it */ -#endif } diff --git a/plat/imx/common/imx8m/lpddr4_retention.c b/plat/imx/common/imx8m/lpddr4_retention.c index c44dd291..205dbbff 100644 --- a/plat/imx/common/imx8m/lpddr4_retention.c +++ b/plat/imx/common/imx8m/lpddr4_retention.c @@ -92,7 +92,7 @@ void lpddr4_enter_retention(void) for (i=0; i<20; i++){ } -#ifdef M850D +#if defined(PLAT_IMX8M) /* pwrdnreqn_async adbm/adbs of ddr */ mmio_clrbits_32(GPC_PU_PWRHSK, (1 << 1)); do { @@ -140,7 +140,7 @@ void lpddr4_exit_retention(void) } /*assert all reset */ -#ifdef M850D +#if defined(PLAT_IMX8M) mmio_write_32(SRC_DDRC_RCR_ADDR+0x4, 0x8F000003); // assert [0]src_system_rst_b! mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F00000F); // assert [0]ddr1_preset_n, [1]ddr1_core_reset_n, [2]ddr1_phy_reset, [3]ddr1_phy_pwrokin_n, mmio_write_32(SRC_DDRC_RCR_ADDR+0x4, 0x8F000000); // deassert [4]src_system_rst_b! diff --git a/plat/imx/common/include/dram.h b/plat/imx/common/include/dram.h index f3d72dd8..bf0b3848 100644 --- a/plat/imx/common/include/dram.h +++ b/plat/imx/common/include/dram.h @@ -56,6 +56,8 @@ struct dram_timing_info { /* ddr phy PIE */ struct dram_cfg_param *ddrphy_pie; unsigned int ddrphy_pie_num; + /* initialized fsp table */ + unsigned int fsp_table[4]; }; struct dram_info { @@ -79,7 +81,8 @@ 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); +void lpddr4_swffc(struct dram_info *dram_info, unsigned int dev_fsp, + unsigned int tgt_freq, bool bypass_mode_supported); /* ddr4 swffw for dvfs */ void ddr4_swffc(struct dram_info *dram_info, unsigned int target_fsp); @@ -88,5 +91,6 @@ void dram_enter_retention(void); void dram_exit_retention(void); void dram_clock_switch(unsigned int target_freq); +void dram_pll_init(unsigned int drate); #endif /* __DRAM_H__ */ diff --git a/plat/imx/common/sip_svc.c b/plat/imx/common/sip_svc.c index b8f918e9..db14773e 100644 --- a/plat/imx/common/sip_svc.c +++ b/plat/imx/common/sip_svc.c @@ -116,17 +116,10 @@ uintptr_t imx_svc_smc_handler(uint32_t smc_fid, { NOTICE("smc_fid is %x\n", smc_fid); switch (smc_fid) { -#ifdef PLAT_IMX8M - case FSL_SIP_DDR_DVFS: - SMC_RET1(handle, lpddr4_dvfs_handler(smc_fid, x1, x2, x3)); - break; -#endif -#if defined(PLAT_IMX8MM) +#if defined(PLAT_IMX8M) || defined(PLAT_IMX8MM) case FSL_SIP_DDR_DVFS: SMC_RET1(handle, dram_dvfs_handler(smc_fid, x1, x2, x3)); break; -#endif -#if defined(PLAT_IMX8M) || defined(PLAT_IMX8MM) case FSL_SIP_GPC: SMC_RET1(handle, imx_gpc_handler(smc_fid, x1, x2, x3)); break; |