2018-04-12 03:59:04

by Keerthy

[permalink] [raw]
Subject: [PATCH 00/14] arm: OMAP: AM437X: Save restores patches for rtc mode with DDR In self-refresh

RTC plus DDR in self-refresh is power a saving mode where in the entire
system including the different voltage rails from PMIC are shutdown except
the ones feeding on to RTC and DDR. DDR is kept in self-refresh hence the
contents are preserved. RTC ALARM2 is connected to PMIC_EN line once
we the ALARM2 is triggered we enter the mode with DDR in self-refresh
and RTC Ticking. After a predetermined time an RTC ALARM1 triggers waking
up the system. The control goes to bootloader. The bootloader then checks
RTC scratchpad registers to confirm it was an rtc_only wakeup and follows
a different path, configure bare minimal clocks for ddr and then jumps to
the resume address in another RTC scratchpad registers and transfers the
control to Kernel. Kernel then restores the saved context.

This series is a prerequisite for the rtc mode with DDR in self
refresh mode for am437x series of SoCs. As all the voltage domains
are shut off apart from RTC and DDR is kept in self refresh
additional save/restores are needed.

The series applies cleanly against linux-next branch.

This mode works only with u-boot built with am43xx_evm_rtconly_defconfig

Dave Gerlach (5):
memory: ti-emif-sram: Add resume function to recopy sram code
ARM: OMAP2+: omap_hwmod: Introduce HWMOD_NEEDS_REIDLE
gpio: omap: Restore power_mode configuration at resume time
ARM: hwmod: RTC: Don't assume lock/unlock will be called with irq
enabled
ARM: OMAP2+: prm44xx: Introduce context save/restore for am43 PRCM IO

Keerthy (1):
OMAP: CLK: CLKSRC: Add suspend resume hooks

Russ Dill (7):
ARM: OMAP2: Add functions to save and restore clockdomain context
en-masse.
ARM: OMAP2: Add functions to save and restore omap hwmod context
en-masse.
ARM: OMAP2: Add functions to save and restore powerdomain context
ARM: AM33XX: Add functions to save/restore am33xx control registers.
ARM: OMAP2: Add functions to save and restore pinctrl context.
ARM: OMAP2: Drop the concept of certain power domains not being able
to lose context.
gpio: omap: Drop the concept of gpio banks not being able to lose
context.

Tero Kristo (1):
ARM: AM43XX: Add functions to save/restore am43xx control registers

arch/arm/mach-omap2/clockdomain.c | 46 +++++
arch/arm/mach-omap2/clockdomain.h | 8 +
arch/arm/mach-omap2/cm33xx.c | 53 ++++++
arch/arm/mach-omap2/cminst44xx.c | 43 +++++
arch/arm/mach-omap2/control.c | 172 ++++++++++++++++++
arch/arm/mach-omap2/control.h | 65 +++++++
arch/arm/mach-omap2/omap_device.c | 50 +++++
arch/arm/mach-omap2/omap_device.h | 1 +
arch/arm/mach-omap2/omap_hwmod.c | 202 +++++++++++++++++++++
arch/arm/mach-omap2/omap_hwmod.h | 21 +++
.../mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c | 14 +-
arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 3 +-
arch/arm/mach-omap2/omap_hwmod_reset.c | 12 +-
arch/arm/mach-omap2/powerdomain.c | 75 +++++---
arch/arm/mach-omap2/powerdomain.h | 8 +-
arch/arm/mach-omap2/prm.h | 2 +
arch/arm/mach-omap2/prm33xx.c | 31 ++++
arch/arm/mach-omap2/prm44xx.c | 79 ++++++++
arch/arm/mach-omap2/timer.c | 37 ++++
drivers/gpio/gpio-omap.c | 40 ++--
drivers/memory/ti-emif-pm.c | 24 +++
drivers/pinctrl/core.c | 1 +
drivers/pinctrl/core.h | 1 -
drivers/pinctrl/pinctrl-single.c | 50 +++++
drivers/pinctrl/pinmux.c | 22 +++
include/linux/pinctrl/pinctrl.h | 7 +
include/linux/pinctrl/pinmux.h | 16 ++
include/linux/platform_data/gpio-omap.h | 1 -
28 files changed, 1019 insertions(+), 65 deletions(-)

--
1.9.1



2018-04-12 03:59:04

by Keerthy

[permalink] [raw]
Subject: [PATCH 04/14] ARM: OMAP2: Add functions to save and restore omap hwmod context en-masse.

From: Russ Dill <[email protected]>

This is used to support suspend modes like RTC-only and hibernate where
the state of these registers is lost.

After the PRCM loses context in the case of an RTC+DDR cycle omap_hwmod
attempts to return all hwmods to their previous state, however certain
hwmods cannot just be disabled when in their default state, which is why
they need the special handling present in that patch when no driver is
present.

In RTC+DDR mode, even if all drivers are present, the modules are all
returned to their previous state before any driver resume happens so we
will still face the issue described above. This can be prevented by
calling _reidle on all hwmods that need it for any module that is being
disabled to return to it's previous state.

Signed-off-by: Dave Gerlach <[email protected]>
Signed-off-by: Russ Dill <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
arch/arm/mach-omap2/omap_hwmod.c | 67 ++++++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/omap_hwmod.h | 4 +++
2 files changed, 71 insertions(+)

diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 90ad8e7..f6782b4 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -4096,3 +4096,70 @@ const char *omap_hwmod_get_main_clk(struct omap_hwmod *oh)

return oh->main_clk;
}
+
+/**
+ * omap_hwmod_save_context - Saves the HW reset line state of submodules
+ * @oh: struct omap_hwmod *
+ * @unused: (unused, caller should pass NULL)
+ *
+ * Saves the HW reset line state of all the submodules in the hwmod
+ */
+static int omap_hwmod_save_context(struct omap_hwmod *oh, void *unused)
+{
+ int i;
+
+ for (i = 0; i < oh->rst_lines_cnt; i++)
+ oh->rst_lines[i].context =
+ _read_hardreset(oh, oh->rst_lines[i].name);
+ return 0;
+}
+
+/**
+ * omap_hwmod_restore_context - Restores the HW reset line state of submodules
+ * @oh: struct omap_hwmod *
+ * @unused: (unused, caller should pass NULL)
+ *
+ * Restores the HW reset line state of all the submodules in the hwmod
+ */
+static int omap_hwmod_restore_context(struct omap_hwmod *oh, void *unused)
+{
+ int i;
+
+ for (i = 0; i < oh->rst_lines_cnt; i++)
+ if (oh->rst_lines[i].context)
+ _assert_hardreset(oh, oh->rst_lines[i].name);
+ else
+ _deassert_hardreset(oh, oh->rst_lines[i].name);
+
+ if (oh->_state == _HWMOD_STATE_ENABLED) {
+ if (soc_ops.enable_module)
+ soc_ops.enable_module(oh);
+ } else {
+ if (oh->flags & HWMOD_NEEDS_REIDLE)
+ _reidle(oh);
+ else if (soc_ops.disable_module)
+ soc_ops.disable_module(oh);
+ }
+
+ return 0;
+}
+
+/**
+ * omap_hwmods_save_context - Saves the HW reset line state for all hwmods
+ *
+ * Saves the HW reset line state of all the registered hwmods
+ */
+void omap_hwmods_save_context(void)
+{
+ omap_hwmod_for_each(omap_hwmod_save_context, NULL);
+}
+
+/**
+ * omap_hwmods_restore_context - Restores the HW reset line state for all hwmods
+ *
+ * Restores the HW reset line state of all the registered hwmods
+ */
+void omap_hwmods_restore_context(void)
+{
+ omap_hwmod_for_each(omap_hwmod_restore_context, NULL);
+}
diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
index f35638b..b5e050e 100644
--- a/arch/arm/mach-omap2/omap_hwmod.h
+++ b/arch/arm/mach-omap2/omap_hwmod.h
@@ -168,6 +168,7 @@ struct omap_hwmod_rst_info {
const char *name;
u8 rst_shift;
u8 st_shift;
+ u8 context;
};

/**
@@ -678,6 +679,9 @@ int omap_hwmod_for_each_by_class(const char *classname,

const char *omap_hwmod_get_main_clk(struct omap_hwmod *oh);

+void omap_hwmods_save_context(void);
+void omap_hwmods_restore_context(void);
+
/*
*
*/
--
1.9.1


2018-04-12 03:59:04

by Keerthy

[permalink] [raw]
Subject: [PATCH 07/14] ARM: AM43XX: Add functions to save/restore am43xx control registers

From: Tero Kristo <[email protected]>

These registers are part of the wkup domain and are lost during RTC only
suspend and also hibernation, so storing/restoring their state is
necessary.

Signed-off-by: Tero Kristo <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
arch/arm/mach-omap2/control.c | 94 +++++++++++++++++++++++++++++++++++++++++--
arch/arm/mach-omap2/control.h | 15 ++++++-
2 files changed, 105 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index d92aa9a..d094ae3 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -622,7 +622,8 @@ void __init omap3_ctrl_init(void)

#endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */

-#if defined(CONFIG_SOC_AM33XX) && defined(CONFIG_PM)
+#if defined(CONFIG_PM)
+#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
static unsigned long am33xx_control_reg_offsets[] = {
AM33XX_CONTROL_SYSCONFIG_OFFSET,
AM33XX_CONTROL_STATUS_OFFSET,
@@ -674,7 +675,65 @@ void __init omap3_ctrl_init(void)
AM33XX_CONTROL_RESET_ISO_OFFSET,
};

-static u32 am33xx_control_vals[ARRAY_SIZE(am33xx_control_reg_offsets)];
+static unsigned long am43xx_control_reg_offsets[] = {
+ AM33XX_CONTROL_SYSCONFIG_OFFSET,
+ AM33XX_CONTROL_STATUS_OFFSET,
+ AM43XX_CONTROL_MPU_L2_CTRL_OFFSET,
+ AM33XX_CONTROL_CORE_SLDO_CTRL_OFFSET,
+ AM33XX_CONTROL_MPU_SLDO_CTRL_OFFSET,
+ AM33XX_CONTROL_CLK32KDIVRATIO_CTRL_OFFSET,
+ AM33XX_CONTROL_BANDGAP_CTRL_OFFSET,
+ AM33XX_CONTROL_BANDGAP_TRIM_OFFSET,
+ AM33XX_CONTROL_PLL_CLKINPULOW_CTRL_OFFSET,
+ AM33XX_CONTROL_MOSC_CTRL_OFFSET,
+ AM33XX_CONTROL_DEEPSLEEP_CTRL_OFFSET,
+ AM43XX_CONTROL_DISPLAY_PLL_SEL_OFFSET,
+ AM33XX_CONTROL_INIT_PRIORITY_0_OFFSET,
+ AM33XX_CONTROL_INIT_PRIORITY_1_OFFSET,
+ AM33XX_CONTROL_TPTC_CFG_OFFSET,
+ AM33XX_CONTROL_USB_CTRL0_OFFSET,
+ AM33XX_CONTROL_USB_CTRL1_OFFSET,
+ AM43XX_CONTROL_USB_CTRL2_OFFSET,
+ AM43XX_CONTROL_GMII_SEL_OFFSET,
+ AM43XX_CONTROL_MPUSS_CTRL_OFFSET,
+ AM43XX_CONTROL_TIMER_CASCADE_CTRL_OFFSET,
+ AM43XX_CONTROL_PWMSS_CTRL_OFFSET,
+ AM33XX_CONTROL_MREQPRIO_0_OFFSET,
+ AM33XX_CONTROL_MREQPRIO_1_OFFSET,
+ AM33XX_CONTROL_HW_EVENT_SEL_GRP1_OFFSET,
+ AM33XX_CONTROL_HW_EVENT_SEL_GRP2_OFFSET,
+ AM33XX_CONTROL_HW_EVENT_SEL_GRP3_OFFSET,
+ AM33XX_CONTROL_HW_EVENT_SEL_GRP4_OFFSET,
+ AM33XX_CONTROL_SMRT_CTRL_OFFSET,
+ AM33XX_CONTROL_MPUSS_HW_DEBUG_SEL_OFFSET,
+ AM43XX_CONTROL_CQDETECT_STS_OFFSET,
+ AM43XX_CONTROL_CQDETECT_STS2_OFFSET,
+ AM43XX_CONTROL_VTP_CTRL_OFFSET,
+ AM33XX_CONTROL_VREF_CTRL_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_0_3_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_4_7_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_8_11_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_12_15_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_16_19_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_20_23_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_24_27_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_28_31_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_32_35_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_36_39_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_40_43_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_44_47_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_48_51_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_52_55_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_56_59_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_60_63_OFFSET,
+ AM33XX_CONTROL_TIMER_EVT_CAPT_OFFSET,
+ AM33XX_CONTROL_ECAP_EVT_CAPT_OFFSET,
+ AM33XX_CONTROL_ADC_EVT_CAPT_OFFSET,
+ AM43XX_CONTROL_ADC1_EVT_CAPT_OFFSET,
+ AM33XX_CONTROL_RESET_ISO_OFFSET,
+};
+
+static u32 am33xx_control_vals[ARRAY_SIZE(am43xx_control_reg_offsets)];

/**
* am33xx_control_save_context - Save the wakeup domain registers
@@ -703,7 +762,36 @@ void am33xx_control_restore_context(void)
omap_ctrl_writel(am33xx_control_vals[i],
am33xx_control_reg_offsets[i]);
}
-#endif /* CONFIG_SOC_AM33XX && CONFIG_PM */
+
+/**
+ * am43xx_control_save_context - Save the wakeup domain registers
+ *
+ * Save the wkup domain registers
+ */
+void am43xx_control_save_context(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(am43xx_control_reg_offsets); i++)
+ am33xx_control_vals[i] =
+ omap_ctrl_readl(am43xx_control_reg_offsets[i]);
+}
+
+/**
+ * am43xx_control_restore_context - Restore the wakeup domain registers
+ *
+ * Restore the wkup domain registers
+ */
+void am43xx_control_restore_context(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(am43xx_control_reg_offsets); i++)
+ omap_ctrl_writel(am33xx_control_vals[i],
+ am43xx_control_reg_offsets[i]);
+}
+#endif /* CONFIG_PM */
+#endif /* CONFIG_SOC_AM33XX || CONFIG_SOC_AM43XX */

struct control_init_data {
int index;
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index 4c50199..46ea820 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -409,9 +409,10 @@
#define AM33XX_DEV_FEATURE 0x604
#define AM33XX_SGX_MASK BIT(29)

-/* Additional AM33XX CONTROL registers */
+/* Additional AM33XX/AM43XX CONTROL registers */
#define AM33XX_CONTROL_SYSCONFIG_OFFSET 0x0010
#define AM33XX_CONTROL_STATUS_OFFSET 0x0040
+#define AM43XX_CONTROL_MPU_L2_CTRL_OFFSET 0x01e0
#define AM33XX_CONTROL_CORTEX_VBBLDO_CTRL_OFFSET 0x041c
#define AM33XX_CONTROL_CORE_SLDO_CTRL_OFFSET 0x0428
#define AM33XX_CONTROL_MPU_SLDO_CTRL_OFFSET 0x042c
@@ -422,6 +423,7 @@
#define AM33XX_CONTROL_MOSC_CTRL_OFFSET 0x0468
#define AM33XX_CONTROL_RCOSC_CTRL_OFFSET 0x046c
#define AM33XX_CONTROL_DEEPSLEEP_CTRL_OFFSET 0x0470
+#define AM43XX_CONTROL_DISPLAY_PLL_SEL_OFFSET 0x0534
#define AM33XX_CONTROL_INIT_PRIORITY_0_OFFSET 0x0608
#define AM33XX_CONTROL_INIT_PRIORITY_1_OFFSET 0x060c
#define AM33XX_CONTROL_MMU_CFG_OFFSET 0x0610
@@ -429,6 +431,11 @@
#define AM33XX_CONTROL_USB_CTRL0_OFFSET 0x0620
#define AM33XX_CONTROL_USB_CTRL1_OFFSET 0x0628
#define AM33XX_CONTROL_USB_WKUP_CTRL_OFFSET 0x0648
+#define AM43XX_CONTROL_USB_CTRL2_OFFSET 0x064c
+#define AM43XX_CONTROL_GMII_SEL_OFFSET 0x0650
+#define AM43XX_CONTROL_MPUSS_CTRL_OFFSET 0x0654
+#define AM43XX_CONTROL_TIMER_CASCADE_CTRL_OFFSET 0x0658
+#define AM43XX_CONTROL_PWMSS_CTRL_OFFSET 0x0664
#define AM33XX_CONTROL_MREQPRIO_0_OFFSET 0x0670
#define AM33XX_CONTROL_MREQPRIO_1_OFFSET 0x0674
#define AM33XX_CONTROL_HW_EVENT_SEL_GRP1_OFFSET 0x0690
@@ -437,6 +444,9 @@
#define AM33XX_CONTROL_HW_EVENT_SEL_GRP4_OFFSET 0x069c
#define AM33XX_CONTROL_SMRT_CTRL_OFFSET 0x06a0
#define AM33XX_CONTROL_MPUSS_HW_DEBUG_SEL_OFFSET 0x06a4
+#define AM43XX_CONTROL_CQDETECT_STS_OFFSET 0x0e00
+#define AM43XX_CONTROL_CQDETECT_STS2_OFFSET 0x0e08
+#define AM43XX_CONTROL_VTP_CTRL_OFFSET 0x0e0c
#define AM33XX_CONTROL_VREF_CTRL_OFFSET 0x0e14
#define AM33XX_CONTROL_TPCC_EVT_MUX_0_3_OFFSET 0x0f90
#define AM33XX_CONTROL_TPCC_EVT_MUX_4_7_OFFSET 0x0f94
@@ -457,6 +467,7 @@
#define AM33XX_CONTROL_TIMER_EVT_CAPT_OFFSET 0x0fd0
#define AM33XX_CONTROL_ECAP_EVT_CAPT_OFFSET 0x0fd4
#define AM33XX_CONTROL_ADC_EVT_CAPT_OFFSET 0x0fd8
+#define AM43XX_CONTROL_ADC1_EVT_CAPT_OFFSET 0x0fdc
#define AM33XX_CONTROL_RESET_ISO_OFFSET 0x1000

/* CONTROL OMAP STATUS register to identify OMAP3 features */
@@ -519,6 +530,8 @@
void omap2_set_globals_control(void __iomem *ctrl);
extern void am33xx_control_save_context(void);
extern void am33xx_control_restore_context(void);
+extern void am43xx_control_save_context(void);
+extern void am43xx_control_restore_context(void);
void __init omap3_control_legacy_iomap_init(void);
#else
#define omap_ctrl_readb(x) 0
--
1.9.1


2018-04-12 03:59:04

by Keerthy

[permalink] [raw]
Subject: [PATCH 02/14] ARM: OMAP2: Add functions to save and restore clockdomain context en-masse.

From: Russ Dill <[email protected]>

This is used to support suspend modes like RTC-only and hibernate where
the state of the registers controlling clockdomains is lost.

Signed-off-by: Russ Dill <[email protected]>
Signed-off-by: Dave Gerlach <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
arch/arm/mach-omap2/clockdomain.c | 46 +++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/clockdomain.h | 8 ++++++
arch/arm/mach-omap2/cm33xx.c | 53 +++++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/cminst44xx.c | 43 +++++++++++++++++++++++++++++++
4 files changed, 150 insertions(+)

diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index b79b1ca..0906380 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -1307,3 +1307,49 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
return 0;
}

+/**
+ * _clkdm_save_context - save the context for the control of this clkdm
+ *
+ * Due to a suspend or hibernation operation, the state of the registers
+ * controlling this clkdm will be lost, save their context.
+ */
+static int _clkdm_save_context(struct clockdomain *clkdm, void *ununsed)
+{
+ if (!arch_clkdm || !arch_clkdm->clkdm_save_context)
+ return -EINVAL;
+
+ return arch_clkdm->clkdm_save_context(clkdm);
+}
+
+/**
+ * _clkdm_restore_context - restore context for control of this clkdm
+ *
+ * Restore the register values for this clockdomain.
+ */
+static int _clkdm_restore_context(struct clockdomain *clkdm, void *ununsed)
+{
+ if (!arch_clkdm || !arch_clkdm->clkdm_restore_context)
+ return -EINVAL;
+
+ return arch_clkdm->clkdm_restore_context(clkdm);
+}
+
+/**
+ * clkdm_save_context - Saves the context for each registered clkdm
+ *
+ * Save the context for each registered clockdomain.
+ */
+void clkdm_save_context(void)
+{
+ clkdm_for_each(_clkdm_save_context, NULL);
+}
+
+/**
+ * clkdm_restore_context - Restores the context for each registered clkdm
+ *
+ * Restore the context for each registered clockdomain.
+ */
+void clkdm_restore_context(void)
+{
+ clkdm_for_each(_clkdm_restore_context, NULL);
+}
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h
index 24667a5..c7d0953 100644
--- a/arch/arm/mach-omap2/clockdomain.h
+++ b/arch/arm/mach-omap2/clockdomain.h
@@ -141,6 +141,7 @@ struct clockdomain {
int usecount;
int forcewake_count;
struct list_head node;
+ u32 context;
};

/**
@@ -159,6 +160,8 @@ struct clockdomain {
* @clkdm_deny_idle: Disable hw supervised idle transitions for clock domain
* @clkdm_clk_enable: Put the clkdm in right state for a clock enable
* @clkdm_clk_disable: Put the clkdm in right state for a clock disable
+ * @clkdm_save_context: Save the current clkdm context
+ * @clkdm_restore_context: Restore the clkdm context
*/
struct clkdm_ops {
int (*clkdm_add_wkdep)(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
@@ -175,6 +178,8 @@ struct clkdm_ops {
void (*clkdm_deny_idle)(struct clockdomain *clkdm);
int (*clkdm_clk_enable)(struct clockdomain *clkdm);
int (*clkdm_clk_disable)(struct clockdomain *clkdm);
+ int (*clkdm_save_context)(struct clockdomain *clkdm);
+ int (*clkdm_restore_context)(struct clockdomain *clkdm);
};

int clkdm_register_platform_funcs(struct clkdm_ops *co);
@@ -214,6 +219,9 @@ int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user),
int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh);
int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh);

+void clkdm_save_context(void);
+void clkdm_restore_context(void);
+
extern void __init omap242x_clockdomains_init(void);
extern void __init omap243x_clockdomains_init(void);
extern void __init omap3xxx_clockdomains_init(void);
diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c
index 1cc0247..084d454 100644
--- a/arch/arm/mach-omap2/cm33xx.c
+++ b/arch/arm/mach-omap2/cm33xx.c
@@ -72,6 +72,17 @@ static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
return v;
}

+static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
+{
+ u32 v;
+
+ v = am33xx_cm_read_reg(inst, idx);
+ v &= mask;
+ v >>= __ffs(mask);
+
+ return v;
+}
+
/**
* _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
* @inst: CM instance register offset (*_INST macro)
@@ -338,6 +349,46 @@ static u32 am33xx_cm_xlate_clkctrl(u8 part, u16 inst, u16 offset)
return cm_base.pa + inst + offset;
}

+/**
+ * am33xx_clkdm_save_context - Save the clockdomain transition context
+ * @clkdm: The clockdomain pointer whose context needs to be saved
+ *
+ * Save the clockdomain transition context.
+ */
+static int am33xx_clkdm_save_context(struct clockdomain *clkdm)
+{
+ clkdm->context = am33xx_cm_read_reg_bits(clkdm->cm_inst,
+ clkdm->clkdm_offs,
+ AM33XX_CLKTRCTRL_MASK);
+
+ return 0;
+}
+
+/**
+ * am33xx_restore_save_context - Restore the clockdomain transition context
+ * @clkdm: The clockdomain pointer whose context needs to be restored
+ *
+ * Restore the clockdomain transition context.
+ */
+static int am33xx_clkdm_restore_context(struct clockdomain *clkdm)
+{
+ switch (clkdm->context) {
+ case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
+ am33xx_clkdm_deny_idle(clkdm);
+ break;
+ case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
+ am33xx_clkdm_sleep(clkdm);
+ break;
+ case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
+ am33xx_clkdm_wakeup(clkdm);
+ break;
+ case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
+ am33xx_clkdm_allow_idle(clkdm);
+ break;
+ }
+ return 0;
+}
+
struct clkdm_ops am33xx_clkdm_operations = {
.clkdm_sleep = am33xx_clkdm_sleep,
.clkdm_wakeup = am33xx_clkdm_wakeup,
@@ -345,6 +396,8 @@ struct clkdm_ops am33xx_clkdm_operations = {
.clkdm_deny_idle = am33xx_clkdm_deny_idle,
.clkdm_clk_enable = am33xx_clkdm_clk_enable,
.clkdm_clk_disable = am33xx_clkdm_clk_disable,
+ .clkdm_save_context = am33xx_clkdm_save_context,
+ .clkdm_restore_context = am33xx_clkdm_restore_context,
};

static const struct cm_ll_data am33xx_cm_ll_data = {
diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c
index 7deefee..c11ac49 100644
--- a/arch/arm/mach-omap2/cminst44xx.c
+++ b/arch/arm/mach-omap2/cminst44xx.c
@@ -481,6 +481,47 @@ static u32 omap4_cminst_xlate_clkctrl(u8 part, u16 inst, u16 offset)
return _cm_bases[part].pa + inst + offset;
}

+/**
+ * omap4_clkdm_save_context - Save the clockdomain modulemode context
+ * @clkdm: The clockdomain pointer whose context needs to be saved
+ *
+ * Save the clockdomain modulemode context.
+ */
+static int omap4_clkdm_save_context(struct clockdomain *clkdm)
+{
+ clkdm->context = omap4_cminst_read_inst_reg(clkdm->prcm_partition,
+ clkdm->cm_inst,
+ clkdm->clkdm_offs +
+ OMAP4_CM_CLKSTCTRL);
+ clkdm->context &= OMAP4430_MODULEMODE_MASK;
+ return 0;
+}
+
+/**
+ * omap4_clkdm_restore_context - Restore the clockdomain modulemode context
+ * @clkdm: The clockdomain pointer whose context needs to be restored
+ *
+ * Restore the clockdomain modulemode context.
+ */
+static int omap4_clkdm_restore_context(struct clockdomain *clkdm)
+{
+ switch (clkdm->context) {
+ case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
+ omap4_clkdm_deny_idle(clkdm);
+ break;
+ case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
+ omap4_clkdm_sleep(clkdm);
+ break;
+ case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
+ omap4_clkdm_wakeup(clkdm);
+ break;
+ case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
+ omap4_clkdm_allow_idle(clkdm);
+ break;
+ }
+ return 0;
+}
+
struct clkdm_ops omap4_clkdm_operations = {
.clkdm_add_wkdep = omap4_clkdm_add_wkup_sleep_dep,
.clkdm_del_wkdep = omap4_clkdm_del_wkup_sleep_dep,
@@ -496,6 +537,8 @@ struct clkdm_ops omap4_clkdm_operations = {
.clkdm_deny_idle = omap4_clkdm_deny_idle,
.clkdm_clk_enable = omap4_clkdm_clk_enable,
.clkdm_clk_disable = omap4_clkdm_clk_disable,
+ .clkdm_save_context = omap4_clkdm_save_context,
+ .clkdm_restore_context = omap4_clkdm_restore_context,
};

struct clkdm_ops am43xx_clkdm_operations = {
--
1.9.1


2018-04-12 03:59:07

by Keerthy

[permalink] [raw]
Subject: [PATCH 10/14] gpio: omap: Drop the concept of gpio banks not being able to lose context.

From: Russ Dill <[email protected]>

It isn't much of a win, and with hibernation, everything loses context.

Signed-off-by: Russ Dill <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
drivers/gpio/gpio-omap.c | 38 ++++++++++++---------------------
include/linux/platform_data/gpio-omap.h | 1 -
2 files changed, 14 insertions(+), 25 deletions(-)

diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 35971a3..34fde30 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -68,7 +68,7 @@ struct gpio_bank {
bool dbck_enabled;
bool is_mpuio;
bool dbck_flag;
- bool loses_context;
+
bool context_valid;
int stride;
u32 width;
@@ -1198,15 +1198,9 @@ static int omap_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_OF_GPIO
bank->chip.of_node = of_node_get(node);
#endif
- if (node) {
- if (!of_property_read_bool(node, "ti,gpio-always-on"))
- bank->loses_context = true;
- } else {
- bank->loses_context = pdata->loses_context;
-
- if (bank->loses_context)
- bank->get_context_loss_count =
- pdata->get_context_loss_count;
+ if (!node) {
+ bank->get_context_loss_count =
+ pdata->get_context_loss_count;
}

if (bank->regs->set_dataout && bank->regs->clr_dataout)
@@ -1365,7 +1359,7 @@ static int omap_gpio_runtime_resume(struct device *dev)
* been initialised and so initialise it now. Also initialise
* the context loss count.
*/
- if (bank->loses_context && !bank->context_valid) {
+ if (!bank->context_valid) {
omap_gpio_init_context(bank);

if (bank->get_context_loss_count)
@@ -1386,17 +1380,13 @@ static int omap_gpio_runtime_resume(struct device *dev)
writel_relaxed(bank->context.risingdetect,
bank->base + bank->regs->risingdetect);

- if (bank->loses_context) {
- if (!bank->get_context_loss_count) {
- omap_gpio_restore_context(bank);
- } else {
- c = bank->get_context_loss_count(dev);
- if (c != bank->context_loss_count) {
- omap_gpio_restore_context(bank);
- } else {
- raw_spin_unlock_irqrestore(&bank->lock, flags);
- return 0;
- }
+ if (!bank->get_context_loss_count) {
+ omap_gpio_restore_context(bank);
+ } else {
+ c = bank->get_context_loss_count(bank->chip.parent);
+ if (c != bank->context_loss_count) {
+ raw_spin_unlock_irqrestore(&bank->lock, flags);
+ return 0;
}
}

@@ -1468,7 +1458,7 @@ void omap2_gpio_prepare_for_idle(int pwr_mode)
struct gpio_bank *bank;

list_for_each_entry(bank, &omap_gpio_list, node) {
- if (!BANK_USED(bank) || !bank->loses_context)
+ if (!BANK_USED(bank))
continue;

bank->power_mode = pwr_mode;
@@ -1482,7 +1472,7 @@ void omap2_gpio_resume_after_idle(void)
struct gpio_bank *bank;

list_for_each_entry(bank, &omap_gpio_list, node) {
- if (!BANK_USED(bank) || !bank->loses_context)
+ if (!BANK_USED(bank))
continue;

pm_runtime_get_sync(bank->chip.parent);
diff --git a/include/linux/platform_data/gpio-omap.h b/include/linux/platform_data/gpio-omap.h
index 8612855..77eb187 100644
--- a/include/linux/platform_data/gpio-omap.h
+++ b/include/linux/platform_data/gpio-omap.h
@@ -193,7 +193,6 @@ struct omap_gpio_platform_data {
int bank_width; /* GPIO bank width */
int bank_stride; /* Only needed for omap1 MPUIO */
bool dbck_flag; /* dbck required or not - True for OMAP3&4 */
- bool loses_context; /* whether the bank would ever lose context */
bool is_mpuio; /* whether the bank is of type MPUIO */
u32 non_wakeup_gpios;

--
1.9.1


2018-04-12 03:59:31

by Keerthy

[permalink] [raw]
Subject: [PATCH 11/14] gpio: omap: Restore power_mode configuration at resume time

From: Dave Gerlach <[email protected]>

Commit 2dc983c565e0 ("gpio/omap: cleanup prepare_for_idle and
resume_after_idle") introduces omap2_gpio_prepare_for_idle and
omap2_gpio_resume_after_idle to properly configure gpios that are used
as wake sources. When entering off mode, omap2_gpio_prepare_for_idle
can set a flag indicating off-mode entry is desired, however once this
flag is set it is never cleared, so any additional calls to this
function, regardless of the mode, have this flag set.

This patch restores the pwr_mode flag to 0 in
omap2_gpio_resume_after_idle to ensure the flag is not misconfigured
during non off-mode operation.

Signed-off-by: Dave Gerlach <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
drivers/gpio/gpio-omap.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 34fde30..84d664b 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1476,6 +1476,8 @@ void omap2_gpio_resume_after_idle(void)
continue;

pm_runtime_get_sync(bank->chip.parent);
+
+ bank->power_mode = 0;
}
}
#endif
--
1.9.1


2018-04-12 03:59:37

by Keerthy

[permalink] [raw]
Subject: [PATCH 13/14] ARM: hwmod: RTC: Don't assume lock/unlock will be called with irq enabled

From: Dave Gerlach <[email protected]>

When the RTC lock and unlock functions were introduced it was likely
assumed that they would always be called from irq enabled context, hence
the use of local_irq_disable/enable. This is no longer true as the
RTC+DDR path makes a late call during the suspend path after irqs
have been disabled to enable the RTC hwmod which calls both unlock and
lock, leading to IRQs being reenabled through the local_irq_enable call
in omap_hwmod_rtc_lock call.

To avoid this change the local_irq_disable/enable to
local_irq_save/restore to ensure that from whatever context this is
called the proper IRQ configuration is maintained.

Signed-off-by: Dave Gerlach <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
arch/arm/mach-omap2/omap_hwmod_reset.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_hwmod_reset.c b/arch/arm/mach-omap2/omap_hwmod_reset.c
index b68f9c0..d5ddba0 100644
--- a/arch/arm/mach-omap2/omap_hwmod_reset.c
+++ b/arch/arm/mach-omap2/omap_hwmod_reset.c
@@ -92,11 +92,13 @@ static void omap_rtc_wait_not_busy(struct omap_hwmod *oh)
*/
void omap_hwmod_rtc_unlock(struct omap_hwmod *oh)
{
- local_irq_disable();
+ unsigned long flags;
+
+ local_irq_save(flags);
omap_rtc_wait_not_busy(oh);
omap_hwmod_write(OMAP_RTC_KICK0_VALUE, oh, OMAP_RTC_KICK0_REG);
omap_hwmod_write(OMAP_RTC_KICK1_VALUE, oh, OMAP_RTC_KICK1_REG);
- local_irq_enable();
+ local_irq_restore(flags);
}

/**
@@ -110,9 +112,11 @@ void omap_hwmod_rtc_unlock(struct omap_hwmod *oh)
*/
void omap_hwmod_rtc_lock(struct omap_hwmod *oh)
{
- local_irq_disable();
+ unsigned long flags;
+
+ local_irq_save(flags);
omap_rtc_wait_not_busy(oh);
omap_hwmod_write(0x0, oh, OMAP_RTC_KICK0_REG);
omap_hwmod_write(0x0, oh, OMAP_RTC_KICK1_REG);
- local_irq_enable();
+ local_irq_restore(flags);
}
--
1.9.1


2018-04-12 04:00:13

by Keerthy

[permalink] [raw]
Subject: [PATCH 14/14] ARM: OMAP2+: prm44xx: Introduce context save/restore for am43 PRCM IO

From: Dave Gerlach <[email protected]>

There are two registers on am43x needed for IO daisy chain wake to work
properly, however currently after an RTC+DDR cycle they are lost. We
must take care to save and restore these before and after entering RTC
mode otherwise IO daisy chain wake will stop working from DeepSleep
after resuming.

Signed-off-by: Dave Gerlach <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
arch/arm/mach-omap2/prm.h | 2 ++
arch/arm/mach-omap2/prm44xx.c | 29 +++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)

diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h
index f0fb508..32e275f 100644
--- a/arch/arm/mach-omap2/prm.h
+++ b/arch/arm/mach-omap2/prm.h
@@ -179,6 +179,8 @@ int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod,
u32 omap_prm_vp_check_txdone(u8 vp_id);
void omap_prm_vp_clear_txdone(u8 vp_id);

+void am43xx_prm_save_context(void);
+void am43xx_prm_restore_context(void);
#endif


diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index 47b657c..0d1111e 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -57,6 +57,13 @@
.reconfigure_io_chain = &omap44xx_prm_reconfigure_io_chain,
};

+struct omap_prm_irq_context {
+ unsigned long irq_enable;
+ unsigned long pm_ctrl;
+};
+
+static struct omap_prm_irq_context omap_prm_context;
+
/*
* omap44xx_prm_reset_src_map - map from bits in the PRM_RSTST
* hardware register (which are specific to OMAP44xx SoCs) to reset
@@ -739,6 +746,28 @@ struct pwrdm_ops omap4_pwrdm_operations = {

static int omap44xx_prm_late_init(void);

+void am43xx_prm_save_context(void)
+{
+ omap_prm_context.irq_enable =
+ omap4_prm_read_inst_reg(AM43XX_PRM_OCP_SOCKET_INST,
+ omap4_prcm_irq_setup.mask);
+
+ omap_prm_context.pm_ctrl =
+ omap4_prm_read_inst_reg(AM43XX_PRM_DEVICE_INST,
+ omap4_prcm_irq_setup.pm_ctrl);
+}
+
+void am43xx_prm_restore_context(void)
+{
+ omap4_prm_write_inst_reg(omap_prm_context.irq_enable,
+ OMAP4430_PRM_OCP_SOCKET_INST,
+ omap4_prcm_irq_setup.mask);
+
+ omap4_prm_write_inst_reg(omap_prm_context.pm_ctrl,
+ AM43XX_PRM_DEVICE_INST,
+ omap4_prcm_irq_setup.pm_ctrl);
+}
+
/*
* XXX document
*/
--
1.9.1


2018-04-12 04:00:48

by Keerthy

[permalink] [raw]
Subject: [PATCH 09/14] ARM: OMAP2: Drop the concept of certain power domains not being able to lose context.

From: Russ Dill <[email protected]>

It isn't much of a win, and with hibernation, everything loses context.
So Drop the concept of certain power domains not being able to lose
context.

Signed-off-by: Russ Dill <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
arch/arm/mach-omap2/powerdomain.c | 41 ---------------------------------------
arch/arm/mach-omap2/powerdomain.h | 1 -
2 files changed, 42 deletions(-)

diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index ee693f6..f180d22 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -1160,47 +1160,6 @@ int pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
}

/**
- * pwrdm_can_ever_lose_context - can this powerdomain ever lose context?
- * @pwrdm: struct powerdomain *
- *
- * Given a struct powerdomain * @pwrdm, returns 1 if the powerdomain
- * can lose either memory or logic context or if @pwrdm is invalid, or
- * returns 0 otherwise. This function is not concerned with how the
- * powerdomain registers are programmed (i.e., to go off or not); it's
- * concerned with whether it's ever possible for this powerdomain to
- * go off while some other part of the chip is active. This function
- * assumes that every powerdomain can go to either ON or INACTIVE.
- */
-bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
-{
- int i;
-
- if (!pwrdm) {
- pr_debug("powerdomain: %s: invalid powerdomain pointer\n",
- __func__);
- return 1;
- }
-
- if (pwrdm->pwrsts & PWRSTS_OFF)
- return 1;
-
- if (pwrdm->pwrsts & PWRSTS_RET) {
- if (pwrdm->pwrsts_logic_ret & PWRSTS_OFF)
- return 1;
-
- for (i = 0; i < pwrdm->banks; i++)
- if (pwrdm->pwrsts_mem_ret[i] & PWRSTS_OFF)
- return 1;
- }
-
- for (i = 0; i < pwrdm->banks; i++)
- if (pwrdm->pwrsts_mem_on[i] & PWRSTS_OFF)
- return 1;
-
- return 0;
-}
-
-/**
* pwrdm_save_context - save powerdomain registers
*
* Register state is going to be lost due to a suspend or hibernate
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 9a907fb..a5bdc28 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -247,7 +247,6 @@ u8 pwrdm_get_valid_lp_state(struct powerdomain *pwrdm,
int pwrdm_pre_transition(struct powerdomain *pwrdm);
int pwrdm_post_transition(struct powerdomain *pwrdm);
int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
-bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);

extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 state);

--
1.9.1


2018-04-12 04:02:13

by Keerthy

[permalink] [raw]
Subject: [PATCH 05/14] ARM: OMAP2: Add functions to save and restore powerdomain context

From: Russ Dill <[email protected]>

The powerdomain control registers are stored in the WKUP powerdomain on
AM33XX/AM43XX, which is lost on RTC-only suspend and also hibernate. This
adds context save and restore functions for those registers.
Sometimes the powerdomain state does not need to change,
perhaps we only need to change memory retention states, so make
sure the restored state is different from the current state before we wait
for a transition.

Signed-off-by: Keerthy <[email protected]>
Signed-off-by: Dave Gerlach <[email protected]>
Signed-off-by: Russ Dill <[email protected]>
---
arch/arm/mach-omap2/powerdomain.c | 60 +++++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/powerdomain.h | 7 +++++
arch/arm/mach-omap2/prm33xx.c | 31 ++++++++++++++++++++
arch/arm/mach-omap2/prm44xx.c | 50 ++++++++++++++++++++++++++++++++
4 files changed, 148 insertions(+)

diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 76eb6ec..ee693f6 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -1199,3 +1199,63 @@ bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)

return 0;
}
+
+/**
+ * pwrdm_save_context - save powerdomain registers
+ *
+ * Register state is going to be lost due to a suspend or hibernate
+ * event. Save the powerdomain registers.
+ */
+static int pwrdm_save_context(struct powerdomain *pwrdm, void *unused)
+{
+ if (arch_pwrdm && arch_pwrdm->pwrdm_save_context)
+ arch_pwrdm->pwrdm_save_context(pwrdm);
+ return 0;
+}
+
+/**
+ * pwrdm_save_context - restore powerdomain registers
+ *
+ * Restore powerdomain control registers after a suspend or resume
+ * event.
+ */
+static int pwrdm_restore_context(struct powerdomain *pwrdm, void *unused)
+{
+ if (arch_pwrdm && arch_pwrdm->pwrdm_restore_context)
+ arch_pwrdm->pwrdm_restore_context(pwrdm);
+ return 0;
+}
+
+static int pwrdm_lost_power(struct powerdomain *pwrdm, void *unused)
+{
+ int state;
+
+ /*
+ * Power has been lost across all powerdomains, increment the
+ * counter.
+ */
+
+ state = pwrdm_read_pwrst(pwrdm);
+ if (state != PWRDM_POWER_OFF) {
+ pwrdm->state_counter[state]++;
+ pwrdm->state_counter[PWRDM_POWER_OFF]++;
+ }
+ pwrdm->state = state;
+
+ return 0;
+}
+
+void pwrdms_save_context(void)
+{
+ pwrdm_for_each(pwrdm_save_context, NULL);
+}
+
+void pwrdms_restore_context(void)
+{
+ pwrdm_for_each(pwrdm_restore_context, NULL);
+}
+
+void pwrdms_lost_power(void)
+{
+ pwrdm_for_each(pwrdm_lost_power, NULL);
+}
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 28a796c..9a907fb 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -144,6 +144,7 @@ struct powerdomain {
s64 timer;
s64 state_timer[PWRDM_MAX_PWRSTS];
#endif
+ u32 context;
};

/**
@@ -198,6 +199,8 @@ struct pwrdm_ops {
int (*pwrdm_set_lowpwrstchange)(struct powerdomain *pwrdm);
int (*pwrdm_wait_transition)(struct powerdomain *pwrdm);
int (*pwrdm_has_voltdm)(void);
+ void (*pwrdm_save_context)(struct powerdomain *pwrdm);
+ void (*pwrdm_restore_context)(struct powerdomain *pwrdm);
};

int pwrdm_register_platform_funcs(struct pwrdm_ops *custom_funcs);
@@ -273,4 +276,8 @@ u8 pwrdm_get_valid_lp_state(struct powerdomain *pwrdm,
extern void pwrdm_lock(struct powerdomain *pwrdm);
extern void pwrdm_unlock(struct powerdomain *pwrdm);

+extern void pwrdms_save_context(void);
+extern void pwrdms_restore_context(void);
+
+extern void pwrdms_lost_power(void);
#endif
diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c
index ebaf80d..d514166 100644
--- a/arch/arm/mach-omap2/prm33xx.c
+++ b/arch/arm/mach-omap2/prm33xx.c
@@ -342,6 +342,35 @@ static void am33xx_prm_global_warm_sw_reset(void)
AM33XX_PRM_RSTCTRL_OFFSET);
}

+static void am33xx_pwrdm_save_context(struct powerdomain *pwrdm)
+{
+ pwrdm->context = am33xx_prm_read_reg(pwrdm->prcm_offs,
+ pwrdm->pwrstctrl_offs);
+ /*
+ * Do not save LOWPOWERSTATECHANGE, writing a 1 indicates a request,
+ * reading back a 1 indicates a request in progress.
+ */
+ pwrdm->context &= ~AM33XX_LOWPOWERSTATECHANGE_MASK;
+}
+
+static void am33xx_pwrdm_restore_context(struct powerdomain *pwrdm)
+{
+ int st, ctrl;
+
+ st = am33xx_prm_read_reg(pwrdm->prcm_offs,
+ pwrdm->pwrstst_offs);
+
+ am33xx_prm_write_reg(pwrdm->context, pwrdm->prcm_offs,
+ pwrdm->pwrstctrl_offs);
+
+ /* Make sure we only wait for a transition if there is one */
+ st &= OMAP_POWERSTATEST_MASK;
+ ctrl = OMAP_POWERSTATEST_MASK & pwrdm->context;
+
+ if (st != ctrl)
+ am33xx_pwrdm_wait_transition(pwrdm);
+}
+
struct pwrdm_ops am33xx_pwrdm_operations = {
.pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst,
.pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst,
@@ -357,6 +386,8 @@ struct pwrdm_ops am33xx_pwrdm_operations = {
.pwrdm_set_mem_retst = am33xx_pwrdm_set_mem_retst,
.pwrdm_wait_transition = am33xx_pwrdm_wait_transition,
.pwrdm_has_voltdm = am33xx_check_vcvp,
+ .pwrdm_save_context = am33xx_pwrdm_save_context,
+ .pwrdm_restore_context = am33xx_pwrdm_restore_context,
};

static struct prm_ll_data am33xx_prm_ll_data = {
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index acb9593..47b657c 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -667,6 +667,54 @@ static int omap4_check_vcvp(void)
return 0;
}

+/**
+ * omap4_pwrdm_save_context - Saves the powerdomain state
+ * @pwrdm: pointer to individual powerdomain
+ *
+ * The function saves the powerdomain state control information.
+ * This is needed in rtc+ddr modes where we lose powerdomain context.
+ */
+static void omap4_pwrdm_save_context(struct powerdomain *pwrdm)
+{
+ pwrdm->context = omap4_prminst_read_inst_reg(pwrdm->prcm_partition,
+ pwrdm->prcm_offs,
+ pwrdm->pwrstctrl_offs);
+
+ /*
+ * Do not save LOWPOWERSTATECHANGE, writing a 1 indicates a request,
+ * reading back a 1 indicates a request in progress.
+ */
+ pwrdm->context &= ~OMAP4430_LOWPOWERSTATECHANGE_MASK;
+}
+
+/**
+ * omap4_pwrdm_restore_context - Restores the powerdomain state
+ * @pwrdm: pointer to individual powerdomain
+ *
+ * The function restores the powerdomain state control information.
+ * This is needed in rtc+ddr modes where we lose powerdomain context.
+ */
+static void omap4_pwrdm_restore_context(struct powerdomain *pwrdm)
+{
+ int st, ctrl;
+
+ st = omap4_prminst_read_inst_reg(pwrdm->prcm_partition,
+ pwrdm->prcm_offs,
+ pwrdm->pwrstctrl_offs);
+
+ omap4_prminst_write_inst_reg(pwrdm->context,
+ pwrdm->prcm_partition,
+ pwrdm->prcm_offs,
+ pwrdm->pwrstctrl_offs);
+
+ /* Make sure we only wait for a transition if there is one */
+ st &= OMAP_POWERSTATEST_MASK;
+ ctrl = OMAP_POWERSTATEST_MASK & pwrdm->context;
+
+ if (st != ctrl)
+ omap4_pwrdm_wait_transition(pwrdm);
+}
+
struct pwrdm_ops omap4_pwrdm_operations = {
.pwrdm_set_next_pwrst = omap4_pwrdm_set_next_pwrst,
.pwrdm_read_next_pwrst = omap4_pwrdm_read_next_pwrst,
@@ -685,6 +733,8 @@ struct pwrdm_ops omap4_pwrdm_operations = {
.pwrdm_set_mem_retst = omap4_pwrdm_set_mem_retst,
.pwrdm_wait_transition = omap4_pwrdm_wait_transition,
.pwrdm_has_voltdm = omap4_check_vcvp,
+ .pwrdm_save_context = omap4_pwrdm_save_context,
+ .pwrdm_restore_context = omap4_pwrdm_restore_context,
};

static int omap44xx_prm_late_init(void);
--
1.9.1


2018-04-12 04:02:22

by Keerthy

[permalink] [raw]
Subject: [PATCH 08/14] ARM: OMAP2: Add functions to save and restore pinctrl context.

From: Russ Dill <[email protected]>

This adds a pair of context save/restore functions to save/restore the
state of a set of pinctrl registers. This simplifies some of the AM33XX
PM code as some of the pinctrl registers are lost when the per power
domain loses power. The pincrtl code can perform the necessary
save/restore.

This will also be necessary for hibernation and RTC only sleep, as all
pinctrl registers all lost.

Signed-off-by: Russ Dill <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
drivers/pinctrl/core.c | 1 +
drivers/pinctrl/core.h | 1 -
drivers/pinctrl/pinctrl-single.c | 50 ++++++++++++++++++++++++++++++++++++++++
drivers/pinctrl/pinmux.c | 22 ++++++++++++++++++
include/linux/pinctrl/pinctrl.h | 7 ++++++
include/linux/pinctrl/pinmux.h | 16 +++++++++++++
6 files changed, 96 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index e5a3030..1a9ae64 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -119,6 +119,7 @@ struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname)

return NULL;
}
+EXPORT_SYMBOL_GPL(get_pinctrl_dev_from_devname);

struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np)
{
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index 8cf2eba..e587c29 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -226,7 +226,6 @@ int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev,

#endif /* CONFIG_GENERIC_PINCTRL_GROUPS */

-struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np);
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index a7c5eb3..2fc3317 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -144,6 +144,7 @@ struct pcs_soc_data {
* struct pcs_device - pinctrl device instance
* @res: resources
* @base: virtual address of the controller
+ * @saved_vals: saved values for the controller
* @size: size of the ioremapped area
* @dev: device entry
* @np: device tree node
@@ -172,6 +173,7 @@ struct pcs_soc_data {
struct pcs_device {
struct resource *res;
void __iomem *base;
+ void *saved_vals;
unsigned size;
struct device *dev;
struct device_node *np;
@@ -372,6 +374,52 @@ static int pcs_set_mux(struct pinctrl_dev *pctldev, unsigned fselector,
return 0;
}

+static int pcs_save_context(struct pinctrl_dev *pctldev)
+{
+ struct pcs_device *pcs;
+ int i;
+
+ pcs = pinctrl_dev_get_drvdata(pctldev);
+
+ if (!pcs->saved_vals)
+ pcs->saved_vals = devm_kzalloc(pcs->dev, pcs->size, GFP_ATOMIC);
+
+ switch (pcs->width) {
+ case 32:
+ for (i = 0; i < pcs->size; i += 4)
+ *(u32 *)(pcs->saved_vals + i) =
+ pcs->read(pcs->base + i);
+ break;
+ case 16:
+ for (i = 0; i < pcs->size; i += 2)
+ *(u16 *)(pcs->saved_vals + i) =
+ pcs->read(pcs->base + i);
+ break;
+ }
+ return 0;
+}
+
+static void pcs_restore_context(struct pinctrl_dev *pctldev)
+{
+ struct pcs_device *pcs;
+ int i;
+
+ pcs = pinctrl_dev_get_drvdata(pctldev);
+
+ switch (pcs->width) {
+ case 32:
+ for (i = 0; i < pcs->size; i += 4)
+ pcs->write(*(u32 *)(pcs->saved_vals + i),
+ pcs->base + i);
+ break;
+ case 16:
+ for (i = 0; i < pcs->size; i += 2)
+ pcs->write(*(u16 *)(pcs->saved_vals + i),
+ pcs->base + i);
+ break;
+ }
+}
+
static int pcs_request_gpio(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range, unsigned pin)
{
@@ -420,6 +468,8 @@ static int pcs_request_gpio(struct pinctrl_dev *pctldev,
.get_function_name = pinmux_generic_get_function_name,
.get_function_groups = pinmux_generic_get_function_groups,
.set_mux = pcs_set_mux,
+ .save_context = pcs_save_context,
+ .restore_context = pcs_restore_context,
.gpio_request_enable = pcs_request_gpio,
};

diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index b8e9bda..b144e0d 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -312,6 +312,28 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
return -EINVAL;
}

+int pinmux_save_context(struct pinctrl_dev *pctldev, const char *function)
+{
+ const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
+
+ if (!pmxops || !pmxops->save_context)
+ return -EINVAL;
+
+ return pmxops->save_context(pctldev);
+}
+EXPORT_SYMBOL(pinmux_save_context);
+
+void pinmux_restore_context(struct pinctrl_dev *pctldev, const char *function)
+{
+ const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
+
+ if (!pmxops || !pmxops->restore_context)
+ return;
+
+ pmxops->restore_context(pctldev);
+}
+EXPORT_SYMBOL(pinmux_restore_context);
+
int pinmux_map_to_setting(const struct pinctrl_map *map,
struct pinctrl_setting *setting)
{
diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
index 8f5dbb8..c523593 100644
--- a/include/linux/pinctrl/pinctrl.h
+++ b/include/linux/pinctrl/pinctrl.h
@@ -198,6 +198,7 @@ struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
extern const char *pinctrl_dev_get_devname(struct pinctrl_dev *pctldev);
extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
+extern struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
#else

struct pinctrl_dev;
@@ -208,6 +209,12 @@ static inline bool pin_is_valid(struct pinctrl_dev *pctldev, int pin)
return pin >= 0;
}

+static inline struct pinctrl_dev *get_pinctrl_dev_from_devname(
+ const char *dev_name)
+{
+ return NULL;
+}
+
#endif /* !CONFIG_PINCTRL */

#endif /* __LINUX_PINCTRL_PINCTRL_H */
diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h
index ace60d7..f837b8f 100644
--- a/include/linux/pinctrl/pinmux.h
+++ b/include/linux/pinctrl/pinmux.h
@@ -75,6 +75,8 @@ struct pinmux_ops {
int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset);
+ int (*save_context)(struct pinctrl_dev *pctldev);
+ void (*restore_context)(struct pinctrl_dev *pctldev);
void (*gpio_disable_free) (struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset);
@@ -85,6 +87,20 @@ struct pinmux_ops {
bool strict;
};

+int pinmux_save_context(struct pinctrl_dev *pctldev, const char *function);
+void pinmux_restore_context(struct pinctrl_dev *pctldev, const char *function);
+
+#else /* !CONFIG_PINMUX */
+
+static inline int pinmux_save_context(struct pinctrl_dev *pctldev,
+ const char *function)
+{
+ return 0;
+}
+
+static inline void pinmux_restore_context(struct pinctrl_dev *pctldev,
+ const char *function) {}
+
#endif /* CONFIG_PINMUX */

#endif /* __LINUX_PINCTRL_PINMUX_H */
--
1.9.1


2018-04-12 04:02:44

by Keerthy

[permalink] [raw]
Subject: [PATCH 01/14] memory: ti-emif-sram: Add resume function to recopy sram code

From: Dave Gerlach <[email protected]>

After an RTC+DDR cycle we lose sram context so emif pm functions present
in sram are lost. We can check if the first byte of the original
code in DDR contains the same first byte as the code in sram, and if
they do not match we know we have lost context and must recopy the
functions to the previous address to maintain PM functionality.

Signed-off-by: Dave Gerlach <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
drivers/memory/ti-emif-pm.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c
index 632651f..ec4a62c 100644
--- a/drivers/memory/ti-emif-pm.c
+++ b/drivers/memory/ti-emif-pm.c
@@ -249,6 +249,25 @@ int ti_emif_get_mem_type(void)
};
MODULE_DEVICE_TABLE(of, ti_emif_of_match);

+#ifdef CONFIG_PM_SLEEP
+static int ti_emif_resume(struct device *dev)
+{
+ unsigned long tmp =
+ __raw_readl((void *)emif_instance->ti_emif_sram_virt);
+
+ /*
+ * Check to see if what we are copying is already present in the
+ * first byte at the destination, only copy if it is not which
+ * indicates we have lost context and sram no longer contains
+ * the PM code
+ */
+ if (tmp != ti_emif_sram)
+ ti_emif_push_sram(dev, emif_instance);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
static int ti_emif_probe(struct platform_device *pdev)
{
int ret;
@@ -308,12 +327,17 @@ static int ti_emif_remove(struct platform_device *pdev)
return 0;
}

+static const struct dev_pm_ops ti_emif_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(NULL, ti_emif_resume)
+};
+
static struct platform_driver ti_emif_driver = {
.probe = ti_emif_probe,
.remove = ti_emif_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = of_match_ptr(ti_emif_of_match),
+ .pm = &ti_emif_pm_ops,
},
};
module_platform_driver(ti_emif_driver);
--
1.9.1


2018-04-12 04:03:00

by Keerthy

[permalink] [raw]
Subject: [PATCH 03/14] ARM: OMAP2+: omap_hwmod: Introduce HWMOD_NEEDS_REIDLE

From: Dave Gerlach <[email protected]>

Some hwmods will not properly assert signals to the PRCM after a
context loss if no driver is present which leads to issues with suspend.
This can be caused by the SYSCONFIG register not being programmed
correctly by default or a softreset being needed before the module will
idle. omap_hwmod will program the SYSCONFIG, idle and softreset them
properly after boot but after the first context loss they will be in
the wrong state once again so suspend will no longer work as there
is no driver associated with the hwmod.

Introduce a new flag, HWMOD_NEEDS_REIDLE, to allow these modules to be
tracked and properly handled. omap_hwmod maintains a list of these
modules and uses a PM notifier to enable and then idle and softreset the
hwmods immediately after resume. omap_device will remove hwmods from this
list when a driver is bound and add the hwmods back if the driver is
removed to avoid any conflicts and allow the proper pm layer to handle
things when a driver is present.

Signed-off-by: Dave Gerlach <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
arch/arm/mach-omap2/omap_device.c | 50 ++++++++
arch/arm/mach-omap2/omap_device.h | 1 +
arch/arm/mach-omap2/omap_hwmod.c | 135 +++++++++++++++++++++
arch/arm/mach-omap2/omap_hwmod.h | 17 +++
.../mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c | 14 ++-
arch/arm/mach-omap2/omap_hwmod_33xx_data.c | 3 +-
6 files changed, 214 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
index 3b829a5..d1e7942 100644
--- a/arch/arm/mach-omap2/omap_device.c
+++ b/arch/arm/mach-omap2/omap_device.c
@@ -208,6 +208,27 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
return ret;
}

+/**
+ * _omap_device_check_reidle_hwmods - check all hwmods in device for reidle flag
+ * @od: struct omap_device *od
+ *
+ * Checks underlying hwmods for reidle flag, if present, remove from hwmod
+ * list and set flag in omap_device to keep track. Returns 0.
+ */
+static int _omap_device_check_reidle_hwmods(struct omap_device *od)
+{
+ int i;
+
+ for (i = 0; i < od->hwmods_cnt; i++) {
+ if (od->hwmods[i]->flags & HWMOD_NEEDS_REIDLE) {
+ od->flags |= OMAP_DEVICE_HAS_REIDLE_HWMODS;
+ omap_hwmod_disable_reidle(od->hwmods[i]);
+ }
+ }
+
+ return 0;
+}
+
static int _omap_device_notifier_call(struct notifier_block *nb,
unsigned long event, void *dev)
{
@@ -237,6 +258,13 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
pm_runtime_set_active(dev);
}
break;
+ case BUS_NOTIFY_BOUND_DRIVER:
+ od = to_omap_device(pdev);
+ if (od) {
+ od->_driver_status = BUS_NOTIFY_BOUND_DRIVER;
+ _omap_device_check_reidle_hwmods(od);
+ }
+ break;
case BUS_NOTIFY_ADD_DEVICE:
if (pdev->dev.of_node)
omap_device_build_from_dt(pdev);
@@ -285,6 +313,24 @@ static int _omap_device_idle_hwmods(struct omap_device *od)
return ret;
}

+/**
+ * _omap_device_reidle_hwmods - call omap_hwmod_enable_reidle on all hwmods
+ * @od: struct omap_device *od
+ *
+ * Add all underlying hwmods to hwmod reidle list. Returns 0.
+ */
+static int _omap_device_reidle_hwmods(struct omap_device *od)
+{
+ int i;
+
+ for (i = 0; i < od->hwmods_cnt; i++)
+ if (od->hwmods[i]->flags | HWMOD_NEEDS_REIDLE)
+ omap_hwmod_enable_reidle(od->hwmods[i]);
+
+ /* XXX pass along return value here? */
+ return 0;
+}
+
/* Public functions for use by core code */

/**
@@ -370,6 +416,9 @@ void omap_device_delete(struct omap_device *od)
if (!od)
return;

+ if (od->flags & OMAP_DEVICE_HAS_REIDLE_HWMODS)
+ _omap_device_reidle_hwmods(od);
+
od->pdev->archdata.od = NULL;
kfree(od->hwmods);
kfree(od);
@@ -821,6 +870,7 @@ struct device *omap_device_get_by_hwmod_name(const char *oh_name)

static int __init omap_device_init(void)
{
+ omap_hwmod_setup_reidle();
bus_register_notifier(&platform_bus_type, &platform_nb);
return 0;
}
diff --git a/arch/arm/mach-omap2/omap_device.h b/arch/arm/mach-omap2/omap_device.h
index 786b9c0..5954727 100644
--- a/arch/arm/mach-omap2/omap_device.h
+++ b/arch/arm/mach-omap2/omap_device.h
@@ -39,6 +39,7 @@

/* omap_device.flags values */
#define OMAP_DEVICE_SUSPENDED BIT(0)
+#define OMAP_DEVICE_HAS_REIDLE_HWMODS BIT(1)

/**
* struct omap_device - omap_device wrapper for platform_devices
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index e7d23e20..90ad8e7 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -141,6 +141,7 @@
#include <linux/cpu.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/suspend.h>
#include <linux/bootmem.h>

#include <linux/platform_data/ti-sysc.h>
@@ -236,6 +237,9 @@ struct omap_hwmod_soc_ops {
/* omap_hwmod_list contains all registered struct omap_hwmods */
static LIST_HEAD(omap_hwmod_list);

+/* oh_reidle_list contains all omap_hwmods with HWMOD_NEEDS_REIDLE set */
+static LIST_HEAD(oh_reidle_list);
+
/* mpu_oh: used to add/remove MPU initiator from sleepdep list */
static struct omap_hwmod *mpu_oh;

@@ -2230,6 +2234,28 @@ int omap_hwmod_parse_module_range(struct omap_hwmod *oh,
}

/**
+ * _setup_reidle- check hwmod @oh and add to reidle list
+ * @oh: struct omap_hwmod *
+ * @n: (unused)
+ *
+ * Check hwmod for HWMOD_NEEDS_REIDLE flag and add to list if
+ * necessary. Return 0 on success.
+ */
+static int _setup_reidle(struct omap_hwmod *oh, void *data)
+{
+ int ret;
+
+ if (oh->flags & HWMOD_NEEDS_REIDLE) {
+ ret = omap_hwmod_enable_reidle(oh);
+
+ if (!ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
* _init_mpu_rt_base - populate the virtual address for a hwmod
* @oh: struct omap_hwmod * to locate the virtual address
* @data: (unused, caller should pass NULL)
@@ -2878,6 +2904,54 @@ static int _am33xx_deassert_hardreset(struct omap_hwmod *oh,
oh->prcm.omap4.rstst_offs);
}

+/**
+ * _reidle - enable then idle a single hwmod
+ *
+ * enables and then immediately reidles an hwmod, as certain hwmods may
+ * not have their sysconfig registers programmed in an idle friendly state
+ * by default
+ */
+static void _reidle(struct omap_hwmod *oh)
+{
+ pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
+
+ omap_hwmod_enable(oh);
+ omap_hwmod_softreset(oh);
+ omap_hwmod_idle(oh);
+}
+
+/**
+ * _reidle_all - enable then idle all hwmods in oh_reidle_list
+ *
+ * Called by pm_notifier to make sure flagged modules do not block suspend
+ * after context loss.
+ */
+static int _reidle_all(void)
+{
+ struct omap_hwmod_list *oh_list_item = NULL;
+
+ list_for_each_entry(oh_list_item, &oh_reidle_list, oh_list) {
+ _reidle(oh_list_item->oh);
+ }
+
+ return 0;
+}
+
+static int _omap_device_pm_notifier(struct notifier_block *self,
+ unsigned long action, void *dev)
+{
+ switch (action) {
+ case PM_POST_SUSPEND:
+ _reidle_all();
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block pm_nb = {
+ .notifier_call = _omap_device_pm_notifier,
+};
+
/* Public functions */

u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs)
@@ -3529,6 +3603,52 @@ static int __init omap_hwmod_setup_all(void)
omap_postcore_initcall(omap_hwmod_setup_all);

/**
+ * omap_hwmod_enable_reidle - add an omap_hwmod to reidle list
+ * @oh: struct omap_hwmod *
+ *
+ * Adds the omap_hwmod to the oh_reidle_list so it will gets enabled then idled
+ * after each suspend cycle. Returns 0 on success.
+ */
+int omap_hwmod_enable_reidle(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_list *oh_list_item = NULL;
+
+ oh_list_item = kzalloc(sizeof(*oh_list_item), GFP_KERNEL);
+
+ if (!oh_list_item)
+ return -ENOMEM;
+
+ oh_list_item->oh = oh;
+ list_add(&oh_list_item->oh_list, &oh_reidle_list);
+
+ pr_debug("omap_hwmod: %s: added to reidle list\n", oh->name);
+
+ return 0;
+}
+
+/**
+ * omap_hwmod_disable_reidle - remove an omap_hwmod from reidle list
+ * @oh: struct omap_hwmod *
+ *
+ * Remove the omap_hwmod from the oh_reidle_list. Returns 0 on success.
+ */
+int omap_hwmod_disable_reidle(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_list *li, *oh_list_item = NULL;
+
+ list_for_each_entry_safe(oh_list_item, li, &oh_reidle_list, oh_list) {
+ if (oh_list_item->oh == oh) {
+ list_del(&oh_list_item->oh_list);
+ pr_debug("omap_hwmod: %s: removed from reidle list\n",
+ oh->name);
+ kfree(oh_list_item);
+ }
+ }
+
+ return 0;
+}
+
+/**
* omap_hwmod_enable - enable an omap_hwmod
* @oh: struct omap_hwmod *
*
@@ -3948,6 +4068,21 @@ void __init omap_hwmod_init(void)
}

/**
+ * omap_hwmod_setup_reidle - add hwmods to reidle list and register notifier
+ *
+ * Returns 0 on success.
+ */
+int omap_hwmod_setup_reidle(void)
+{
+ omap_hwmod_for_each(_setup_reidle, NULL);
+
+ if (!list_empty(&oh_reidle_list))
+ register_pm_notifier(&pm_nb);
+
+ return 0;
+}
+
+/**
* omap_hwmod_get_main_clk - get pointer to main clock name
* @oh: struct omap_hwmod *
*
diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
index c7122ab..f35638b 100644
--- a/arch/arm/mach-omap2/omap_hwmod.h
+++ b/arch/arm/mach-omap2/omap_hwmod.h
@@ -445,6 +445,10 @@ struct omap_hwmod_omap4_prcm {
* entering HW_AUTO while hwmod is active. This is needed to workaround
* some modules which don't function correctly with HW_AUTO. For example,
* DCAN on DRA7x SoC needs this to workaround errata i893.
+ * HWMOD_NEEDS_REIDLE: Some devices do not assert their MSTANDBY signal by
+ * default after losing context if no driver is present and using the
+ * hwmod. This will break subsequent suspend cycles but can be fixed by
+ * enabling then idling the unused hwmod after each suspend cycle.
*/
#define HWMOD_SWSUP_SIDLE (1 << 0)
#define HWMOD_SWSUP_MSTANDBY (1 << 1)
@@ -463,6 +467,7 @@ struct omap_hwmod_omap4_prcm {
#define HWMOD_OPT_CLKS_NEEDED (1 << 14)
#define HWMOD_NO_IDLE (1 << 15)
#define HWMOD_CLKDM_NOAUTO (1 << 16)
+#define HWMOD_NEEDS_REIDLE (1 << 17)

/*
* omap_hwmod._int_flags definitions
@@ -611,6 +616,14 @@ struct omap_hwmod {

struct device_node;

+/*
+ * omap_hwmod_list - simple generic container for omap_hwmod lists
+ */
+struct omap_hwmod_list {
+ struct omap_hwmod *oh;
+ struct list_head oh_list;
+};
+
struct omap_hwmod *omap_hwmod_lookup(const char *name);
int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
void *data);
@@ -649,6 +662,10 @@ int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type,
int omap_hwmod_enable_wakeup(struct omap_hwmod *oh);
int omap_hwmod_disable_wakeup(struct omap_hwmod *oh);

+int omap_hwmod_setup_reidle(void);
+int omap_hwmod_enable_reidle(struct omap_hwmod *oh);
+int omap_hwmod_disable_reidle(struct omap_hwmod *oh);
+
int omap_hwmod_for_each_by_class(const char *classname,
int (*fn)(struct omap_hwmod *oh,
void *user),
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
index 5efe91c..f31ec76 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
@@ -375,7 +375,8 @@ struct omap_hwmod am33xx_cpgmac0_hwmod = {
.name = "cpgmac0",
.class = &am33xx_cpgmac0_hwmod_class,
.clkdm_name = "cpsw_125mhz_clkdm",
- .flags = (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY),
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
+ HWMOD_NEEDS_REIDLE,
.main_clk = "cpsw_125mhz_gclk",
.mpu_rt_idx = 1,
.prcm = {
@@ -618,7 +619,7 @@ struct omap_hwmod am33xx_gpmc_hwmod = {
.class = &am33xx_gpmc_hwmod_class,
.clkdm_name = "l3s_clkdm",
/* Skip reset for CONFIG_OMAP_GPMC_DEBUG for bootloader timings */
- .flags = DEBUG_OMAP_GPMC_HWMOD_FLAGS,
+ .flags = DEBUG_OMAP_GPMC_HWMOD_FLAGS | HWMOD_NEEDS_REIDLE,
.main_clk = "l3s_gclk",
.prcm = {
.omap4 = {
@@ -1094,7 +1095,8 @@ struct omap_hwmod am33xx_tptc0_hwmod = {
.name = "tptc0",
.class = &am33xx_tptc_hwmod_class,
.clkdm_name = "l3_clkdm",
- .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
+ HWMOD_NEEDS_REIDLE,
.main_clk = "l3_gclk",
.prcm = {
.omap4 = {
@@ -1108,7 +1110,8 @@ struct omap_hwmod am33xx_tptc1_hwmod = {
.name = "tptc1",
.class = &am33xx_tptc_hwmod_class,
.clkdm_name = "l3_clkdm",
- .flags = (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY),
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
+ HWMOD_NEEDS_REIDLE,
.main_clk = "l3_gclk",
.prcm = {
.omap4 = {
@@ -1122,7 +1125,8 @@ struct omap_hwmod am33xx_tptc2_hwmod = {
.name = "tptc2",
.class = &am33xx_tptc_hwmod_class,
.clkdm_name = "l3_clkdm",
- .flags = (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY),
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
+ HWMOD_NEEDS_REIDLE,
.main_clk = "l3_gclk",
.prcm = {
.omap4 = {
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
index 53e1ac3..69f7c52 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
@@ -301,7 +301,8 @@
.name = "usb_otg_hs",
.class = &am33xx_usbotg_class,
.clkdm_name = "l3s_clkdm",
- .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
+ HWMOD_NEEDS_REIDLE,
.main_clk = "usbotg_fck",
.prcm = {
.omap4 = {
--
1.9.1


2018-04-12 04:03:28

by Keerthy

[permalink] [raw]
Subject: [PATCH 06/14] ARM: AM33XX: Add functions to save/restore am33xx control registers.

From: Russ Dill <[email protected]>

These registers are part of the wkup domain and are lost during RTC only
suspend and also hibernation, so storing/restoring their state is
necessary.

Signed-off-by: Russ Dill <[email protected]>
Signed-off-by: Keerthy <[email protected]>
---
arch/arm/mach-omap2/control.c | 84 +++++++++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/control.h | 52 +++++++++++++++++++++++++++
2 files changed, 136 insertions(+)

diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index 180da403..d92aa9a 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -619,8 +619,92 @@ void __init omap3_ctrl_init(void)

omap3_ctrl_setup_d2d_padconf();
}
+
#endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */

+#if defined(CONFIG_SOC_AM33XX) && defined(CONFIG_PM)
+static unsigned long am33xx_control_reg_offsets[] = {
+ AM33XX_CONTROL_SYSCONFIG_OFFSET,
+ AM33XX_CONTROL_STATUS_OFFSET,
+ AM33XX_CONTROL_CORTEX_VBBLDO_CTRL_OFFSET,
+ AM33XX_CONTROL_CORE_SLDO_CTRL_OFFSET,
+ AM33XX_CONTROL_MPU_SLDO_CTRL_OFFSET,
+ AM33XX_CONTROL_CLK32KDIVRATIO_CTRL_OFFSET,
+ AM33XX_CONTROL_BANDGAP_CTRL_OFFSET,
+ AM33XX_CONTROL_BANDGAP_TRIM_OFFSET,
+ AM33XX_CONTROL_PLL_CLKINPULOW_CTRL_OFFSET,
+ AM33XX_CONTROL_MOSC_CTRL_OFFSET,
+ AM33XX_CONTROL_RCOSC_CTRL_OFFSET,
+ AM33XX_CONTROL_DEEPSLEEP_CTRL_OFFSET,
+ AM33XX_CONTROL_INIT_PRIORITY_0_OFFSET,
+ AM33XX_CONTROL_INIT_PRIORITY_1_OFFSET,
+ AM33XX_CONTROL_MMU_CFG_OFFSET,
+ AM33XX_CONTROL_TPTC_CFG_OFFSET,
+ AM33XX_CONTROL_USB_CTRL0_OFFSET,
+ AM33XX_CONTROL_USB_CTRL1_OFFSET,
+ AM33XX_CONTROL_USB_WKUP_CTRL_OFFSET,
+ AM33XX_CONTROL_MREQPRIO_0_OFFSET,
+ AM33XX_CONTROL_MREQPRIO_1_OFFSET,
+ AM33XX_CONTROL_HW_EVENT_SEL_GRP1_OFFSET,
+ AM33XX_CONTROL_HW_EVENT_SEL_GRP2_OFFSET,
+ AM33XX_CONTROL_HW_EVENT_SEL_GRP3_OFFSET,
+ AM33XX_CONTROL_HW_EVENT_SEL_GRP4_OFFSET,
+ AM33XX_CONTROL_SMRT_CTRL_OFFSET,
+ AM33XX_CONTROL_MPUSS_HW_DEBUG_SEL_OFFSET,
+ AM33XX_CONTROL_VREF_CTRL_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_0_3_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_4_7_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_8_11_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_12_15_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_16_19_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_20_23_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_24_27_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_28_31_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_32_35_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_36_39_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_40_43_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_44_47_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_48_51_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_52_55_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_56_59_OFFSET,
+ AM33XX_CONTROL_TPCC_EVT_MUX_60_63_OFFSET,
+ AM33XX_CONTROL_TIMER_EVT_CAPT_OFFSET,
+ AM33XX_CONTROL_ECAP_EVT_CAPT_OFFSET,
+ AM33XX_CONTROL_ADC_EVT_CAPT_OFFSET,
+ AM33XX_CONTROL_RESET_ISO_OFFSET,
+};
+
+static u32 am33xx_control_vals[ARRAY_SIZE(am33xx_control_reg_offsets)];
+
+/**
+ * am33xx_control_save_context - Save the wakeup domain registers
+ *
+ * Save the wkup domain registers
+ */
+void am33xx_control_save_context(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(am33xx_control_reg_offsets); i++)
+ am33xx_control_vals[i] =
+ omap_ctrl_readl(am33xx_control_reg_offsets[i]);
+}
+
+/**
+ * am33xx_control_restore_context - Restore the wakeup domain registers
+ *
+ * Restore the wkup domain registers
+ */
+void am33xx_control_restore_context(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(am33xx_control_reg_offsets); i++)
+ omap_ctrl_writel(am33xx_control_vals[i],
+ am33xx_control_reg_offsets[i]);
+}
+#endif /* CONFIG_SOC_AM33XX && CONFIG_PM */
+
struct control_init_data {
int index;
void __iomem *mem;
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index ec406bc..4c50199 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -409,6 +409,56 @@
#define AM33XX_DEV_FEATURE 0x604
#define AM33XX_SGX_MASK BIT(29)

+/* Additional AM33XX CONTROL registers */
+#define AM33XX_CONTROL_SYSCONFIG_OFFSET 0x0010
+#define AM33XX_CONTROL_STATUS_OFFSET 0x0040
+#define AM33XX_CONTROL_CORTEX_VBBLDO_CTRL_OFFSET 0x041c
+#define AM33XX_CONTROL_CORE_SLDO_CTRL_OFFSET 0x0428
+#define AM33XX_CONTROL_MPU_SLDO_CTRL_OFFSET 0x042c
+#define AM33XX_CONTROL_CLK32KDIVRATIO_CTRL_OFFSET 0x0444
+#define AM33XX_CONTROL_BANDGAP_CTRL_OFFSET 0x0448
+#define AM33XX_CONTROL_BANDGAP_TRIM_OFFSET 0x044c
+#define AM33XX_CONTROL_PLL_CLKINPULOW_CTRL_OFFSET 0x0458
+#define AM33XX_CONTROL_MOSC_CTRL_OFFSET 0x0468
+#define AM33XX_CONTROL_RCOSC_CTRL_OFFSET 0x046c
+#define AM33XX_CONTROL_DEEPSLEEP_CTRL_OFFSET 0x0470
+#define AM33XX_CONTROL_INIT_PRIORITY_0_OFFSET 0x0608
+#define AM33XX_CONTROL_INIT_PRIORITY_1_OFFSET 0x060c
+#define AM33XX_CONTROL_MMU_CFG_OFFSET 0x0610
+#define AM33XX_CONTROL_TPTC_CFG_OFFSET 0x0614
+#define AM33XX_CONTROL_USB_CTRL0_OFFSET 0x0620
+#define AM33XX_CONTROL_USB_CTRL1_OFFSET 0x0628
+#define AM33XX_CONTROL_USB_WKUP_CTRL_OFFSET 0x0648
+#define AM33XX_CONTROL_MREQPRIO_0_OFFSET 0x0670
+#define AM33XX_CONTROL_MREQPRIO_1_OFFSET 0x0674
+#define AM33XX_CONTROL_HW_EVENT_SEL_GRP1_OFFSET 0x0690
+#define AM33XX_CONTROL_HW_EVENT_SEL_GRP2_OFFSET 0x0694
+#define AM33XX_CONTROL_HW_EVENT_SEL_GRP3_OFFSET 0x0698
+#define AM33XX_CONTROL_HW_EVENT_SEL_GRP4_OFFSET 0x069c
+#define AM33XX_CONTROL_SMRT_CTRL_OFFSET 0x06a0
+#define AM33XX_CONTROL_MPUSS_HW_DEBUG_SEL_OFFSET 0x06a4
+#define AM33XX_CONTROL_VREF_CTRL_OFFSET 0x0e14
+#define AM33XX_CONTROL_TPCC_EVT_MUX_0_3_OFFSET 0x0f90
+#define AM33XX_CONTROL_TPCC_EVT_MUX_4_7_OFFSET 0x0f94
+#define AM33XX_CONTROL_TPCC_EVT_MUX_8_11_OFFSET 0x0f98
+#define AM33XX_CONTROL_TPCC_EVT_MUX_12_15_OFFSET 0x0f9c
+#define AM33XX_CONTROL_TPCC_EVT_MUX_16_19_OFFSET 0x0fa0
+#define AM33XX_CONTROL_TPCC_EVT_MUX_20_23_OFFSET 0x0fa4
+#define AM33XX_CONTROL_TPCC_EVT_MUX_24_27_OFFSET 0x0fa8
+#define AM33XX_CONTROL_TPCC_EVT_MUX_28_31_OFFSET 0x0fac
+#define AM33XX_CONTROL_TPCC_EVT_MUX_32_35_OFFSET 0x0fb0
+#define AM33XX_CONTROL_TPCC_EVT_MUX_36_39_OFFSET 0x0fb4
+#define AM33XX_CONTROL_TPCC_EVT_MUX_40_43_OFFSET 0x0fb8
+#define AM33XX_CONTROL_TPCC_EVT_MUX_44_47_OFFSET 0x0fbc
+#define AM33XX_CONTROL_TPCC_EVT_MUX_48_51_OFFSET 0x0fc0
+#define AM33XX_CONTROL_TPCC_EVT_MUX_52_55_OFFSET 0x0fc4
+#define AM33XX_CONTROL_TPCC_EVT_MUX_56_59_OFFSET 0x0fc8
+#define AM33XX_CONTROL_TPCC_EVT_MUX_60_63_OFFSET 0x0fcc
+#define AM33XX_CONTROL_TIMER_EVT_CAPT_OFFSET 0x0fd0
+#define AM33XX_CONTROL_ECAP_EVT_CAPT_OFFSET 0x0fd4
+#define AM33XX_CONTROL_ADC_EVT_CAPT_OFFSET 0x0fd8
+#define AM33XX_CONTROL_RESET_ISO_OFFSET 0x1000
+
/* CONTROL OMAP STATUS register to identify OMAP3 features */
#define OMAP3_CONTROL_OMAP_STATUS 0x044c

@@ -467,6 +517,8 @@
int omap2_control_base_init(void);
int omap_control_init(void);
void omap2_set_globals_control(void __iomem *ctrl);
+extern void am33xx_control_save_context(void);
+extern void am33xx_control_restore_context(void);
void __init omap3_control_legacy_iomap_init(void);
#else
#define omap_ctrl_readb(x) 0
--
1.9.1


2018-04-12 04:03:31

by Keerthy

[permalink] [raw]
Subject: [PATCH 12/14] OMAP: CLK: CLKSRC: Add suspend resume hooks

Add the save and restore for clksrc as part of suspend and resume
so that it saves the counter value and restores. This is needed in
modes like rtc+ddr in self-refresh not doing this stalls the time.

Signed-off-by: Keerthy <[email protected]>
---
arch/arm/mach-omap2/timer.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)

diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 4fb4dc2..35fef97 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -442,6 +442,38 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
return ret;
}

+static unsigned int omap2_gptimer_clksrc_load;
+
+static void omap2_gptimer_clksrc_suspend(struct clocksource *unused)
+{
+ struct omap_hwmod *oh;
+
+ omap2_gptimer_clksrc_load =
+ __omap_dm_timer_read_counter(&clksrc, OMAP_TIMER_NONPOSTED);
+
+ oh = omap_hwmod_lookup(clocksource_gpt.name);
+ if (!oh)
+ return;
+
+ omap_hwmod_idle(oh);
+}
+
+static void omap2_gptimer_clksrc_resume(struct clocksource *unused)
+{
+ struct omap_hwmod *oh;
+
+ oh = omap_hwmod_lookup(clocksource_gpt.name);
+ if (!oh)
+ return;
+
+ omap_hwmod_enable(oh);
+
+ __omap_dm_timer_load_start(&clksrc,
+ OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR,
+ omap2_gptimer_clksrc_load,
+ OMAP_TIMER_NONPOSTED);
+}
+
static void __init omap2_gptimer_clocksource_init(int gptimer_id,
const char *fck_source,
const char *property)
@@ -451,6 +483,11 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id,
clksrc.id = gptimer_id;
clksrc.errata = omap_dm_timer_get_errata();

+ if (soc_is_am43xx()) {
+ clocksource_gpt.suspend = omap2_gptimer_clksrc_suspend;
+ clocksource_gpt.resume = omap2_gptimer_clksrc_resume;
+ }
+
res = omap_dm_timer_init_one(&clksrc, fck_source, property,
&clocksource_gpt.name,
OMAP_TIMER_NONPOSTED);
--
1.9.1


2018-04-12 14:20:21

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH 08/14] ARM: OMAP2: Add functions to save and restore pinctrl context.

Hi,

* Keerthy <[email protected]> [180412 03:56]:
> From: Russ Dill <[email protected]>
>
> This adds a pair of context save/restore functions to save/restore the
> state of a set of pinctrl registers. This simplifies some of the AM33XX
> PM code as some of the pinctrl registers are lost when the per power
> domain loses power. The pincrtl code can perform the necessary
> save/restore.

So where's the patch adding callers to this code?

If this cannot be done from regular driver suspend/resume calls,
this probably should be done from cpu_pm notifiers CPU_PM_ENTER and
CPU_PM_EXIT. We should also do the same for GPIO BTW.

BTW, the subject line is wrong here, it should be "pinctrl" :)

Regards,

Tony

2018-04-12 14:28:18

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH 10/14] gpio: omap: Drop the concept of gpio banks not being able to lose context.

* Keerthy <[email protected]> [180412 03:56]:
> From: Russ Dill <[email protected]>
> --- a/drivers/gpio/gpio-omap.c
> +++ b/drivers/gpio/gpio-omap.c
> @@ -68,7 +68,7 @@ struct gpio_bank {
> bool dbck_enabled;
> bool is_mpuio;
> bool dbck_flag;
> - bool loses_context;
> +
> bool context_valid;
> int stride;
> u32 width;

For some SoCs GPIO bank1 won't lose the context ever. So I'd like to
keep loses_context flag around to avoid pointless save and restore.
But maybe this still happens with get_context_loss_count and I'm
misreading this patch?

However..

> @@ -1198,15 +1198,9 @@ static int omap_gpio_probe(struct platform_device *pdev)
> #ifdef CONFIG_OF_GPIO
> bank->chip.of_node = of_node_get(node);
> #endif
> - if (node) {
> - if (!of_property_read_bool(node, "ti,gpio-always-on"))
> - bank->loses_context = true;
> - } else {
> - bank->loses_context = pdata->loses_context;
> -
> - if (bank->loses_context)
> - bank->get_context_loss_count =
> - pdata->get_context_loss_count;
> + if (!node) {
> + bank->get_context_loss_count =
> + pdata->get_context_loss_count;
> }
>
> if (bank->regs->set_dataout && bank->regs->clr_dataout)

.. I do have a patch ready here that I'll post after -rc1 to remove
CONFIG_OMAP_PM_NOOP related stuff, turns out that's noop anyways :)

So yeah the pdata->get_context_loss_count parts are noop and can
be just removed.

Regards,

Tony

2018-04-12 14:32:02

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH 12/14] OMAP: CLK: CLKSRC: Add suspend resume hooks

* Keerthy <[email protected]> [180412 03:56]:
> Add the save and restore for clksrc as part of suspend and resume
> so that it saves the counter value and restores. This is needed in
> modes like rtc+ddr in self-refresh not doing this stalls the time.

I suspect this too should really happen with cpu_pm.

> --- a/arch/arm/mach-omap2/timer.c
> +++ b/arch/arm/mach-omap2/timer.c
> @@ -442,6 +442,38 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
> return ret;
> }
>
> +static unsigned int omap2_gptimer_clksrc_load;
> +
> +static void omap2_gptimer_clksrc_suspend(struct clocksource *unused)
> +{
> + struct omap_hwmod *oh;
> +
> + omap2_gptimer_clksrc_load =
> + __omap_dm_timer_read_counter(&clksrc, OMAP_TIMER_NONPOSTED);
> +
> + oh = omap_hwmod_lookup(clocksource_gpt.name);
> + if (!oh)
> + return;
> +
> + omap_hwmod_idle(oh);
> +}

Probably no need to look up the hwmod every time? Especially if am437x
will start supporting deeper idle modes during runtime.

And probably the cpu_pm notifies should be directly in the hwmod
code so we don't need to add more any more dependencies to hwmod
functions to timer code. We should have this code move to drivers
anyways at some point.

Regards,

Tony

2018-04-12 14:38:13

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH 03/14] ARM: OMAP2+: omap_hwmod: Introduce HWMOD_NEEDS_REIDLE

* Keerthy <[email protected]> [180412 03:56]:
> From: Dave Gerlach <[email protected]>
> --- a/arch/arm/mach-omap2/omap_device.c
> +++ b/arch/arm/mach-omap2/omap_device.c
> @@ -208,6 +208,27 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
> return ret;
> }
>
> +/**
> + * _omap_device_check_reidle_hwmods - check all hwmods in device for reidle flag
> + * @od: struct omap_device *od
> + *
> + * Checks underlying hwmods for reidle flag, if present, remove from hwmod
> + * list and set flag in omap_device to keep track. Returns 0.
> + */
> +static int _omap_device_check_reidle_hwmods(struct omap_device *od)
> +{
> + int i;
> +
> + for (i = 0; i < od->hwmods_cnt; i++) {
> + if (od->hwmods[i]->flags & HWMOD_NEEDS_REIDLE) {
> + od->flags |= OMAP_DEVICE_HAS_REIDLE_HWMODS;
> + omap_hwmod_disable_reidle(od->hwmods[i]);
> + }
> + }
> +
> + return 0;
> +}

Let's not add any more dependencies to omap_device stuff, this will go away
anyways with ti-sysc.

> --- a/arch/arm/mach-omap2/omap_hwmod.c
> +++ b/arch/arm/mach-omap2/omap_hwmod.c
> +static int _omap_device_pm_notifier(struct notifier_block *self,
> + unsigned long action, void *dev)
> +{
> + switch (action) {
> + case PM_POST_SUSPEND:
> + _reidle_all();
> + }
> +
> + return NOTIFY_DONE;
> +}
> +
> +static struct notifier_block pm_nb = {
> + .notifier_call = _omap_device_pm_notifier,
> +};

This seems like the right place to do it :) So for places where
I suggested cpu_pm notifiers, maybe this is actually what you
want to do for pinctrl and gpio etc. Please keep in mind that
for gpio we do save and restore context it dynamically too during
idle, so it's not just suspend and resume. That's why I was thinking
cpu_pm notifiers, but maybe there's a better solution that covers
both PM runtime and suspend.

Regards,

Tony

2018-04-12 14:41:46

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH 05/14] ARM: OMAP2: Add functions to save and restore powerdomain context

* Keerthy <[email protected]> [180412 03:56]:
> From: Russ Dill <[email protected]>
> --- a/arch/arm/mach-omap2/powerdomain.c
> +++ b/arch/arm/mach-omap2/powerdomain.c
> @@ -1199,3 +1199,63 @@ bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
>
> return 0;
> }
> +
> +/**
> + * pwrdm_save_context - save powerdomain registers
> + *
> + * Register state is going to be lost due to a suspend or hibernate
> + * event. Save the powerdomain registers.
> + */
> +static int pwrdm_save_context(struct powerdomain *pwrdm, void *unused)
> +{
> + if (arch_pwrdm && arch_pwrdm->pwrdm_save_context)
> + arch_pwrdm->pwrdm_save_context(pwrdm);
> + return 0;
> +}
> +
> +/**
> + * pwrdm_save_context - restore powerdomain registers
> + *
> + * Restore powerdomain control registers after a suspend or resume
> + * event.
> + */
> +static int pwrdm_restore_context(struct powerdomain *pwrdm, void *unused)
> +{
> + if (arch_pwrdm && arch_pwrdm->pwrdm_restore_context)
> + arch_pwrdm->pwrdm_restore_context(pwrdm);
> + return 0;
> +}

Here too we should use notifiers with the idea being that it allows making
powerdomains into a regular device driver eventually.

Regards,

Tony

2018-04-12 14:45:04

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH 11/14] gpio: omap: Restore power_mode configuration at resume time

* Keerthy <[email protected]> [180412 03:56]:
> From: Dave Gerlach <[email protected]>
>
> Commit 2dc983c565e0 ("gpio/omap: cleanup prepare_for_idle and
> resume_after_idle") introduces omap2_gpio_prepare_for_idle and
> omap2_gpio_resume_after_idle to properly configure gpios that are used
> as wake sources. When entering off mode, omap2_gpio_prepare_for_idle
> can set a flag indicating off-mode entry is desired, however once this
> flag is set it is never cleared, so any additional calls to this
> function, regardless of the mode, have this flag set.
>
> This patch restores the pwr_mode flag to 0 in
> omap2_gpio_resume_after_idle to ensure the flag is not misconfigured
> during non off-mode operation.

Seems like this should be applied as a fix, can you please add
a proper Fixes tag?

Regards,

Tony

2018-04-12 16:48:17

by Santosh Shilimkar

[permalink] [raw]
Subject: Re: [PATCH 01/14] memory: ti-emif-sram: Add resume function to recopy sram code

On 4/11/18 9:53 PM, Keerthy wrote:
> From: Dave Gerlach <[email protected]>
>
> After an RTC+DDR cycle we lose sram context so emif pm functions present
> in sram are lost. We can check if the first byte of the original
> code in DDR contains the same first byte as the code in sram, and if
> they do not match we know we have lost context and must recopy the
> functions to the previous address to maintain PM functionality.
>
> Signed-off-by: Dave Gerlach <[email protected]>
> Signed-off-by: Keerthy <[email protected]>
> ---
> drivers/memory/ti-emif-pm.c | 24 ++++++++++++++++++++++++
> 1 file changed, 24 insertions(+)
>
> diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c
> index 632651f..ec4a62c 100644
> --- a/drivers/memory/ti-emif-pm.c
> +++ b/drivers/memory/ti-emif-pm.c
> @@ -249,6 +249,25 @@ int ti_emif_get_mem_type(void)
> };
> MODULE_DEVICE_TABLE(of, ti_emif_of_match);
>
> +#ifdef CONFIG_PM_SLEEP
> +static int ti_emif_resume(struct device *dev)
> +{
> + unsigned long tmp =
> + __raw_readl((void *)emif_instance->ti_emif_sram_virt);
> +
> + /*
> + * Check to see if what we are copying is already present in the
> + * first byte at the destination, only copy if it is not which
> + * indicates we have lost context and sram no longer contains
> + * the PM code
> + */

> + if (tmp != ti_emif_sram)
> + ti_emif_push_sram(dev, emif_instance);
> +
> + return 0;
> +}
> +#endif /* CONFIG_PM_SLEEP */
Instead of this indirect method , why can't just check the previous
deep sleep mode and based on that do copy or not. EMIF power status
register should have something like that ?

Another minor point is even though there is nothing to do in suspend,
might be good to have a callback with comment that nothing to do with
some explanation why not. Don't have strong preference but may for
better readability.

Regards,
Santosh



2018-04-12 20:18:58

by Grygorii Strashko

[permalink] [raw]
Subject: Re: [PATCH 11/14] gpio: omap: Restore power_mode configuration at resume time



On 04/12/2018 09:39 AM, Tony Lindgren wrote:
> * Keerthy <[email protected]> [180412 03:56]:
>> From: Dave Gerlach <[email protected]>
>>
>> Commit 2dc983c565e0 ("gpio/omap: cleanup prepare_for_idle and
>> resume_after_idle") introduces omap2_gpio_prepare_for_idle and
>> omap2_gpio_resume_after_idle to properly configure gpios that are used
>> as wake sources. When entering off mode, omap2_gpio_prepare_for_idle
>> can set a flag indicating off-mode entry is desired, however once this
>> flag is set it is never cleared, so any additional calls to this
>> function, regardless of the mode, have this flag set.
>>
>> This patch restores the pwr_mode flag to 0 in
>> omap2_gpio_resume_after_idle to ensure the flag is not misconfigured
>> during non off-mode operation.
>
> Seems like this should be applied as a fix, can you please add
> a proper Fixes tag?

Correct. And please send it separate.
But not sure about fixes (to many changes) - it has to manually checked for the lowest
kernel version to apply.

--
regards,
-grygorii

2018-04-12 20:38:14

by Grygorii Strashko

[permalink] [raw]
Subject: Re: [PATCH 10/14] gpio: omap: Drop the concept of gpio banks not being able to lose context.



On 04/12/2018 09:22 AM, Tony Lindgren wrote:
> * Keerthy <[email protected]> [180412 03:56]:
>> From: Russ Dill <[email protected]>
>> --- a/drivers/gpio/gpio-omap.c
>> +++ b/drivers/gpio/gpio-omap.c
>> @@ -68,7 +68,7 @@ struct gpio_bank {
>> bool dbck_enabled;
>> bool is_mpuio;
>> bool dbck_flag;
>> - bool loses_context;
>> +
>> bool context_valid;
>> int stride;
>> u32 width;
>
> For some SoCs GPIO bank1 won't lose the context ever. So I'd like to
> keep loses_context flag around to avoid pointless save and restore.
> But maybe this still happens with get_context_loss_count and I'm
> misreading this patch?
>

Agree with Tony here. More over, even if platform supports RTC suspend
(gpio1 context loss) it might support suspend to RAM - gpio1 will not lose context.

Not sure how to handle this correctly now - always-on gpio bank should not be touched
by omap device framework during suspend otherwise it may hit "in transition" state forever.
From another side it must be handled the same way as other gpio banks in case of RTC suspend.
Q: How to know if current suspend is RTC suspend and not regular suspend to mem?

> However..
>
>> @@ -1198,15 +1198,9 @@ static int omap_gpio_probe(struct platform_device *pdev)
>> #ifdef CONFIG_OF_GPIO
>> bank->chip.of_node = of_node_get(node);
>> #endif
>> - if (node) {
>> - if (!of_property_read_bool(node, "ti,gpio-always-on"))
>> - bank->loses_context = true;
>> - } else {
>> - bank->loses_context = pdata->loses_context;
>> -
>> - if (bank->loses_context)
>> - bank->get_context_loss_count =
>> - pdata->get_context_loss_count;
>> + if (!node) {
>> + bank->get_context_loss_count =
>> + pdata->get_context_loss_count;
>> }
>>
>> if (bank->regs->set_dataout && bank->regs->clr_dataout)
>
> .. I do have a patch ready here that I'll post after -rc1 to remove
> CONFIG_OMAP_PM_NOOP related stuff, turns out that's noop anyways :)
>
> So yeah the pdata->get_context_loss_count parts are noop and can
> be just removed.
>

--
regards,
-grygorii

2018-04-13 06:29:04

by Keerthy

[permalink] [raw]
Subject: Re: [PATCH 08/14] ARM: OMAP2: Add functions to save and restore pinctrl context.



On Thursday 12 April 2018 07:46 PM, Tony Lindgren wrote:
> Hi,
>
> * Keerthy <[email protected]> [180412 03:56]:
>> From: Russ Dill <[email protected]>
>>
>> This adds a pair of context save/restore functions to save/restore the
>> state of a set of pinctrl registers. This simplifies some of the AM33XX
>> PM code as some of the pinctrl registers are lost when the per power
>> domain loses power. The pincrtl code can perform the necessary
>> save/restore.
>
> So where's the patch adding callers to this code?

This series was to get all the additional save/restores needed for the
rtc+ddr mode. Caller patch is in the main patch that implements that
mode that i will be posting once the ground is set.

Based on enable_off_mode being set this function was called only for
rtc+ddr mode.

>
> If this cannot be done from regular driver suspend/resume calls,
> this probably should be done from cpu_pm notifiers CPU_PM_ENTER and
> CPU_PM_EXIT. We should also do the same for GPIO BTW.

I will look into that. Thanks for suggestion.

>
> BTW, the subject line is wrong here, it should be "pinctrl" :)

Oops yes that should be pinctrl.

>
> Regards,
>
> Tony
>

2018-04-16 10:31:32

by Keerthy

[permalink] [raw]
Subject: Re: [PATCH 01/14] memory: ti-emif-sram: Add resume function to recopy sram code



On Thursday 12 April 2018 10:14 PM, [email protected] wrote:
> On 4/11/18 9:53 PM, Keerthy wrote:
>> From: Dave Gerlach <[email protected]>
>>
>> After an RTC+DDR cycle we lose sram context so emif pm functions present
>> in sram are lost. We can check if the first byte of the original
>> code in DDR contains the same first byte as the code in sram, and if
>> they do not match we know we have lost context and must recopy the
>> functions to the previous address to maintain PM functionality.
>>
>> Signed-off-by: Dave Gerlach <[email protected]>
>> Signed-off-by: Keerthy <[email protected]>
>> ---
>>   drivers/memory/ti-emif-pm.c | 24 ++++++++++++++++++++++++
>>   1 file changed, 24 insertions(+)
>>
>> diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c
>> index 632651f..ec4a62c 100644
>> --- a/drivers/memory/ti-emif-pm.c
>> +++ b/drivers/memory/ti-emif-pm.c
>> @@ -249,6 +249,25 @@ int ti_emif_get_mem_type(void)
>>   };
>>   MODULE_DEVICE_TABLE(of, ti_emif_of_match);
>>   +#ifdef CONFIG_PM_SLEEP
>> +static int ti_emif_resume(struct device *dev)
>> +{
>> +    unsigned long tmp =
>> +            __raw_readl((void *)emif_instance->ti_emif_sram_virt);
>> +
>> +    /*
>> +     * Check to see if what we are copying is already present in the
>> +     * first byte at the destination, only copy if it is not which
>> +     * indicates we have lost context and sram no longer contains
>> +     * the PM code
>> +     */
>
>> +    if (tmp != ti_emif_sram)
>> +        ti_emif_push_sram(dev, emif_instance);
>> +
>> +    return 0;
>> +}
>> +#endif /* CONFIG_PM_SLEEP */
> Instead of this indirect method , why can't just check the previous
> deep sleep mode and based on that do copy or not. EMIF power status
> register should have something like that ?

I will check if we have a register that tells the previous state of sram.

>
> Another minor point is even though there is nothing to do in suspend,
> might be good to have a callback with comment that nothing to do with
> some explanation why not. Don't have strong preference but may for
> better readability.

Okay. Thanks a lot for the quick feedback!

>
> Regards,
> Santosh
>
>

2018-04-19 04:12:41

by Keerthy

[permalink] [raw]
Subject: Re: [PATCH 01/14] memory: ti-emif-sram: Add resume function to recopy sram code



On Thursday 12 April 2018 10:14 PM, [email protected] wrote:
> On 4/11/18 9:53 PM, Keerthy wrote:
>> From: Dave Gerlach <[email protected]>
>>
>> After an RTC+DDR cycle we lose sram context so emif pm functions present
>> in sram are lost. We can check if the first byte of the original
>> code in DDR contains the same first byte as the code in sram, and if
>> they do not match we know we have lost context and must recopy the
>> functions to the previous address to maintain PM functionality.
>>
>> Signed-off-by: Dave Gerlach <[email protected]>
>> Signed-off-by: Keerthy <[email protected]>
>> ---
>>   drivers/memory/ti-emif-pm.c | 24 ++++++++++++++++++++++++
>>   1 file changed, 24 insertions(+)
>>
>> diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c
>> index 632651f..ec4a62c 100644
>> --- a/drivers/memory/ti-emif-pm.c
>> +++ b/drivers/memory/ti-emif-pm.c
>> @@ -249,6 +249,25 @@ int ti_emif_get_mem_type(void)
>>   };
>>   MODULE_DEVICE_TABLE(of, ti_emif_of_match);
>>   +#ifdef CONFIG_PM_SLEEP
>> +static int ti_emif_resume(struct device *dev)
>> +{
>> +    unsigned long tmp =
>> +            __raw_readl((void *)emif_instance->ti_emif_sram_virt);
>> +
>> +    /*
>> +     * Check to see if what we are copying is already present in the
>> +     * first byte at the destination, only copy if it is not which
>> +     * indicates we have lost context and sram no longer contains
>> +     * the PM code
>> +     */
>
>> +    if (tmp != ti_emif_sram)
>> +        ti_emif_push_sram(dev, emif_instance);
>> +
>> +    return 0;
>> +}
>> +#endif /* CONFIG_PM_SLEEP */
> Instead of this indirect method , why can't just check the previous
> deep sleep mode and based on that do copy or not. EMIF power status
> register should have something like that ?

I will check if we have a register that tells previous state of sram,
not sure of it.
>
> Another minor point is even though there is nothing to do in suspend,
> might be good to have a callback with comment that nothing to do with
> some explanation why not. Don't have strong preference but may for
> better readability.
>
> Regards,
> Santosh
>
>

2018-05-22 07:59:25

by Keerthy

[permalink] [raw]
Subject: Re: [PATCH 12/14] OMAP: CLK: CLKSRC: Add suspend resume hooks



On Thursday 12 April 2018 07:57 PM, Tony Lindgren wrote:
> * Keerthy <[email protected]> [180412 03:56]:
>> Add the save and restore for clksrc as part of suspend and resume
>> so that it saves the counter value and restores. This is needed in
>> modes like rtc+ddr in self-refresh not doing this stalls the time.
>
> I suspect this too should really happen with cpu_pm.

I believe going by the previous set of patches this fits better with
suspend/resume?

>
>> --- a/arch/arm/mach-omap2/timer.c
>> +++ b/arch/arm/mach-omap2/timer.c
>> @@ -442,6 +442,38 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
>> return ret;
>> }
>>
>> +static unsigned int omap2_gptimer_clksrc_load;
>> +
>> +static void omap2_gptimer_clksrc_suspend(struct clocksource *unused)
>> +{
>> + struct omap_hwmod *oh;
>> +
>> + omap2_gptimer_clksrc_load =
>> + __omap_dm_timer_read_counter(&clksrc, OMAP_TIMER_NONPOSTED);
>> +
>> + oh = omap_hwmod_lookup(clocksource_gpt.name);
>> + if (!oh)
>> + return;
>> +
>> + omap_hwmod_idle(oh);
>> +}
>
> Probably no need to look up the hwmod every time? Especially if am437x
> will start supporting deeper idle modes during runtime.

Like clockevent i will store the hwmod pointer for clocksource as well.

>
> And probably the cpu_pm notifies should be directly in the hwmod
> code so we don't need to add more any more dependencies to hwmod
> functions to timer code. We should have this code move to drivers
> anyways at some point.
>
> Regards,
>
> Tony
>

2018-05-22 13:40:38

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH 12/14] OMAP: CLK: CLKSRC: Add suspend resume hooks

* Keerthy <[email protected]> [180522 07:59]:
> On Thursday 12 April 2018 07:57 PM, Tony Lindgren wrote:
> > * Keerthy <[email protected]> [180412 03:56]:
> >> Add the save and restore for clksrc as part of suspend and resume
> >> so that it saves the counter value and restores. This is needed in
> >> modes like rtc+ddr in self-refresh not doing this stalls the time.
> >
> > I suspect this too should really happen with cpu_pm.
>
> I believe going by the previous set of patches this fits better with
> suspend/resume?

Yes if you don't need it for cpuidle and other SoC variants
don't need it for cpuidle.

> > Probably no need to look up the hwmod every time? Especially if am437x
> > will start supporting deeper idle modes during runtime.
>
> Like clockevent i will store the hwmod pointer for clocksource as well.

OK

Regards,

Tony

2018-05-23 08:49:11

by Keerthy

[permalink] [raw]
Subject: Re: [PATCH 01/14] memory: ti-emif-sram: Add resume function to recopy sram code



On Monday 16 April 2018 03:59 PM, Keerthy wrote:
>
>
> On Thursday 12 April 2018 10:14 PM, [email protected] wrote:
>> On 4/11/18 9:53 PM, Keerthy wrote:
>>> From: Dave Gerlach <[email protected]>
>>>
>>> After an RTC+DDR cycle we lose sram context so emif pm functions present
>>> in sram are lost. We can check if the first byte of the original
>>> code in DDR contains the same first byte as the code in sram, and if
>>> they do not match we know we have lost context and must recopy the
>>> functions to the previous address to maintain PM functionality.
>>>
>>> Signed-off-by: Dave Gerlach <[email protected]>
>>> Signed-off-by: Keerthy <[email protected]>
>>> ---
>>>   drivers/memory/ti-emif-pm.c | 24 ++++++++++++++++++++++++
>>>   1 file changed, 24 insertions(+)
>>>
>>> diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c
>>> index 632651f..ec4a62c 100644
>>> --- a/drivers/memory/ti-emif-pm.c
>>> +++ b/drivers/memory/ti-emif-pm.c
>>> @@ -249,6 +249,25 @@ int ti_emif_get_mem_type(void)
>>>   };
>>>   MODULE_DEVICE_TABLE(of, ti_emif_of_match);
>>>   +#ifdef CONFIG_PM_SLEEP
>>> +static int ti_emif_resume(struct device *dev)
>>> +{
>>> +    unsigned long tmp =
>>> +            __raw_readl((void *)emif_instance->ti_emif_sram_virt);
>>> +
>>> +    /*
>>> +     * Check to see if what we are copying is already present in the
>>> +     * first byte at the destination, only copy if it is not which
>>> +     * indicates we have lost context and sram no longer contains
>>> +     * the PM code
>>> +     */
>>
>>> +    if (tmp != ti_emif_sram)
>>> +        ti_emif_push_sram(dev, emif_instance);
>>> +
>>> +    return 0;
>>> +}
>>> +#endif /* CONFIG_PM_SLEEP */
>> Instead of this indirect method , why can't just check the previous
>> deep sleep mode and based on that do copy or not. EMIF power status
>> register should have something like that ?
>
> I will check if we have a register that tells the previous state of sram.

Unfortunately i do not see any such register for knowing SRAM previous
state in am43 TRM and hence this indirect way of knowing.

http://www.ti.com/lit/ug/spruhl7h/spruhl7h.pdf

>
>>
>> Another minor point is even though there is nothing to do in suspend,
>> might be good to have a callback with comment that nothing to do with
>> some explanation why not. Don't have strong preference but may for
>> better readability.

I can add a blank suspend call with comment

"The contents are already present in DDR hence no need to explicitly save"

The comment in resume function pretty much explains the above. So let me
know if i need to add the suspend callback.

Regards,
Keerthy

>
> Okay. Thanks a lot for the quick feedback!
>
>>
>> Regards,
>> Santosh
>>
>>

2018-05-23 16:44:54

by Santosh Shilimkar

[permalink] [raw]
Subject: Re: [PATCH 01/14] memory: ti-emif-sram: Add resume function to recopy sram code


On 5/23/2018 1:47 AM, Keerthy wrote:
>
>
> On Monday 16 April 2018 03:59 PM, Keerthy wrote:
>>
[..]

>>> Instead of this indirect method , why can't just check the previous
>>> deep sleep mode and based on that do copy or not. EMIF power status
>>> register should have something like that ?
>>
>> I will check if we have a register that tells the previous state of sram.
>
> Unfortunately i do not see any such register for knowing SRAM previous
> state in am43 TRM and hence this indirect way of knowing.
>
OK.

>
>>
>>>
>>> Another minor point is even though there is nothing to do in suspend,
>>> might be good to have a callback with comment that nothing to do with
>>> some explanation why not. Don't have strong preference but may for
>>> better readability.
>
> I can add a blank suspend call with comment
>
> "The contents are already present in DDR hence no need to explicitly save"
>
> The comment in resume function pretty much explains the above. So let me
> know if i need to add the suspend callback.
> Please add the empty suspend callback with comment.

Regards,
Santosh