From c290a9e1664628a13a5e75e2400c5cc17882fbba Mon Sep 17 00:00:00 2001 From: Bai Ping Date: Mon, 29 Oct 2018 18:33:58 +0800 Subject: 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 --- plat/imx/common/imx8m/clock.c | 27 +++++++++ plat/imx/common/imx8m/dram.c | 100 ++++++++++++++++++++++++++++++- plat/imx/common/imx8m/lpddr4_dvfs.c | 16 +++-- plat/imx/common/imx8m/lpddr4_retention.c | 4 +- plat/imx/common/include/dram.h | 6 +- plat/imx/common/sip_svc.c | 9 +-- plat/imx/imx8mq/ddr/lpddr4_dvfs.c | 3 - plat/imx/imx8mq/gpc.c | 5 +- plat/imx/imx8mq/imx8mq_bl31_setup.c | 6 +- plat/imx/imx8mq/include/ddrc.h | 27 +++++++++ plat/imx/imx8mq/include/platform_def.h | 6 ++ plat/imx/imx8mq/platform.mk | 14 +++-- 12 files changed, 193 insertions(+), 30 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; diff --git a/plat/imx/imx8mq/ddr/lpddr4_dvfs.c b/plat/imx/imx8mq/ddr/lpddr4_dvfs.c index 7adbf924..c7702290 100644 --- a/plat/imx/imx8mq/ddr/lpddr4_dvfs.c +++ b/plat/imx/imx8mq/ddr/lpddr4_dvfs.c @@ -109,6 +109,3 @@ int lpddr4_dvfs_handler(uint32_t smc_fid, return 0; } - - - diff --git a/plat/imx/imx8mq/gpc.c b/plat/imx/imx8mq/gpc.c index a094bd65..40d303c1 100644 --- a/plat/imx/imx8mq/gpc.c +++ b/plat/imx/imx8mq/gpc.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -391,10 +392,10 @@ void imx_set_sys_lpm(bool retention) SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN); /* DDR enter retention */ - ddrc_enter_retention(); + dram_enter_retention(); } else { /* DDR exit retention */ - ddrc_exit_retention(); + dram_exit_retention(); } mmio_write_32(IMX_GPC_BASE + 0x14, val); diff --git a/plat/imx/imx8mq/imx8mq_bl31_setup.c b/plat/imx/imx8mq/imx8mq_bl31_setup.c index 5fc21a56..46a4d76d 100644 --- a/plat/imx/imx8mq/imx8mq_bl31_setup.c +++ b/plat/imx/imx8mq/imx8mq_bl31_setup.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +61,7 @@ static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; + /* get SPSR for BL33 entry */ static uint32_t get_spsr_for_bl33_entry(void) { @@ -291,8 +294,7 @@ void bl31_platform_setup(void) /* gpc init */ imx_gpc_init(); - /* switch DDR frequency to 3200 mts */ - lpddr4_switch_to_3200(); + dram_info_init(SAVED_DRAM_TIMING_BASE); } entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type) diff --git a/plat/imx/imx8mq/include/ddrc.h b/plat/imx/imx8mq/include/ddrc.h index 8eb42fd8..ed6ebfa1 100644 --- a/plat/imx/imx8mq/include/ddrc.h +++ b/plat/imx/imx8mq/include/ddrc.h @@ -297,6 +297,33 @@ #define DDRC_DFITMG3_SHADOW(X) (DDRC_IPS_BASE_ADDR(X) + 0x21b8) #define DDRC_ODTCFG_SHADOW(X) (DDRC_IPS_BASE_ADDR(X) + 0x2240) +#define DRC_PERF_MON_BASE_ADDR(X) 0x3d800000 + (X * 0x2000000) +#define DRC_PERF_MON_CNT0_CTL(X) DRC_PERF_MON_BASE_ADDR(X) + 0x0 +#define DRC_PERF_MON_CNT1_CTL(X) DRC_PERF_MON_BASE_ADDR(X) + 0x4 +#define DRC_PERF_MON_CNT2_CTL(X) DRC_PERF_MON_BASE_ADDR(X) + 0x8 +#define DRC_PERF_MON_CNT3_CTL(X) DRC_PERF_MON_BASE_ADDR(X) + 0xC +#define DRC_PERF_MON_CNT0_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x20 +#define DRC_PERF_MON_CNT1_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x24 +#define DRC_PERF_MON_CNT2_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x28 +#define DRC_PERF_MON_CNT3_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x2C +#define DRC_PERF_MON_DPCR_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x30 +#define DRC_PERF_MON_MRR0_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x40 +#define DRC_PERF_MON_MRR1_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x44 +#define DRC_PERF_MON_MRR2_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x48 +#define DRC_PERF_MON_MRR3_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x4C +#define DRC_PERF_MON_MRR4_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x50 +#define DRC_PERF_MON_MRR5_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x54 +#define DRC_PERF_MON_MRR6_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x58 +#define DRC_PERF_MON_MRR7_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x5C +#define DRC_PERF_MON_MRR8_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x60 +#define DRC_PERF_MON_MRR9_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x64 +#define DRC_PERF_MON_MRR10_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x68 +#define DRC_PERF_MON_MRR11_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x6C +#define DRC_PERF_MON_MRR12_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x70 +#define DRC_PERF_MON_MRR13_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x74 +#define DRC_PERF_MON_MRR14_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x78 +#define DRC_PERF_MON_MRR15_DAT(X) DRC_PERF_MON_BASE_ADDR(X) + 0x7C + #define IP2APB_DDRPHY_IPS_BASE_ADDR(X) (0x3c000000 + (X * 0x2000000)) #define dwc_ddrphy_apb_rd(addr) mmio_read_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * (addr)) #define dwc_ddrphy_apb_wr(addr, val) mmio_write_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * (addr), val) diff --git a/plat/imx/imx8mq/include/platform_def.h b/plat/imx/imx8mq/include/platform_def.h index f2c3d112..488175be 100644 --- a/plat/imx/imx8mq/include/platform_def.h +++ b/plat/imx/imx8mq/include/platform_def.h @@ -69,6 +69,12 @@ #define IMX_DDR_IPS_BASE 0x3d000000 #define IMX_ROM_BASE 0x0 +#define SAVED_DRAM_TIMING_BASE 0x40000000 + +#define HW_DRAM_PLL_CFG0 (IMX_ANAMIX_BASE + 0x60) +#define HW_DRAM_PLL_CFG1 (IMX_ANAMIX_BASE + 0x64) +#define HW_DRAM_PLL_CFG2 (IMX_ANAMIX_BASE + 0x68) + #define OCRAM_S_BASE 0x00180000 #define OCRAM_S_SIZE 0x8000 #define OCRAM_S_LIMIT (OCRAM_S_BASE + OCRAM_S_SIZE) diff --git a/plat/imx/imx8mq/platform.mk b/plat/imx/imx8mq/platform.mk index 93d61c41..456d7ced 100644 --- a/plat/imx/imx8mq/platform.mk +++ b/plat/imx/imx8mq/platform.mk @@ -7,11 +7,13 @@ PLAT_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \ plat/common/plat_gicv3.c \ plat/imx/common/plat_imx8_gic.c -PLAT_DDR_SOURCES := plat/imx/imx8mq/ddr/lpddr4_ddrc_cfg.c \ - plat/imx/imx8mq/ddr/lpddr4_phy_cfg.c \ - plat/imx/imx8mq/ddr/lpddr4_dvfs.c \ - plat/imx/imx8mq/ddr/lpddr4_swffc.c \ - plat/imx/imx8mq/ddr/lpddr4_retention.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 \ + plat/imx/common/imx8m/ddr4_dvfs.c BL31_SOURCES += plat/imx/common/imx8_helpers.S \ plat/imx/common/mxcuart_console.S \ @@ -32,7 +34,7 @@ BL31_SOURCES += plat/imx/common/imx8_helpers.S \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ ${PLAT_GIC_SOURCES} \ - ${PLAT_DDR_SOURCES} \ + ${PLAT_DRAM_SOURCES} \ drivers/arm/tzc/tzc380.c ENABLE_PLAT_COMPAT := 0 -- cgit v1.2.3