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>
diff --git a/drivers/thermal/mnh-clk.c b/drivers/thermal/mnh-clk.c
index 8d82750..747f419 100644
--- a/drivers/thermal/mnh-clk.c
+++ b/drivers/thermal/mnh-clk.c
@@ -87,6 +87,7 @@
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 @@
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 @@
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;