From 38853979e6dce8466a1f611cadebc0f00adb901b Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Tue, 26 Jun 2018 10:05:17 -0700 Subject: memory: ti-emif-sram: Add resume function to recopy sram code 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 Signed-off-by: Keerthy Signed-off-by: Santosh Shilimkar --- drivers/memory/ti-emif-pm.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c index 632651f4b6e8..2250d03ea17f 100644 --- a/drivers/memory/ti-emif-pm.c +++ b/drivers/memory/ti-emif-pm.c @@ -249,6 +249,34 @@ static const struct of_device_id ti_emif_of_match[] = { }; 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; +} + +static int ti_emif_suspend(struct device *dev) +{ + /* + * The contents will be present in DDR hence no need to + * explicitly save + */ + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + static int ti_emif_probe(struct platform_device *pdev) { int ret; @@ -308,12 +336,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(ti_emif_suspend, 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); -- cgit v1.2.3 From 7a872b6fb7fdc4213e9bb4e1c83a65e6b8af7ebd Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 4 Jul 2018 20:19:06 -0700 Subject: soc: ti: wkup_m3_ipc: Add rtc_only with ddr in self refresh mode support Adds rtc_only support. This needs resume function to shutdown and reboot the m3. Signed-off-by: Keerthy Signed-off-by: Santosh Shilimkar --- drivers/soc/ti/wkup_m3_ipc.c | 41 +++++++++++++++++++++++++++++++++++++++++ include/linux/wkup_m3_ipc.h | 3 +++ 2 files changed, 44 insertions(+) diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 369aef5e7228..b732c39e2754 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -329,12 +329,24 @@ static int wkup_m3_finish_low_power(struct wkup_m3_ipc *m3_ipc) return 0; } +/** + * wkup_m3_set_rtc_only - Set the rtc_only flag + * @wkup_m3_wakeup: struct wkup_m3_wakeup_src * gets assigned the + * wakeup src value + */ +static void wkup_m3_set_rtc_only(struct wkup_m3_ipc *m3_ipc) +{ + if (m3_ipc_state) + m3_ipc_state->is_rtc_only = true; +} + static struct wkup_m3_ipc_ops ipc_ops = { .set_mem_type = wkup_m3_set_mem_type, .set_resume_address = wkup_m3_set_resume_address, .prepare_low_power = wkup_m3_prepare_low_power, .finish_low_power = wkup_m3_finish_low_power, .request_pm_status = wkup_m3_request_pm_status, + .set_rtc_only = wkup_m3_set_rtc_only, }; /** @@ -484,6 +496,32 @@ static int wkup_m3_ipc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int wkup_m3_ipc_suspend(struct device *dev) +{ + /* + * Nothing needs to be done on suspend even with rtc_only flag set + */ + return 0; +} + +static int wkup_m3_ipc_resume(struct device *dev) +{ + if (m3_ipc_state->is_rtc_only) { + rproc_shutdown(m3_ipc_state->rproc); + rproc_boot(m3_ipc_state->rproc); + } + + m3_ipc_state->is_rtc_only = false; + + return 0; +} + +static const struct dev_pm_ops wkup_m3_ipc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(wkup_m3_ipc_suspend, wkup_m3_ipc_resume) +}; +#endif + static const struct of_device_id wkup_m3_ipc_of_match[] = { { .compatible = "ti,am3352-wkup-m3-ipc", }, { .compatible = "ti,am4372-wkup-m3-ipc", }, @@ -497,6 +535,9 @@ static struct platform_driver wkup_m3_ipc_driver = { .driver = { .name = "wkup_m3_ipc", .of_match_table = wkup_m3_ipc_of_match, +#ifdef CONFIG_PM + .pm = &wkup_m3_ipc_pm_ops, +#endif }, }; diff --git a/include/linux/wkup_m3_ipc.h b/include/linux/wkup_m3_ipc.h index d6ba7d39a62f..d639df15e8ba 100644 --- a/include/linux/wkup_m3_ipc.h +++ b/include/linux/wkup_m3_ipc.h @@ -40,6 +40,7 @@ struct wkup_m3_ipc { struct mbox_chan *mbox; struct wkup_m3_ipc_ops *ops; + int is_rtc_only; }; struct wkup_m3_ipc_ops { @@ -48,8 +49,10 @@ struct wkup_m3_ipc_ops { int (*prepare_low_power)(struct wkup_m3_ipc *m3_ipc, int state); int (*finish_low_power)(struct wkup_m3_ipc *m3_ipc); int (*request_pm_status)(struct wkup_m3_ipc *m3_ipc); + void (*set_rtc_only)(struct wkup_m3_ipc *m3_ipc); }; struct wkup_m3_ipc *wkup_m3_ipc_get(void); void wkup_m3_ipc_put(struct wkup_m3_ipc *m3_ipc); +void wkup_m3_set_rtc_only_mode(void); #endif /* _LINUX_WKUP_M3_IPC_H */ -- cgit v1.2.3 From ec93b62fec9c7138d2b75334d192ecc12376f885 Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Wed, 4 Jul 2018 20:19:06 -0700 Subject: soc: ti: wkup_m3_ipc: Add wkup_m3_request_wake_src Add wkup_m3_request_wake_src to allow users to get the name of the wakeup source after a DeepSleep or Standby transition. Signed-off-by: Dave Gerlach Signed-off-by: Keerthy Signed-off-by: Santosh Shilimkar --- drivers/soc/ti/wkup_m3_ipc.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/wkup_m3_ipc.h | 6 ++++++ 2 files changed, 45 insertions(+) diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index b732c39e2754..6840688236b9 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -46,6 +46,7 @@ #define M3_BASELINE_VERSION 0x191 #define M3_STATUS_RESP_MASK (0xffff << 16) #define M3_FW_VERSION_MASK 0xffff +#define M3_WAKE_SRC_MASK 0xff #define M3_STATE_UNKNOWN 0 #define M3_STATE_RESET 1 @@ -55,6 +56,23 @@ static struct wkup_m3_ipc *m3_ipc_state; +static const struct wkup_m3_wakeup_src wakeups[] = { + {.irq_nr = 35, .src = "USB0_PHY"}, + {.irq_nr = 36, .src = "USB1_PHY"}, + {.irq_nr = 40, .src = "I2C0"}, + {.irq_nr = 41, .src = "RTC Timer"}, + {.irq_nr = 42, .src = "RTC Alarm"}, + {.irq_nr = 43, .src = "Timer0"}, + {.irq_nr = 44, .src = "Timer1"}, + {.irq_nr = 45, .src = "UART"}, + {.irq_nr = 46, .src = "GPIO0"}, + {.irq_nr = 48, .src = "MPU_WAKE"}, + {.irq_nr = 49, .src = "WDT0"}, + {.irq_nr = 50, .src = "WDT1"}, + {.irq_nr = 51, .src = "ADC_TSC"}, + {.irq_nr = 0, .src = "Unknown"}, +}; + static void am33xx_txev_eoi(struct wkup_m3_ipc *m3_ipc) { writel(AM33XX_M3_TXEV_ACK, @@ -329,6 +347,26 @@ static int wkup_m3_finish_low_power(struct wkup_m3_ipc *m3_ipc) return 0; } +/** + * wkup_m3_request_wake_src - Get the wakeup source info passed from wkup_m3 + * @m3_ipc: Pointer to wkup_m3_ipc context + */ +static const char *wkup_m3_request_wake_src(struct wkup_m3_ipc *m3_ipc) +{ + unsigned int wakeup_src_idx; + int j, val; + + val = wkup_m3_ctrl_ipc_read(m3_ipc, 6); + + wakeup_src_idx = val & M3_WAKE_SRC_MASK; + + for (j = 0; j < ARRAY_SIZE(wakeups) - 1; j++) { + if (wakeups[j].irq_nr == wakeup_src_idx) + return wakeups[j].src; + } + return wakeups[j].src; +} + /** * wkup_m3_set_rtc_only - Set the rtc_only flag * @wkup_m3_wakeup: struct wkup_m3_wakeup_src * gets assigned the @@ -346,6 +384,7 @@ static struct wkup_m3_ipc_ops ipc_ops = { .prepare_low_power = wkup_m3_prepare_low_power, .finish_low_power = wkup_m3_finish_low_power, .request_pm_status = wkup_m3_request_pm_status, + .request_wake_src = wkup_m3_request_wake_src, .set_rtc_only = wkup_m3_set_rtc_only, }; diff --git a/include/linux/wkup_m3_ipc.h b/include/linux/wkup_m3_ipc.h index d639df15e8ba..e497e621dbb7 100644 --- a/include/linux/wkup_m3_ipc.h +++ b/include/linux/wkup_m3_ipc.h @@ -43,12 +43,18 @@ struct wkup_m3_ipc { int is_rtc_only; }; +struct wkup_m3_wakeup_src { + int irq_nr; + char src[10]; +}; + struct wkup_m3_ipc_ops { void (*set_mem_type)(struct wkup_m3_ipc *m3_ipc, int mem_type); void (*set_resume_address)(struct wkup_m3_ipc *m3_ipc, void *addr); int (*prepare_low_power)(struct wkup_m3_ipc *m3_ipc, int state); int (*finish_low_power)(struct wkup_m3_ipc *m3_ipc); int (*request_pm_status)(struct wkup_m3_ipc *m3_ipc); + const char *(*request_wake_src)(struct wkup_m3_ipc *m3_ipc); void (*set_rtc_only)(struct wkup_m3_ipc *m3_ipc); }; -- cgit v1.2.3 From 990c10091db318c7eb7e8935c86b6f7c01585015 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 6 Jul 2018 09:47:51 -0700 Subject: soc: ti: wkup_m3_ipc: mark PM functions as __maybe_unused Everyone gets these #ifdefs wrong, leading to another warning here: drivers/soc/ti/wkup_m3_ipc.c:547:12: error: 'wkup_m3_ipc_resume' defined but not used [-Werror=unused-function] static int wkup_m3_ipc_resume(struct device *dev) drivers/soc/ti/wkup_m3_ipc.c:539:12: error: 'wkup_m3_ipc_suspend' defined but not used [-Werror=unused-function] static int wkup_m3_ipc_suspend(struct device *dev) The easiest way to get it right is to remove all the #ifdefs and let the compiler drop the unused functions silently after we mark them as __maybe_unused. Fixes: 7a872b6fb7fd ("soc: ti: wkup_m3_ipc: Add rtc_only with ddr in self refresh mode support") Signed-off-by: Arnd Bergmann Signed-off-by: Santosh Shilimkar --- drivers/soc/ti/wkup_m3_ipc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 6840688236b9..f5cb8c0af09f 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -535,8 +535,7 @@ static int wkup_m3_ipc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int wkup_m3_ipc_suspend(struct device *dev) +static int __maybe_unused wkup_m3_ipc_suspend(struct device *dev) { /* * Nothing needs to be done on suspend even with rtc_only flag set @@ -544,7 +543,7 @@ static int wkup_m3_ipc_suspend(struct device *dev) return 0; } -static int wkup_m3_ipc_resume(struct device *dev) +static int __maybe_unused wkup_m3_ipc_resume(struct device *dev) { if (m3_ipc_state->is_rtc_only) { rproc_shutdown(m3_ipc_state->rproc); @@ -559,7 +558,6 @@ static int wkup_m3_ipc_resume(struct device *dev) static const struct dev_pm_ops wkup_m3_ipc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(wkup_m3_ipc_suspend, wkup_m3_ipc_resume) }; -#endif static const struct of_device_id wkup_m3_ipc_of_match[] = { { .compatible = "ti,am3352-wkup-m3-ipc", }, @@ -574,9 +572,7 @@ static struct platform_driver wkup_m3_ipc_driver = { .driver = { .name = "wkup_m3_ipc", .of_match_table = wkup_m3_ipc_of_match, -#ifdef CONFIG_PM .pm = &wkup_m3_ipc_pm_ops, -#endif }, }; -- cgit v1.2.3