xref: /openbmc/linux/drivers/soc/ti/pm33xx.c (revision 6afaff1c)
1afe761f8SDave Gerlach // SPDX-License-Identifier: GPL-2.0
2afe761f8SDave Gerlach /*
3afe761f8SDave Gerlach  * AM33XX Power Management Routines
4afe761f8SDave Gerlach  *
5afe761f8SDave Gerlach  * Copyright (C) 2012-2018 Texas Instruments Incorporated - http://www.ti.com/
6afe761f8SDave Gerlach  *	Vaibhav Bedia, Dave Gerlach
7afe761f8SDave Gerlach  */
8afe761f8SDave Gerlach 
95a99ae00SKeerthy #include <linux/clk.h>
10afe761f8SDave Gerlach #include <linux/cpu.h>
11afe761f8SDave Gerlach #include <linux/err.h>
12afe761f8SDave Gerlach #include <linux/genalloc.h>
13afe761f8SDave Gerlach #include <linux/kernel.h>
14afe761f8SDave Gerlach #include <linux/init.h>
15afe761f8SDave Gerlach #include <linux/io.h>
16afe761f8SDave Gerlach #include <linux/module.h>
175a99ae00SKeerthy #include <linux/nvmem-consumer.h>
18afe761f8SDave Gerlach #include <linux/of.h>
19afe761f8SDave Gerlach #include <linux/platform_data/pm33xx.h>
20afe761f8SDave Gerlach #include <linux/platform_device.h>
215a99ae00SKeerthy #include <linux/rtc.h>
225a99ae00SKeerthy #include <linux/rtc/rtc-omap.h>
23afe761f8SDave Gerlach #include <linux/sizes.h>
24afe761f8SDave Gerlach #include <linux/sram.h>
25afe761f8SDave Gerlach #include <linux/suspend.h>
26afe761f8SDave Gerlach #include <linux/ti-emif-sram.h>
27afe761f8SDave Gerlach #include <linux/wkup_m3_ipc.h>
28afe761f8SDave Gerlach 
29afe761f8SDave Gerlach #include <asm/proc-fns.h>
30afe761f8SDave Gerlach #include <asm/suspend.h>
31afe761f8SDave Gerlach #include <asm/system_misc.h>
32afe761f8SDave Gerlach 
33afe761f8SDave Gerlach #define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \
34afe761f8SDave Gerlach 					 (unsigned long)pm_sram->do_wfi)
35afe761f8SDave Gerlach 
365a99ae00SKeerthy #define RTC_SCRATCH_RESUME_REG	0
375a99ae00SKeerthy #define RTC_SCRATCH_MAGIC_REG	1
385a99ae00SKeerthy #define RTC_REG_BOOT_MAGIC	0x8cd0 /* RTC */
395a99ae00SKeerthy #define GIC_INT_SET_PENDING_BASE 0x200
405a99ae00SKeerthy #define AM43XX_GIC_DIST_BASE	0x48241000
415a99ae00SKeerthy 
425a99ae00SKeerthy static u32 rtc_magic_val;
435a99ae00SKeerthy 
44afe761f8SDave Gerlach static int (*am33xx_do_wfi_sram)(unsigned long unused);
45afe761f8SDave Gerlach static phys_addr_t am33xx_do_wfi_sram_phys;
46afe761f8SDave Gerlach 
47afe761f8SDave Gerlach static struct gen_pool *sram_pool, *sram_pool_data;
48afe761f8SDave Gerlach static unsigned long ocmcram_location, ocmcram_location_data;
49afe761f8SDave Gerlach 
505a99ae00SKeerthy static struct rtc_device *omap_rtc;
515a99ae00SKeerthy static void __iomem *gic_dist_base;
525a99ae00SKeerthy 
53afe761f8SDave Gerlach static struct am33xx_pm_platform_data *pm_ops;
54afe761f8SDave Gerlach static struct am33xx_pm_sram_addr *pm_sram;
55afe761f8SDave Gerlach 
56afe761f8SDave Gerlach static struct device *pm33xx_dev;
57afe761f8SDave Gerlach static struct wkup_m3_ipc *m3_ipc;
58afe761f8SDave Gerlach 
595a99ae00SKeerthy #ifdef CONFIG_SUSPEND
605a99ae00SKeerthy static int rtc_only_idle;
615a99ae00SKeerthy static int retrigger_irq;
6274655749SDave Gerlach static unsigned long suspend_wfi_flags;
6374655749SDave Gerlach 
645a99ae00SKeerthy static struct wkup_m3_wakeup_src wakeup_src = {.irq_nr = 0,
655a99ae00SKeerthy 	.src = "Unknown",
665a99ae00SKeerthy };
675a99ae00SKeerthy 
685a99ae00SKeerthy static struct wkup_m3_wakeup_src rtc_alarm_wakeup = {
695a99ae00SKeerthy 	.irq_nr = 108, .src = "RTC Alarm",
705a99ae00SKeerthy };
715a99ae00SKeerthy 
725a99ae00SKeerthy static struct wkup_m3_wakeup_src rtc_ext_wakeup = {
735a99ae00SKeerthy 	.irq_nr = 0, .src = "Ext wakeup",
745a99ae00SKeerthy };
755a99ae00SKeerthy #endif
765a99ae00SKeerthy 
77afe761f8SDave Gerlach static u32 sram_suspend_address(unsigned long addr)
78afe761f8SDave Gerlach {
79afe761f8SDave Gerlach 	return ((unsigned long)am33xx_do_wfi_sram +
80afe761f8SDave Gerlach 		AMX3_PM_SRAM_SYMBOL_OFFSET(addr));
81afe761f8SDave Gerlach }
82afe761f8SDave Gerlach 
831c6c0354SKeerthy static int am33xx_push_sram_idle(void)
841c6c0354SKeerthy {
851c6c0354SKeerthy 	struct am33xx_pm_ro_sram_data ro_sram_data;
861c6c0354SKeerthy 	int ret;
871c6c0354SKeerthy 	u32 table_addr, ro_data_addr;
881c6c0354SKeerthy 	void *copy_addr;
891c6c0354SKeerthy 
901c6c0354SKeerthy 	ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data;
911c6c0354SKeerthy 	ro_sram_data.amx3_pm_sram_data_phys =
921c6c0354SKeerthy 		gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data);
931c6c0354SKeerthy 	ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr();
941c6c0354SKeerthy 
951c6c0354SKeerthy 	/* Save physical address to calculate resume offset during pm init */
961c6c0354SKeerthy 	am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool,
971c6c0354SKeerthy 							ocmcram_location);
981c6c0354SKeerthy 
991c6c0354SKeerthy 	am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location,
1001c6c0354SKeerthy 					    pm_sram->do_wfi,
1011c6c0354SKeerthy 					    *pm_sram->do_wfi_sz);
1021c6c0354SKeerthy 	if (!am33xx_do_wfi_sram) {
1031c6c0354SKeerthy 		dev_err(pm33xx_dev,
1041c6c0354SKeerthy 			"PM: %s: am33xx_do_wfi copy to sram failed\n",
1051c6c0354SKeerthy 			__func__);
1061c6c0354SKeerthy 		return -ENODEV;
1071c6c0354SKeerthy 	}
1081c6c0354SKeerthy 
1091c6c0354SKeerthy 	table_addr =
1101c6c0354SKeerthy 		sram_suspend_address((unsigned long)pm_sram->emif_sram_table);
1111c6c0354SKeerthy 	ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr);
1121c6c0354SKeerthy 	if (ret) {
1131c6c0354SKeerthy 		dev_dbg(pm33xx_dev,
1141c6c0354SKeerthy 			"PM: %s: EMIF function copy failed\n", __func__);
1151c6c0354SKeerthy 		return -EPROBE_DEFER;
1161c6c0354SKeerthy 	}
1171c6c0354SKeerthy 
1181c6c0354SKeerthy 	ro_data_addr =
1191c6c0354SKeerthy 		sram_suspend_address((unsigned long)pm_sram->ro_sram_data);
1201c6c0354SKeerthy 	copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr,
1211c6c0354SKeerthy 				   &ro_sram_data,
1221c6c0354SKeerthy 				   sizeof(ro_sram_data));
1231c6c0354SKeerthy 	if (!copy_addr) {
1241c6c0354SKeerthy 		dev_err(pm33xx_dev,
1251c6c0354SKeerthy 			"PM: %s: ro_sram_data copy to sram failed\n",
1261c6c0354SKeerthy 			__func__);
1271c6c0354SKeerthy 		return -ENODEV;
1281c6c0354SKeerthy 	}
1291c6c0354SKeerthy 
1301c6c0354SKeerthy 	return 0;
1311c6c0354SKeerthy }
1321c6c0354SKeerthy 
1336afaff1cSDave Gerlach static int am33xx_do_sram_idle(u32 wfi_flags)
1346afaff1cSDave Gerlach {
1356afaff1cSDave Gerlach 	int ret = 0;
1366afaff1cSDave Gerlach 
1376afaff1cSDave Gerlach 	if (!m3_ipc || !pm_ops)
1386afaff1cSDave Gerlach 		return 0;
1396afaff1cSDave Gerlach 
1406afaff1cSDave Gerlach 	if (wfi_flags & WFI_FLAG_WAKE_M3)
1416afaff1cSDave Gerlach 		ret = m3_ipc->ops->prepare_low_power(m3_ipc, WKUP_M3_IDLE);
1426afaff1cSDave Gerlach 
1436afaff1cSDave Gerlach 	return pm_ops->cpu_suspend(am33xx_do_wfi_sram, wfi_flags);
1446afaff1cSDave Gerlach }
1456afaff1cSDave Gerlach 
1465a99ae00SKeerthy static int __init am43xx_map_gic(void)
1475a99ae00SKeerthy {
1485a99ae00SKeerthy 	gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K);
1495a99ae00SKeerthy 
1505a99ae00SKeerthy 	if (!gic_dist_base)
1515a99ae00SKeerthy 		return -ENOMEM;
1525a99ae00SKeerthy 
1535a99ae00SKeerthy 	return 0;
1545a99ae00SKeerthy }
1555a99ae00SKeerthy 
156afe761f8SDave Gerlach #ifdef CONFIG_SUSPEND
1574a65bbb9SYueHaibing static struct wkup_m3_wakeup_src rtc_wake_src(void)
1585a99ae00SKeerthy {
1595a99ae00SKeerthy 	u32 i;
1605a99ae00SKeerthy 
1615a99ae00SKeerthy 	i = __raw_readl(pm_ops->get_rtc_base_addr() + 0x44) & 0x40;
1625a99ae00SKeerthy 
1635a99ae00SKeerthy 	if (i) {
1645a99ae00SKeerthy 		retrigger_irq = rtc_alarm_wakeup.irq_nr;
1655a99ae00SKeerthy 		return rtc_alarm_wakeup;
1665a99ae00SKeerthy 	}
1675a99ae00SKeerthy 
1685a99ae00SKeerthy 	retrigger_irq = rtc_ext_wakeup.irq_nr;
1695a99ae00SKeerthy 
1705a99ae00SKeerthy 	return rtc_ext_wakeup;
1715a99ae00SKeerthy }
1725a99ae00SKeerthy 
1734a65bbb9SYueHaibing static int am33xx_rtc_only_idle(unsigned long wfi_flags)
1745a99ae00SKeerthy {
1755a99ae00SKeerthy 	omap_rtc_power_off_program(&omap_rtc->dev);
1765a99ae00SKeerthy 	am33xx_do_wfi_sram(wfi_flags);
1775a99ae00SKeerthy 	return 0;
1785a99ae00SKeerthy }
1795a99ae00SKeerthy 
180afe761f8SDave Gerlach static int am33xx_pm_suspend(suspend_state_t suspend_state)
181afe761f8SDave Gerlach {
182afe761f8SDave Gerlach 	int i, ret = 0;
183afe761f8SDave Gerlach 
1845a99ae00SKeerthy 	if (suspend_state == PM_SUSPEND_MEM &&
1855a99ae00SKeerthy 	    pm_ops->check_off_mode_enable()) {
1865a99ae00SKeerthy 		pm_ops->prepare_rtc_suspend();
1875a99ae00SKeerthy 		pm_ops->save_context();
1885a99ae00SKeerthy 		suspend_wfi_flags |= WFI_FLAG_RTC_ONLY;
1895a99ae00SKeerthy 		clk_save_context();
1905a99ae00SKeerthy 		ret = pm_ops->soc_suspend(suspend_state, am33xx_rtc_only_idle,
1915a99ae00SKeerthy 					  suspend_wfi_flags);
1925a99ae00SKeerthy 
1935a99ae00SKeerthy 		suspend_wfi_flags &= ~WFI_FLAG_RTC_ONLY;
19445450f36SKeerthy 		dev_info(pm33xx_dev, "Entering RTC Only mode with DDR in self-refresh\n");
1955a99ae00SKeerthy 
1965a99ae00SKeerthy 		if (!ret) {
1975a99ae00SKeerthy 			clk_restore_context();
1985a99ae00SKeerthy 			pm_ops->restore_context();
1995a99ae00SKeerthy 			m3_ipc->ops->set_rtc_only(m3_ipc);
2005a99ae00SKeerthy 			am33xx_push_sram_idle();
2015a99ae00SKeerthy 		}
2025a99ae00SKeerthy 	} else {
2035a99ae00SKeerthy 		ret = pm_ops->soc_suspend(suspend_state, am33xx_do_wfi_sram,
2045a99ae00SKeerthy 					  suspend_wfi_flags);
2055a99ae00SKeerthy 	}
206afe761f8SDave Gerlach 
207afe761f8SDave Gerlach 	if (ret) {
208afe761f8SDave Gerlach 		dev_err(pm33xx_dev, "PM: Kernel suspend failure\n");
209afe761f8SDave Gerlach 	} else {
210afe761f8SDave Gerlach 		i = m3_ipc->ops->request_pm_status(m3_ipc);
211afe761f8SDave Gerlach 
212afe761f8SDave Gerlach 		switch (i) {
213afe761f8SDave Gerlach 		case 0:
214afe761f8SDave Gerlach 			dev_info(pm33xx_dev,
215afe761f8SDave Gerlach 				 "PM: Successfully put all powerdomains to target state\n");
216afe761f8SDave Gerlach 			break;
217afe761f8SDave Gerlach 		case 1:
218afe761f8SDave Gerlach 			dev_err(pm33xx_dev,
219afe761f8SDave Gerlach 				"PM: Could not transition all powerdomains to target state\n");
220afe761f8SDave Gerlach 			ret = -1;
221afe761f8SDave Gerlach 			break;
222afe761f8SDave Gerlach 		default:
223afe761f8SDave Gerlach 			dev_err(pm33xx_dev,
224afe761f8SDave Gerlach 				"PM: CM3 returned unknown result = %d\n", i);
225afe761f8SDave Gerlach 			ret = -1;
226afe761f8SDave Gerlach 		}
2275a99ae00SKeerthy 
2285a99ae00SKeerthy 		/* print the wakeup reason */
2295a99ae00SKeerthy 		if (rtc_only_idle) {
2305a99ae00SKeerthy 			wakeup_src = rtc_wake_src();
2315a99ae00SKeerthy 			pr_info("PM: Wakeup source %s\n", wakeup_src.src);
2325a99ae00SKeerthy 		} else {
2335a99ae00SKeerthy 			pr_info("PM: Wakeup source %s\n",
2345a99ae00SKeerthy 				m3_ipc->ops->request_wake_src(m3_ipc));
235afe761f8SDave Gerlach 		}
2365a99ae00SKeerthy 	}
2375a99ae00SKeerthy 
2385a99ae00SKeerthy 	if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable())
2395a99ae00SKeerthy 		pm_ops->prepare_rtc_resume();
240afe761f8SDave Gerlach 
241afe761f8SDave Gerlach 	return ret;
242afe761f8SDave Gerlach }
243afe761f8SDave Gerlach 
244afe761f8SDave Gerlach static int am33xx_pm_enter(suspend_state_t suspend_state)
245afe761f8SDave Gerlach {
246afe761f8SDave Gerlach 	int ret = 0;
247afe761f8SDave Gerlach 
248afe761f8SDave Gerlach 	switch (suspend_state) {
249afe761f8SDave Gerlach 	case PM_SUSPEND_MEM:
250afe761f8SDave Gerlach 	case PM_SUSPEND_STANDBY:
251afe761f8SDave Gerlach 		ret = am33xx_pm_suspend(suspend_state);
252afe761f8SDave Gerlach 		break;
253afe761f8SDave Gerlach 	default:
254afe761f8SDave Gerlach 		ret = -EINVAL;
255afe761f8SDave Gerlach 	}
256afe761f8SDave Gerlach 
257afe761f8SDave Gerlach 	return ret;
258afe761f8SDave Gerlach }
259afe761f8SDave Gerlach 
260afe761f8SDave Gerlach static int am33xx_pm_begin(suspend_state_t state)
261afe761f8SDave Gerlach {
262afe761f8SDave Gerlach 	int ret = -EINVAL;
2635a99ae00SKeerthy 	struct nvmem_device *nvmem;
2645a99ae00SKeerthy 
2655a99ae00SKeerthy 	if (state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) {
2665a99ae00SKeerthy 		nvmem = devm_nvmem_device_get(&omap_rtc->dev,
2675a99ae00SKeerthy 					      "omap_rtc_scratch0");
268d8e0cecbSKeerthy 		if (!IS_ERR(nvmem))
2695a99ae00SKeerthy 			nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4,
2705a99ae00SKeerthy 					   (void *)&rtc_magic_val);
2715a99ae00SKeerthy 		rtc_only_idle = 1;
2725a99ae00SKeerthy 	} else {
2735a99ae00SKeerthy 		rtc_only_idle = 0;
2745a99ae00SKeerthy 	}
275afe761f8SDave Gerlach 
2766afaff1cSDave Gerlach 	pm_ops->begin_suspend();
2776afaff1cSDave Gerlach 
278afe761f8SDave Gerlach 	switch (state) {
279afe761f8SDave Gerlach 	case PM_SUSPEND_MEM:
280afe761f8SDave Gerlach 		ret = m3_ipc->ops->prepare_low_power(m3_ipc, WKUP_M3_DEEPSLEEP);
281afe761f8SDave Gerlach 		break;
282afe761f8SDave Gerlach 	case PM_SUSPEND_STANDBY:
283afe761f8SDave Gerlach 		ret = m3_ipc->ops->prepare_low_power(m3_ipc, WKUP_M3_STANDBY);
284afe761f8SDave Gerlach 		break;
285afe761f8SDave Gerlach 	}
286afe761f8SDave Gerlach 
287afe761f8SDave Gerlach 	return ret;
288afe761f8SDave Gerlach }
289afe761f8SDave Gerlach 
290afe761f8SDave Gerlach static void am33xx_pm_end(void)
291afe761f8SDave Gerlach {
2925a99ae00SKeerthy 	u32 val = 0;
2935a99ae00SKeerthy 	struct nvmem_device *nvmem;
2945a99ae00SKeerthy 
2955a99ae00SKeerthy 	nvmem = devm_nvmem_device_get(&omap_rtc->dev, "omap_rtc_scratch0");
296d8e0cecbSKeerthy 	if (IS_ERR(nvmem))
297d8e0cecbSKeerthy 		return;
298d8e0cecbSKeerthy 
299afe761f8SDave Gerlach 	m3_ipc->ops->finish_low_power(m3_ipc);
3005a99ae00SKeerthy 	if (rtc_only_idle) {
301d8e0cecbSKeerthy 		if (retrigger_irq) {
3025a99ae00SKeerthy 			/*
3035a99ae00SKeerthy 			 * 32 bits of Interrupt Set-Pending correspond to 32
3045a99ae00SKeerthy 			 * 32 interrupts. Compute the bit offset of the
3055a99ae00SKeerthy 			 * Interrupt and set that particular bit
3065a99ae00SKeerthy 			 * Compute the register offset by dividing interrupt
3075a99ae00SKeerthy 			 * number by 32 and mutiplying by 4
3085a99ae00SKeerthy 			 */
3095a99ae00SKeerthy 			writel_relaxed(1 << (retrigger_irq & 31),
3105a99ae00SKeerthy 				       gic_dist_base + GIC_INT_SET_PENDING_BASE
3115a99ae00SKeerthy 				       + retrigger_irq / 32 * 4);
312d8e0cecbSKeerthy 		}
313d8e0cecbSKeerthy 
3145a99ae00SKeerthy 		nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4,
3155a99ae00SKeerthy 				   (void *)&val);
3165a99ae00SKeerthy 	}
3175a99ae00SKeerthy 
3185a99ae00SKeerthy 	rtc_only_idle = 0;
3196afaff1cSDave Gerlach 
3206afaff1cSDave Gerlach 	pm_ops->finish_suspend();
321afe761f8SDave Gerlach }
322afe761f8SDave Gerlach 
323afe761f8SDave Gerlach static int am33xx_pm_valid(suspend_state_t state)
324afe761f8SDave Gerlach {
325afe761f8SDave Gerlach 	switch (state) {
326afe761f8SDave Gerlach 	case PM_SUSPEND_STANDBY:
327afe761f8SDave Gerlach 	case PM_SUSPEND_MEM:
328afe761f8SDave Gerlach 		return 1;
329afe761f8SDave Gerlach 	default:
330afe761f8SDave Gerlach 		return 0;
331afe761f8SDave Gerlach 	}
332afe761f8SDave Gerlach }
333afe761f8SDave Gerlach 
334afe761f8SDave Gerlach static const struct platform_suspend_ops am33xx_pm_ops = {
335afe761f8SDave Gerlach 	.begin		= am33xx_pm_begin,
336afe761f8SDave Gerlach 	.end		= am33xx_pm_end,
337afe761f8SDave Gerlach 	.enter		= am33xx_pm_enter,
338afe761f8SDave Gerlach 	.valid		= am33xx_pm_valid,
339afe761f8SDave Gerlach };
340afe761f8SDave Gerlach #endif /* CONFIG_SUSPEND */
341afe761f8SDave Gerlach 
342afe761f8SDave Gerlach static void am33xx_pm_set_ipc_ops(void)
343afe761f8SDave Gerlach {
344afe761f8SDave Gerlach 	u32 resume_address;
345afe761f8SDave Gerlach 	int temp;
346afe761f8SDave Gerlach 
347afe761f8SDave Gerlach 	temp = ti_emif_get_mem_type();
348afe761f8SDave Gerlach 	if (temp < 0) {
349afe761f8SDave Gerlach 		dev_err(pm33xx_dev, "PM: Cannot determine memory type, no PM available\n");
350afe761f8SDave Gerlach 		return;
351afe761f8SDave Gerlach 	}
352afe761f8SDave Gerlach 	m3_ipc->ops->set_mem_type(m3_ipc, temp);
353afe761f8SDave Gerlach 
354afe761f8SDave Gerlach 	/* Physical resume address to be used by ROM code */
355afe761f8SDave Gerlach 	resume_address = am33xx_do_wfi_sram_phys +
356afe761f8SDave Gerlach 			 *pm_sram->resume_offset + 0x4;
357afe761f8SDave Gerlach 
358afe761f8SDave Gerlach 	m3_ipc->ops->set_resume_address(m3_ipc, (void *)resume_address);
359afe761f8SDave Gerlach }
360afe761f8SDave Gerlach 
361afe761f8SDave Gerlach static void am33xx_pm_free_sram(void)
362afe761f8SDave Gerlach {
363afe761f8SDave Gerlach 	gen_pool_free(sram_pool, ocmcram_location, *pm_sram->do_wfi_sz);
364afe761f8SDave Gerlach 	gen_pool_free(sram_pool_data, ocmcram_location_data,
365afe761f8SDave Gerlach 		      sizeof(struct am33xx_pm_ro_sram_data));
366afe761f8SDave Gerlach }
367afe761f8SDave Gerlach 
368afe761f8SDave Gerlach /*
369afe761f8SDave Gerlach  * Push the minimal suspend-resume code to SRAM
370afe761f8SDave Gerlach  */
371afe761f8SDave Gerlach static int am33xx_pm_alloc_sram(void)
372afe761f8SDave Gerlach {
373afe761f8SDave Gerlach 	struct device_node *np;
374afe761f8SDave Gerlach 	int ret = 0;
375afe761f8SDave Gerlach 
376afe761f8SDave Gerlach 	np = of_find_compatible_node(NULL, NULL, "ti,omap3-mpu");
377afe761f8SDave Gerlach 	if (!np) {
378afe761f8SDave Gerlach 		np = of_find_compatible_node(NULL, NULL, "ti,omap4-mpu");
379afe761f8SDave Gerlach 		if (!np) {
380afe761f8SDave Gerlach 			dev_err(pm33xx_dev, "PM: %s: Unable to find device node for mpu\n",
381afe761f8SDave Gerlach 				__func__);
382afe761f8SDave Gerlach 			return -ENODEV;
383afe761f8SDave Gerlach 		}
384afe761f8SDave Gerlach 	}
385afe761f8SDave Gerlach 
386afe761f8SDave Gerlach 	sram_pool = of_gen_pool_get(np, "pm-sram", 0);
387afe761f8SDave Gerlach 	if (!sram_pool) {
388afe761f8SDave Gerlach 		dev_err(pm33xx_dev, "PM: %s: Unable to get sram pool for ocmcram\n",
389afe761f8SDave Gerlach 			__func__);
390afe761f8SDave Gerlach 		ret = -ENODEV;
391afe761f8SDave Gerlach 		goto mpu_put_node;
392afe761f8SDave Gerlach 	}
393afe761f8SDave Gerlach 
394afe761f8SDave Gerlach 	sram_pool_data = of_gen_pool_get(np, "pm-sram", 1);
395afe761f8SDave Gerlach 	if (!sram_pool_data) {
396afe761f8SDave Gerlach 		dev_err(pm33xx_dev, "PM: %s: Unable to get sram data pool for ocmcram\n",
397afe761f8SDave Gerlach 			__func__);
398afe761f8SDave Gerlach 		ret = -ENODEV;
399afe761f8SDave Gerlach 		goto mpu_put_node;
400afe761f8SDave Gerlach 	}
401afe761f8SDave Gerlach 
402afe761f8SDave Gerlach 	ocmcram_location = gen_pool_alloc(sram_pool, *pm_sram->do_wfi_sz);
403afe761f8SDave Gerlach 	if (!ocmcram_location) {
404afe761f8SDave Gerlach 		dev_err(pm33xx_dev, "PM: %s: Unable to allocate memory from ocmcram\n",
405afe761f8SDave Gerlach 			__func__);
406afe761f8SDave Gerlach 		ret = -ENOMEM;
407afe761f8SDave Gerlach 		goto mpu_put_node;
408afe761f8SDave Gerlach 	}
409afe761f8SDave Gerlach 
410afe761f8SDave Gerlach 	ocmcram_location_data = gen_pool_alloc(sram_pool_data,
411afe761f8SDave Gerlach 					       sizeof(struct emif_regs_amx3));
412afe761f8SDave Gerlach 	if (!ocmcram_location_data) {
413afe761f8SDave Gerlach 		dev_err(pm33xx_dev, "PM: Unable to allocate memory from ocmcram\n");
414afe761f8SDave Gerlach 		gen_pool_free(sram_pool, ocmcram_location, *pm_sram->do_wfi_sz);
415afe761f8SDave Gerlach 		ret = -ENOMEM;
416afe761f8SDave Gerlach 	}
417afe761f8SDave Gerlach 
418afe761f8SDave Gerlach mpu_put_node:
419afe761f8SDave Gerlach 	of_node_put(np);
420afe761f8SDave Gerlach 	return ret;
421afe761f8SDave Gerlach }
422afe761f8SDave Gerlach 
4235a99ae00SKeerthy static int am33xx_pm_rtc_setup(void)
4245a99ae00SKeerthy {
4255a99ae00SKeerthy 	struct device_node *np;
4265a99ae00SKeerthy 	unsigned long val = 0;
4275a99ae00SKeerthy 	struct nvmem_device *nvmem;
4285a99ae00SKeerthy 
4295a99ae00SKeerthy 	np = of_find_node_by_name(NULL, "rtc");
4305a99ae00SKeerthy 
4315a99ae00SKeerthy 	if (of_device_is_available(np)) {
4325a99ae00SKeerthy 		omap_rtc = rtc_class_open("rtc0");
4335a99ae00SKeerthy 		if (!omap_rtc) {
4345a99ae00SKeerthy 			pr_warn("PM: rtc0 not available");
4355a99ae00SKeerthy 			return -EPROBE_DEFER;
4365a99ae00SKeerthy 		}
4375a99ae00SKeerthy 
4385a99ae00SKeerthy 		nvmem = devm_nvmem_device_get(&omap_rtc->dev,
4395a99ae00SKeerthy 					      "omap_rtc_scratch0");
440d8e0cecbSKeerthy 		if (!IS_ERR(nvmem)) {
4415a99ae00SKeerthy 			nvmem_device_read(nvmem, RTC_SCRATCH_MAGIC_REG * 4,
4425a99ae00SKeerthy 					  4, (void *)&rtc_magic_val);
4435a99ae00SKeerthy 			if ((rtc_magic_val & 0xffff) != RTC_REG_BOOT_MAGIC)
4445a99ae00SKeerthy 				pr_warn("PM: bootloader does not support rtc-only!\n");
4455a99ae00SKeerthy 
4465a99ae00SKeerthy 			nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4,
4475a99ae00SKeerthy 					   4, (void *)&val);
4485a99ae00SKeerthy 			val = pm_sram->resume_address;
4495a99ae00SKeerthy 			nvmem_device_write(nvmem, RTC_SCRATCH_RESUME_REG * 4,
4505a99ae00SKeerthy 					   4, (void *)&val);
4515a99ae00SKeerthy 		}
4525a99ae00SKeerthy 	} else {
4535a99ae00SKeerthy 		pr_warn("PM: no-rtc available, rtc-only mode disabled.\n");
4545a99ae00SKeerthy 	}
4555a99ae00SKeerthy 
4565a99ae00SKeerthy 	return 0;
4575a99ae00SKeerthy }
4585a99ae00SKeerthy 
459afe761f8SDave Gerlach static int am33xx_pm_probe(struct platform_device *pdev)
460afe761f8SDave Gerlach {
461afe761f8SDave Gerlach 	struct device *dev = &pdev->dev;
462afe761f8SDave Gerlach 	int ret;
463afe761f8SDave Gerlach 
464afe761f8SDave Gerlach 	if (!of_machine_is_compatible("ti,am33xx") &&
465afe761f8SDave Gerlach 	    !of_machine_is_compatible("ti,am43"))
466afe761f8SDave Gerlach 		return -ENODEV;
467afe761f8SDave Gerlach 
468afe761f8SDave Gerlach 	pm_ops = dev->platform_data;
469afe761f8SDave Gerlach 	if (!pm_ops) {
470afe761f8SDave Gerlach 		dev_err(dev, "PM: Cannot get core PM ops!\n");
471afe761f8SDave Gerlach 		return -ENODEV;
472afe761f8SDave Gerlach 	}
473afe761f8SDave Gerlach 
4745a99ae00SKeerthy 	ret = am43xx_map_gic();
4755a99ae00SKeerthy 	if (ret) {
4765a99ae00SKeerthy 		pr_err("PM: Could not ioremap GIC base\n");
4775a99ae00SKeerthy 		return ret;
4785a99ae00SKeerthy 	}
4795a99ae00SKeerthy 
480afe761f8SDave Gerlach 	pm_sram = pm_ops->get_sram_addrs();
481afe761f8SDave Gerlach 	if (!pm_sram) {
482afe761f8SDave Gerlach 		dev_err(dev, "PM: Cannot get PM asm function addresses!!\n");
483afe761f8SDave Gerlach 		return -ENODEV;
484afe761f8SDave Gerlach 	}
485afe761f8SDave Gerlach 
4865a99ae00SKeerthy 	m3_ipc = wkup_m3_ipc_get();
4875a99ae00SKeerthy 	if (!m3_ipc) {
4885a99ae00SKeerthy 		pr_err("PM: Cannot get wkup_m3_ipc handle\n");
4895a99ae00SKeerthy 		return -EPROBE_DEFER;
4905a99ae00SKeerthy 	}
4915a99ae00SKeerthy 
492afe761f8SDave Gerlach 	pm33xx_dev = dev;
493afe761f8SDave Gerlach 
494afe761f8SDave Gerlach 	ret = am33xx_pm_alloc_sram();
495afe761f8SDave Gerlach 	if (ret)
496afe761f8SDave Gerlach 		return ret;
497afe761f8SDave Gerlach 
4985a99ae00SKeerthy 	ret = am33xx_pm_rtc_setup();
499afe761f8SDave Gerlach 	if (ret)
500afe761f8SDave Gerlach 		goto err_free_sram;
501afe761f8SDave Gerlach 
5025a99ae00SKeerthy 	ret = am33xx_push_sram_idle();
5035a99ae00SKeerthy 	if (ret)
504afe761f8SDave Gerlach 		goto err_free_sram;
505afe761f8SDave Gerlach 
506afe761f8SDave Gerlach 	am33xx_pm_set_ipc_ops();
507afe761f8SDave Gerlach 
508afe761f8SDave Gerlach #ifdef CONFIG_SUSPEND
509afe761f8SDave Gerlach 	suspend_set_ops(&am33xx_pm_ops);
510afe761f8SDave Gerlach 
51174655749SDave Gerlach 	/*
51274655749SDave Gerlach 	 * For a system suspend we must flush the caches, we want
51374655749SDave Gerlach 	 * the DDR in self-refresh, we want to save the context
51474655749SDave Gerlach 	 * of the EMIF, and we want the wkup_m3 to handle low-power
51574655749SDave Gerlach 	 * transition.
51674655749SDave Gerlach 	 */
51774655749SDave Gerlach 	suspend_wfi_flags |= WFI_FLAG_FLUSH_CACHE;
51874655749SDave Gerlach 	suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH;
51974655749SDave Gerlach 	suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF;
52074655749SDave Gerlach 	suspend_wfi_flags |= WFI_FLAG_WAKE_M3;
5215a99ae00SKeerthy #endif /* CONFIG_SUSPEND */
52274655749SDave Gerlach 
5236afaff1cSDave Gerlach 	ret = pm_ops->init(am33xx_do_sram_idle);
524afe761f8SDave Gerlach 	if (ret) {
525afe761f8SDave Gerlach 		dev_err(dev, "Unable to call core pm init!\n");
526afe761f8SDave Gerlach 		ret = -ENODEV;
527afe761f8SDave Gerlach 		goto err_put_wkup_m3_ipc;
528afe761f8SDave Gerlach 	}
529afe761f8SDave Gerlach 
530afe761f8SDave Gerlach 	return 0;
531afe761f8SDave Gerlach 
532afe761f8SDave Gerlach err_put_wkup_m3_ipc:
533afe761f8SDave Gerlach 	wkup_m3_ipc_put(m3_ipc);
534afe761f8SDave Gerlach err_free_sram:
535afe761f8SDave Gerlach 	am33xx_pm_free_sram();
536afe761f8SDave Gerlach 	pm33xx_dev = NULL;
537afe761f8SDave Gerlach 	return ret;
538afe761f8SDave Gerlach }
539afe761f8SDave Gerlach 
540afe761f8SDave Gerlach static int am33xx_pm_remove(struct platform_device *pdev)
541afe761f8SDave Gerlach {
5426afaff1cSDave Gerlach 	if (pm_ops->deinit)
5436afaff1cSDave Gerlach 		pm_ops->deinit();
544afe761f8SDave Gerlach 	suspend_set_ops(NULL);
545afe761f8SDave Gerlach 	wkup_m3_ipc_put(m3_ipc);
546afe761f8SDave Gerlach 	am33xx_pm_free_sram();
547afe761f8SDave Gerlach 	return 0;
548afe761f8SDave Gerlach }
549afe761f8SDave Gerlach 
550afe761f8SDave Gerlach static struct platform_driver am33xx_pm_driver = {
551afe761f8SDave Gerlach 	.driver = {
552afe761f8SDave Gerlach 		.name   = "pm33xx",
553afe761f8SDave Gerlach 	},
554afe761f8SDave Gerlach 	.probe = am33xx_pm_probe,
555afe761f8SDave Gerlach 	.remove = am33xx_pm_remove,
556afe761f8SDave Gerlach };
557afe761f8SDave Gerlach module_platform_driver(am33xx_pm_driver);
558afe761f8SDave Gerlach 
559afe761f8SDave Gerlach MODULE_ALIAS("platform:pm33xx");
560afe761f8SDave Gerlach MODULE_LICENSE("GPL v2");
561afe761f8SDave Gerlach MODULE_DESCRIPTION("am33xx power management driver");
562