summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Loeppert <anthony.loeppert@intel.com>2018-10-25 22:00:50 -0700
committerCheng Gu <gucheng@google.com>2019-06-27 14:32:52 -0700
commita0def480a5ad23e5028873608ece311f2ba2ea24 (patch)
treed7115d57a5a3c832ecb5b76307264eaa892f935a
parent2e6be2e883dec3e24229627abe91ad4396c8d49f (diff)
downloadarm64-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.c33
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;