diff options
author | Anthony Loeppert <anthony.loeppert@intel.com> | 2018-10-25 22:00:50 -0700 |
---|---|---|
committer | Cheng Gu <gucheng@google.com> | 2019-06-27 14:32:52 -0700 |
commit | a0def480a5ad23e5028873608ece311f2ba2ea24 (patch) | |
tree | d7115d57a5a3c832ecb5b76307264eaa892f935a | |
parent | 2e6be2e883dec3e24229627abe91ad4396c8d49f (diff) | |
download | arm64-a0def480a5ad23e5028873608ece311f2ba2ea24.tar.gz |
Minimize ddr auto low power mode reg accesses.
The refresh worker thread toggles auto low pwr on and off
periodically.
In rare cases a hang was observed manifesting as an AXI
interrupt while the memory system is in its deepest
sleep state - see SCU registers DBG_STATUS and IRQ status.
Based on register dumps, analysis pointed to a hang in
mnh_ddr_disable_lp upon sending the exit lp command.
Following up on this theory, the entry/exit from LP mode
was scrutinized and this patch is the result of minimizing
register accesses with respect said LP mode.
Disable/enable lp method as per cadence recommendation
Bug: 111703181
Change-Id: Iddd4733cbd8a119ec26bbef7e5c381269d727fc3
Signed-off-by: Anthony Loeppert <anthony.loeppert@intel.com>
(cherry picked from commit 765eccf324294e6700c9574912316c23d8d4695c)
-rw-r--r-- | drivers/thermal/mnh-clk.c | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/drivers/thermal/mnh-clk.c b/drivers/thermal/mnh-clk.c index 523a7dea1c36..b3d59a8e6c74 100644 --- a/drivers/thermal/mnh-clk.c +++ b/drivers/thermal/mnh-clk.c @@ -87,6 +87,7 @@ HW_OUT(mnh_dev->ddraddr, DDR_CTL, reg, val) int mnh_ddr_clr_int_status(void); static void mnh_ddr_adjust_refresh_worker(struct work_struct *work); static void mnh_ddr_disable_lp(void); +static u8 lp_counters[4]; enum mnh_refclk_type { REFCLK_KHZ_19200 = 0, @@ -972,18 +973,34 @@ static void mnh_ddr_enable_lp(void) MNH_DDR_CTL_OUTf(124, LP_AUTO_SR_MC_GATE_IDLE, sleep_val[fsp]); - MNH_DDR_CTL_OUTf(122, LP_AUTO_MEM_GATE_EN, 0x4); - MNH_DDR_CTL_OUTf(122, LP_AUTO_ENTRY_EN, 0x4); - MNH_DDR_CTL_OUTf(122, LP_AUTO_EXIT_EN, 0xF); + MNH_DDR_CTL_OUTf(123, LP_AUTO_PD_IDLE, lp_counters[0]); + MNH_DDR_CTL_OUTf(123, LP_AUTO_SRPD_LITE_IDLE, lp_counters[1]); + MNH_DDR_CTL_OUTf(124, LP_AUTO_SR_IDLE, lp_counters[2]); + MNH_DDR_CTL_OUTf(124, LP_AUTO_SR_MC_GATE_IDLE, lp_counters[3]); + + if (MNH_DDR_CTL_INf(122, LP_AUTO_EXIT_EN) == 0) + MNH_DDR_CTL_OUTf(122, LP_AUTO_EXIT_EN, 0xF); + + if (MNH_DDR_CTL_INf(122, LP_AUTO_MEM_GATE_EN) == 0) + MNH_DDR_CTL_OUTf(122, LP_AUTO_MEM_GATE_EN, 0x4); + + if (MNH_DDR_CTL_INf(122, LP_AUTO_ENTRY_EN) == 0) + MNH_DDR_CTL_OUTf(122, LP_AUTO_ENTRY_EN, 0x4); } static void mnh_ddr_disable_lp(void) { dev_dbg(mnh_dev->dev, "%s\n", __func__); - MNH_DDR_CTL_OUTf(124, LP_AUTO_SR_MC_GATE_IDLE, 0x00); - MNH_DDR_CTL_OUTf(122, LP_AUTO_MEM_GATE_EN, 0x0); + lp_counters[0] = MNH_DDR_CTL_INf(123, LP_AUTO_PD_IDLE); + lp_counters[1] = MNH_DDR_CTL_INf(123, LP_AUTO_SRPD_LITE_IDLE); + lp_counters[2] = MNH_DDR_CTL_INf(124, LP_AUTO_SR_IDLE); + lp_counters[3] = MNH_DDR_CTL_INf(124, LP_AUTO_SR_MC_GATE_IDLE); + + MNH_DDR_CTL_OUTf(123, LP_AUTO_PD_IDLE, 0x0); + MNH_DDR_CTL_OUTf(123, LP_AUTO_SRPD_LITE_IDLE, 0x0); + MNH_DDR_CTL_OUTf(124, LP_AUTO_SR_IDLE, 0x0); + MNH_DDR_CTL_OUTf(124, LP_AUTO_SR_MC_GATE_IDLE, 0x0); MNH_DDR_CTL_OUTf(122, LP_AUTO_ENTRY_EN, 0x0); - MNH_DDR_CTL_OUTf(122, LP_AUTO_EXIT_EN, 0x0); mnh_ddr_send_lp_cmd(LP_CMD_EXIT_LP); } @@ -1139,6 +1156,10 @@ static void mnh_ddr_adjust_refresh_worker(struct work_struct *work) int ret = 0; int got_tuf = 0; + /* skip the refresh rate update if the DRAM is in low power state */ + if ((MNH_DDR_CTL_INf(121, LP_STATE) & 0xF) > 0x7) + goto refresh_again; + ret = mnh_ddr_read_mode_reg(4, &val0, &val1); mnh_dev->ddr_mrr4 = (u32)val1 << 16 | (u32)val0; |