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> 192152fbbdSTony Lindgren #include <linux/of_address.h> 20afe761f8SDave Gerlach #include <linux/platform_data/pm33xx.h> 21afe761f8SDave Gerlach #include <linux/platform_device.h> 22*74033131STony Lindgren #include <linux/pm_runtime.h> 235a99ae00SKeerthy #include <linux/rtc.h> 245a99ae00SKeerthy #include <linux/rtc/rtc-omap.h> 25afe761f8SDave Gerlach #include <linux/sizes.h> 26afe761f8SDave Gerlach #include <linux/sram.h> 27afe761f8SDave Gerlach #include <linux/suspend.h> 28afe761f8SDave Gerlach #include <linux/ti-emif-sram.h> 29afe761f8SDave Gerlach #include <linux/wkup_m3_ipc.h> 30afe761f8SDave Gerlach 31afe761f8SDave Gerlach #include <asm/proc-fns.h> 32afe761f8SDave Gerlach #include <asm/suspend.h> 33afe761f8SDave Gerlach #include <asm/system_misc.h> 34afe761f8SDave Gerlach 35afe761f8SDave Gerlach #define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \ 36afe761f8SDave Gerlach (unsigned long)pm_sram->do_wfi) 37afe761f8SDave Gerlach 385a99ae00SKeerthy #define RTC_SCRATCH_RESUME_REG 0 395a99ae00SKeerthy #define RTC_SCRATCH_MAGIC_REG 1 405a99ae00SKeerthy #define RTC_REG_BOOT_MAGIC 0x8cd0 /* RTC */ 415a99ae00SKeerthy #define GIC_INT_SET_PENDING_BASE 0x200 425a99ae00SKeerthy #define AM43XX_GIC_DIST_BASE 0x48241000 435a99ae00SKeerthy 442152fbbdSTony Lindgren static void __iomem *rtc_base_virt; 452152fbbdSTony Lindgren static struct clk *rtc_fck; 465a99ae00SKeerthy static u32 rtc_magic_val; 475a99ae00SKeerthy 48afe761f8SDave Gerlach static int (*am33xx_do_wfi_sram)(unsigned long unused); 49afe761f8SDave Gerlach static phys_addr_t am33xx_do_wfi_sram_phys; 50afe761f8SDave Gerlach 51afe761f8SDave Gerlach static struct gen_pool *sram_pool, *sram_pool_data; 52afe761f8SDave Gerlach static unsigned long ocmcram_location, ocmcram_location_data; 53afe761f8SDave Gerlach 545a99ae00SKeerthy static struct rtc_device *omap_rtc; 555a99ae00SKeerthy static void __iomem *gic_dist_base; 565a99ae00SKeerthy 57afe761f8SDave Gerlach static struct am33xx_pm_platform_data *pm_ops; 58afe761f8SDave Gerlach static struct am33xx_pm_sram_addr *pm_sram; 59afe761f8SDave Gerlach 60afe761f8SDave Gerlach static struct device *pm33xx_dev; 61afe761f8SDave Gerlach static struct wkup_m3_ipc *m3_ipc; 62afe761f8SDave Gerlach 635a99ae00SKeerthy #ifdef CONFIG_SUSPEND 645a99ae00SKeerthy static int rtc_only_idle; 655a99ae00SKeerthy static int retrigger_irq; 6674655749SDave Gerlach static unsigned long suspend_wfi_flags; 6774655749SDave Gerlach 685a99ae00SKeerthy static struct wkup_m3_wakeup_src wakeup_src = {.irq_nr = 0, 695a99ae00SKeerthy .src = "Unknown", 705a99ae00SKeerthy }; 715a99ae00SKeerthy 725a99ae00SKeerthy static struct wkup_m3_wakeup_src rtc_alarm_wakeup = { 735a99ae00SKeerthy .irq_nr = 108, .src = "RTC Alarm", 745a99ae00SKeerthy }; 755a99ae00SKeerthy 765a99ae00SKeerthy static struct wkup_m3_wakeup_src rtc_ext_wakeup = { 775a99ae00SKeerthy .irq_nr = 0, .src = "Ext wakeup", 785a99ae00SKeerthy }; 795a99ae00SKeerthy #endif 805a99ae00SKeerthy 81afe761f8SDave Gerlach static u32 sram_suspend_address(unsigned long addr) 82afe761f8SDave Gerlach { 83afe761f8SDave Gerlach return ((unsigned long)am33xx_do_wfi_sram + 84afe761f8SDave Gerlach AMX3_PM_SRAM_SYMBOL_OFFSET(addr)); 85afe761f8SDave Gerlach } 86afe761f8SDave Gerlach 871c6c0354SKeerthy static int am33xx_push_sram_idle(void) 881c6c0354SKeerthy { 891c6c0354SKeerthy struct am33xx_pm_ro_sram_data ro_sram_data; 901c6c0354SKeerthy int ret; 911c6c0354SKeerthy u32 table_addr, ro_data_addr; 921c6c0354SKeerthy void *copy_addr; 931c6c0354SKeerthy 941c6c0354SKeerthy ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data; 951c6c0354SKeerthy ro_sram_data.amx3_pm_sram_data_phys = 961c6c0354SKeerthy gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data); 972152fbbdSTony Lindgren ro_sram_data.rtc_base_virt = rtc_base_virt; 981c6c0354SKeerthy 991c6c0354SKeerthy /* Save physical address to calculate resume offset during pm init */ 1001c6c0354SKeerthy am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool, 1011c6c0354SKeerthy ocmcram_location); 1021c6c0354SKeerthy 1031c6c0354SKeerthy am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location, 1041c6c0354SKeerthy pm_sram->do_wfi, 1051c6c0354SKeerthy *pm_sram->do_wfi_sz); 1061c6c0354SKeerthy if (!am33xx_do_wfi_sram) { 1071c6c0354SKeerthy dev_err(pm33xx_dev, 1081c6c0354SKeerthy "PM: %s: am33xx_do_wfi copy to sram failed\n", 1091c6c0354SKeerthy __func__); 1101c6c0354SKeerthy return -ENODEV; 1111c6c0354SKeerthy } 1121c6c0354SKeerthy 1131c6c0354SKeerthy table_addr = 1141c6c0354SKeerthy sram_suspend_address((unsigned long)pm_sram->emif_sram_table); 1151c6c0354SKeerthy ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr); 1161c6c0354SKeerthy if (ret) { 1171c6c0354SKeerthy dev_dbg(pm33xx_dev, 1181c6c0354SKeerthy "PM: %s: EMIF function copy failed\n", __func__); 1191c6c0354SKeerthy return -EPROBE_DEFER; 1201c6c0354SKeerthy } 1211c6c0354SKeerthy 1221c6c0354SKeerthy ro_data_addr = 1231c6c0354SKeerthy sram_suspend_address((unsigned long)pm_sram->ro_sram_data); 1241c6c0354SKeerthy copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr, 1251c6c0354SKeerthy &ro_sram_data, 1261c6c0354SKeerthy sizeof(ro_sram_data)); 1271c6c0354SKeerthy if (!copy_addr) { 1281c6c0354SKeerthy dev_err(pm33xx_dev, 1291c6c0354SKeerthy "PM: %s: ro_sram_data copy to sram failed\n", 1301c6c0354SKeerthy __func__); 1311c6c0354SKeerthy return -ENODEV; 1321c6c0354SKeerthy } 1331c6c0354SKeerthy 1341c6c0354SKeerthy return 0; 1351c6c0354SKeerthy } 1361c6c0354SKeerthy 1376afaff1cSDave Gerlach static int am33xx_do_sram_idle(u32 wfi_flags) 1386afaff1cSDave Gerlach { 1396afaff1cSDave Gerlach int ret = 0; 1406afaff1cSDave Gerlach 1416afaff1cSDave Gerlach if (!m3_ipc || !pm_ops) 1426afaff1cSDave Gerlach return 0; 1436afaff1cSDave Gerlach 1446afaff1cSDave Gerlach if (wfi_flags & WFI_FLAG_WAKE_M3) 1456afaff1cSDave Gerlach ret = m3_ipc->ops->prepare_low_power(m3_ipc, WKUP_M3_IDLE); 1466afaff1cSDave Gerlach 1476afaff1cSDave Gerlach return pm_ops->cpu_suspend(am33xx_do_wfi_sram, wfi_flags); 1486afaff1cSDave Gerlach } 1496afaff1cSDave Gerlach 1505a99ae00SKeerthy static int __init am43xx_map_gic(void) 1515a99ae00SKeerthy { 1525a99ae00SKeerthy gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K); 1535a99ae00SKeerthy 1545a99ae00SKeerthy if (!gic_dist_base) 1555a99ae00SKeerthy return -ENOMEM; 1565a99ae00SKeerthy 1575a99ae00SKeerthy return 0; 1585a99ae00SKeerthy } 1595a99ae00SKeerthy 160afe761f8SDave Gerlach #ifdef CONFIG_SUSPEND 1614a65bbb9SYueHaibing static struct wkup_m3_wakeup_src rtc_wake_src(void) 1625a99ae00SKeerthy { 1635a99ae00SKeerthy u32 i; 1645a99ae00SKeerthy 1652152fbbdSTony Lindgren i = __raw_readl(rtc_base_virt + 0x44) & 0x40; 1665a99ae00SKeerthy 1675a99ae00SKeerthy if (i) { 1685a99ae00SKeerthy retrigger_irq = rtc_alarm_wakeup.irq_nr; 1695a99ae00SKeerthy return rtc_alarm_wakeup; 1705a99ae00SKeerthy } 1715a99ae00SKeerthy 1725a99ae00SKeerthy retrigger_irq = rtc_ext_wakeup.irq_nr; 1735a99ae00SKeerthy 1745a99ae00SKeerthy return rtc_ext_wakeup; 1755a99ae00SKeerthy } 1765a99ae00SKeerthy 1774a65bbb9SYueHaibing static int am33xx_rtc_only_idle(unsigned long wfi_flags) 1785a99ae00SKeerthy { 1795a99ae00SKeerthy omap_rtc_power_off_program(&omap_rtc->dev); 1805a99ae00SKeerthy am33xx_do_wfi_sram(wfi_flags); 1815a99ae00SKeerthy return 0; 1825a99ae00SKeerthy } 1835a99ae00SKeerthy 1842152fbbdSTony Lindgren /* 1852152fbbdSTony Lindgren * Note that the RTC module clock must be re-enabled only for rtc+ddr suspend. 1862152fbbdSTony Lindgren * And looks like the module can stay in SYSC_IDLE_SMART_WKUP mode configured 1872152fbbdSTony Lindgren * by the interconnect code just fine for both rtc+ddr suspend and retention 1882152fbbdSTony Lindgren * suspend. 1892152fbbdSTony Lindgren */ 190afe761f8SDave Gerlach static int am33xx_pm_suspend(suspend_state_t suspend_state) 191afe761f8SDave Gerlach { 192afe761f8SDave Gerlach int i, ret = 0; 193afe761f8SDave Gerlach 1945a99ae00SKeerthy if (suspend_state == PM_SUSPEND_MEM && 1955a99ae00SKeerthy pm_ops->check_off_mode_enable()) { 1962152fbbdSTony Lindgren ret = clk_prepare_enable(rtc_fck); 1972152fbbdSTony Lindgren if (ret) { 1982152fbbdSTony Lindgren dev_err(pm33xx_dev, "Failed to enable clock: %i\n", ret); 1992152fbbdSTony Lindgren return ret; 2002152fbbdSTony Lindgren } 2012152fbbdSTony Lindgren 2025a99ae00SKeerthy pm_ops->save_context(); 2035a99ae00SKeerthy suspend_wfi_flags |= WFI_FLAG_RTC_ONLY; 2045a99ae00SKeerthy clk_save_context(); 2055a99ae00SKeerthy ret = pm_ops->soc_suspend(suspend_state, am33xx_rtc_only_idle, 2065a99ae00SKeerthy suspend_wfi_flags); 2075a99ae00SKeerthy 2085a99ae00SKeerthy suspend_wfi_flags &= ~WFI_FLAG_RTC_ONLY; 20945450f36SKeerthy dev_info(pm33xx_dev, "Entering RTC Only mode with DDR in self-refresh\n"); 2105a99ae00SKeerthy 2115a99ae00SKeerthy if (!ret) { 2125a99ae00SKeerthy clk_restore_context(); 2135a99ae00SKeerthy pm_ops->restore_context(); 2145a99ae00SKeerthy m3_ipc->ops->set_rtc_only(m3_ipc); 2155a99ae00SKeerthy am33xx_push_sram_idle(); 2165a99ae00SKeerthy } 2175a99ae00SKeerthy } else { 2185a99ae00SKeerthy ret = pm_ops->soc_suspend(suspend_state, am33xx_do_wfi_sram, 2195a99ae00SKeerthy suspend_wfi_flags); 2205a99ae00SKeerthy } 221afe761f8SDave Gerlach 222afe761f8SDave Gerlach if (ret) { 223afe761f8SDave Gerlach dev_err(pm33xx_dev, "PM: Kernel suspend failure\n"); 224afe761f8SDave Gerlach } else { 225afe761f8SDave Gerlach i = m3_ipc->ops->request_pm_status(m3_ipc); 226afe761f8SDave Gerlach 227afe761f8SDave Gerlach switch (i) { 228afe761f8SDave Gerlach case 0: 229afe761f8SDave Gerlach dev_info(pm33xx_dev, 230afe761f8SDave Gerlach "PM: Successfully put all powerdomains to target state\n"); 231afe761f8SDave Gerlach break; 232afe761f8SDave Gerlach case 1: 233afe761f8SDave Gerlach dev_err(pm33xx_dev, 234afe761f8SDave Gerlach "PM: Could not transition all powerdomains to target state\n"); 235afe761f8SDave Gerlach ret = -1; 236afe761f8SDave Gerlach break; 237afe761f8SDave Gerlach default: 238afe761f8SDave Gerlach dev_err(pm33xx_dev, 239afe761f8SDave Gerlach "PM: CM3 returned unknown result = %d\n", i); 240afe761f8SDave Gerlach ret = -1; 241afe761f8SDave Gerlach } 2425a99ae00SKeerthy 2435a99ae00SKeerthy /* print the wakeup reason */ 2445a99ae00SKeerthy if (rtc_only_idle) { 2455a99ae00SKeerthy wakeup_src = rtc_wake_src(); 2465a99ae00SKeerthy pr_info("PM: Wakeup source %s\n", wakeup_src.src); 2475a99ae00SKeerthy } else { 2485a99ae00SKeerthy pr_info("PM: Wakeup source %s\n", 2495a99ae00SKeerthy m3_ipc->ops->request_wake_src(m3_ipc)); 250afe761f8SDave Gerlach } 2515a99ae00SKeerthy } 2525a99ae00SKeerthy 2535a99ae00SKeerthy if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) 2542152fbbdSTony Lindgren clk_disable_unprepare(rtc_fck); 255afe761f8SDave Gerlach 256afe761f8SDave Gerlach return ret; 257afe761f8SDave Gerlach } 258afe761f8SDave Gerlach 259afe761f8SDave Gerlach static int am33xx_pm_enter(suspend_state_t suspend_state) 260afe761f8SDave Gerlach { 261afe761f8SDave Gerlach int ret = 0; 262afe761f8SDave Gerlach 263afe761f8SDave Gerlach switch (suspend_state) { 264afe761f8SDave Gerlach case PM_SUSPEND_MEM: 265afe761f8SDave Gerlach case PM_SUSPEND_STANDBY: 266afe761f8SDave Gerlach ret = am33xx_pm_suspend(suspend_state); 267afe761f8SDave Gerlach break; 268afe761f8SDave Gerlach default: 269afe761f8SDave Gerlach ret = -EINVAL; 270afe761f8SDave Gerlach } 271afe761f8SDave Gerlach 272afe761f8SDave Gerlach return ret; 273afe761f8SDave Gerlach } 274afe761f8SDave Gerlach 275afe761f8SDave Gerlach static int am33xx_pm_begin(suspend_state_t state) 276afe761f8SDave Gerlach { 277afe761f8SDave Gerlach int ret = -EINVAL; 2785a99ae00SKeerthy struct nvmem_device *nvmem; 2795a99ae00SKeerthy 2805a99ae00SKeerthy if (state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) { 2815a99ae00SKeerthy nvmem = devm_nvmem_device_get(&omap_rtc->dev, 2825a99ae00SKeerthy "omap_rtc_scratch0"); 283d8e0cecbSKeerthy if (!IS_ERR(nvmem)) 2845a99ae00SKeerthy nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, 2855a99ae00SKeerthy (void *)&rtc_magic_val); 2865a99ae00SKeerthy rtc_only_idle = 1; 2875a99ae00SKeerthy } else { 2885a99ae00SKeerthy rtc_only_idle = 0; 2895a99ae00SKeerthy } 290afe761f8SDave Gerlach 2916afaff1cSDave Gerlach pm_ops->begin_suspend(); 2926afaff1cSDave Gerlach 293afe761f8SDave Gerlach switch (state) { 294afe761f8SDave Gerlach case PM_SUSPEND_MEM: 295afe761f8SDave Gerlach ret = m3_ipc->ops->prepare_low_power(m3_ipc, WKUP_M3_DEEPSLEEP); 296afe761f8SDave Gerlach break; 297afe761f8SDave Gerlach case PM_SUSPEND_STANDBY: 298afe761f8SDave Gerlach ret = m3_ipc->ops->prepare_low_power(m3_ipc, WKUP_M3_STANDBY); 299afe761f8SDave Gerlach break; 300afe761f8SDave Gerlach } 301afe761f8SDave Gerlach 302afe761f8SDave Gerlach return ret; 303afe761f8SDave Gerlach } 304afe761f8SDave Gerlach 305afe761f8SDave Gerlach static void am33xx_pm_end(void) 306afe761f8SDave Gerlach { 3075a99ae00SKeerthy u32 val = 0; 3085a99ae00SKeerthy struct nvmem_device *nvmem; 3095a99ae00SKeerthy 3105a99ae00SKeerthy nvmem = devm_nvmem_device_get(&omap_rtc->dev, "omap_rtc_scratch0"); 311d8e0cecbSKeerthy if (IS_ERR(nvmem)) 312d8e0cecbSKeerthy return; 313d8e0cecbSKeerthy 314afe761f8SDave Gerlach m3_ipc->ops->finish_low_power(m3_ipc); 3155a99ae00SKeerthy if (rtc_only_idle) { 316d8e0cecbSKeerthy if (retrigger_irq) { 3175a99ae00SKeerthy /* 3185a99ae00SKeerthy * 32 bits of Interrupt Set-Pending correspond to 32 3195a99ae00SKeerthy * 32 interrupts. Compute the bit offset of the 3205a99ae00SKeerthy * Interrupt and set that particular bit 3215a99ae00SKeerthy * Compute the register offset by dividing interrupt 3225a99ae00SKeerthy * number by 32 and mutiplying by 4 3235a99ae00SKeerthy */ 3245a99ae00SKeerthy writel_relaxed(1 << (retrigger_irq & 31), 3255a99ae00SKeerthy gic_dist_base + GIC_INT_SET_PENDING_BASE 3265a99ae00SKeerthy + retrigger_irq / 32 * 4); 327d8e0cecbSKeerthy } 328d8e0cecbSKeerthy 3295a99ae00SKeerthy nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, 3305a99ae00SKeerthy (void *)&val); 3315a99ae00SKeerthy } 3325a99ae00SKeerthy 3335a99ae00SKeerthy rtc_only_idle = 0; 3346afaff1cSDave Gerlach 3356afaff1cSDave Gerlach pm_ops->finish_suspend(); 336afe761f8SDave Gerlach } 337afe761f8SDave Gerlach 338afe761f8SDave Gerlach static int am33xx_pm_valid(suspend_state_t state) 339afe761f8SDave Gerlach { 340afe761f8SDave Gerlach switch (state) { 341afe761f8SDave Gerlach case PM_SUSPEND_STANDBY: 342afe761f8SDave Gerlach case PM_SUSPEND_MEM: 343afe761f8SDave Gerlach return 1; 344afe761f8SDave Gerlach default: 345afe761f8SDave Gerlach return 0; 346afe761f8SDave Gerlach } 347afe761f8SDave Gerlach } 348afe761f8SDave Gerlach 349afe761f8SDave Gerlach static const struct platform_suspend_ops am33xx_pm_ops = { 350afe761f8SDave Gerlach .begin = am33xx_pm_begin, 351afe761f8SDave Gerlach .end = am33xx_pm_end, 352afe761f8SDave Gerlach .enter = am33xx_pm_enter, 353afe761f8SDave Gerlach .valid = am33xx_pm_valid, 354afe761f8SDave Gerlach }; 355afe761f8SDave Gerlach #endif /* CONFIG_SUSPEND */ 356afe761f8SDave Gerlach 357afe761f8SDave Gerlach static void am33xx_pm_set_ipc_ops(void) 358afe761f8SDave Gerlach { 359afe761f8SDave Gerlach u32 resume_address; 360afe761f8SDave Gerlach int temp; 361afe761f8SDave Gerlach 362afe761f8SDave Gerlach temp = ti_emif_get_mem_type(); 363afe761f8SDave Gerlach if (temp < 0) { 364afe761f8SDave Gerlach dev_err(pm33xx_dev, "PM: Cannot determine memory type, no PM available\n"); 365afe761f8SDave Gerlach return; 366afe761f8SDave Gerlach } 367afe761f8SDave Gerlach m3_ipc->ops->set_mem_type(m3_ipc, temp); 368afe761f8SDave Gerlach 369afe761f8SDave Gerlach /* Physical resume address to be used by ROM code */ 370afe761f8SDave Gerlach resume_address = am33xx_do_wfi_sram_phys + 371afe761f8SDave Gerlach *pm_sram->resume_offset + 0x4; 372afe761f8SDave Gerlach 373afe761f8SDave Gerlach m3_ipc->ops->set_resume_address(m3_ipc, (void *)resume_address); 374afe761f8SDave Gerlach } 375afe761f8SDave Gerlach 376afe761f8SDave Gerlach static void am33xx_pm_free_sram(void) 377afe761f8SDave Gerlach { 378afe761f8SDave Gerlach gen_pool_free(sram_pool, ocmcram_location, *pm_sram->do_wfi_sz); 379afe761f8SDave Gerlach gen_pool_free(sram_pool_data, ocmcram_location_data, 380afe761f8SDave Gerlach sizeof(struct am33xx_pm_ro_sram_data)); 381afe761f8SDave Gerlach } 382afe761f8SDave Gerlach 383afe761f8SDave Gerlach /* 384afe761f8SDave Gerlach * Push the minimal suspend-resume code to SRAM 385afe761f8SDave Gerlach */ 386afe761f8SDave Gerlach static int am33xx_pm_alloc_sram(void) 387afe761f8SDave Gerlach { 388afe761f8SDave Gerlach struct device_node *np; 389afe761f8SDave Gerlach int ret = 0; 390afe761f8SDave Gerlach 391afe761f8SDave Gerlach np = of_find_compatible_node(NULL, NULL, "ti,omap3-mpu"); 392afe761f8SDave Gerlach if (!np) { 393afe761f8SDave Gerlach np = of_find_compatible_node(NULL, NULL, "ti,omap4-mpu"); 394afe761f8SDave Gerlach if (!np) { 395afe761f8SDave Gerlach dev_err(pm33xx_dev, "PM: %s: Unable to find device node for mpu\n", 396afe761f8SDave Gerlach __func__); 397afe761f8SDave Gerlach return -ENODEV; 398afe761f8SDave Gerlach } 399afe761f8SDave Gerlach } 400afe761f8SDave Gerlach 401afe761f8SDave Gerlach sram_pool = of_gen_pool_get(np, "pm-sram", 0); 402afe761f8SDave Gerlach if (!sram_pool) { 403afe761f8SDave Gerlach dev_err(pm33xx_dev, "PM: %s: Unable to get sram pool for ocmcram\n", 404afe761f8SDave Gerlach __func__); 405afe761f8SDave Gerlach ret = -ENODEV; 406afe761f8SDave Gerlach goto mpu_put_node; 407afe761f8SDave Gerlach } 408afe761f8SDave Gerlach 409afe761f8SDave Gerlach sram_pool_data = of_gen_pool_get(np, "pm-sram", 1); 410afe761f8SDave Gerlach if (!sram_pool_data) { 411afe761f8SDave Gerlach dev_err(pm33xx_dev, "PM: %s: Unable to get sram data pool for ocmcram\n", 412afe761f8SDave Gerlach __func__); 413afe761f8SDave Gerlach ret = -ENODEV; 414afe761f8SDave Gerlach goto mpu_put_node; 415afe761f8SDave Gerlach } 416afe761f8SDave Gerlach 417afe761f8SDave Gerlach ocmcram_location = gen_pool_alloc(sram_pool, *pm_sram->do_wfi_sz); 418afe761f8SDave Gerlach if (!ocmcram_location) { 419afe761f8SDave Gerlach dev_err(pm33xx_dev, "PM: %s: Unable to allocate memory from ocmcram\n", 420afe761f8SDave Gerlach __func__); 421afe761f8SDave Gerlach ret = -ENOMEM; 422afe761f8SDave Gerlach goto mpu_put_node; 423afe761f8SDave Gerlach } 424afe761f8SDave Gerlach 425afe761f8SDave Gerlach ocmcram_location_data = gen_pool_alloc(sram_pool_data, 426afe761f8SDave Gerlach sizeof(struct emif_regs_amx3)); 427afe761f8SDave Gerlach if (!ocmcram_location_data) { 428afe761f8SDave Gerlach dev_err(pm33xx_dev, "PM: Unable to allocate memory from ocmcram\n"); 429afe761f8SDave Gerlach gen_pool_free(sram_pool, ocmcram_location, *pm_sram->do_wfi_sz); 430afe761f8SDave Gerlach ret = -ENOMEM; 431afe761f8SDave Gerlach } 432afe761f8SDave Gerlach 433afe761f8SDave Gerlach mpu_put_node: 434afe761f8SDave Gerlach of_node_put(np); 435afe761f8SDave Gerlach return ret; 436afe761f8SDave Gerlach } 437afe761f8SDave Gerlach 4385a99ae00SKeerthy static int am33xx_pm_rtc_setup(void) 4395a99ae00SKeerthy { 4405a99ae00SKeerthy struct device_node *np; 4415a99ae00SKeerthy unsigned long val = 0; 4425a99ae00SKeerthy struct nvmem_device *nvmem; 4432152fbbdSTony Lindgren int error; 4445a99ae00SKeerthy 4455a99ae00SKeerthy np = of_find_node_by_name(NULL, "rtc"); 4465a99ae00SKeerthy 4475a99ae00SKeerthy if (of_device_is_available(np)) { 4482152fbbdSTony Lindgren /* RTC interconnect target module clock */ 4492152fbbdSTony Lindgren rtc_fck = of_clk_get_by_name(np->parent, "fck"); 4502152fbbdSTony Lindgren if (IS_ERR(rtc_fck)) 4512152fbbdSTony Lindgren return PTR_ERR(rtc_fck); 4522152fbbdSTony Lindgren 4532152fbbdSTony Lindgren rtc_base_virt = of_iomap(np, 0); 4542152fbbdSTony Lindgren if (!rtc_base_virt) { 4552152fbbdSTony Lindgren pr_warn("PM: could not iomap rtc"); 4562152fbbdSTony Lindgren error = -ENODEV; 4572152fbbdSTony Lindgren goto err_clk_put; 4582152fbbdSTony Lindgren } 4592152fbbdSTony Lindgren 4605a99ae00SKeerthy omap_rtc = rtc_class_open("rtc0"); 4615a99ae00SKeerthy if (!omap_rtc) { 4625a99ae00SKeerthy pr_warn("PM: rtc0 not available"); 4632152fbbdSTony Lindgren error = -EPROBE_DEFER; 4642152fbbdSTony Lindgren goto err_iounmap; 4655a99ae00SKeerthy } 4665a99ae00SKeerthy 4675a99ae00SKeerthy nvmem = devm_nvmem_device_get(&omap_rtc->dev, 4685a99ae00SKeerthy "omap_rtc_scratch0"); 469d8e0cecbSKeerthy if (!IS_ERR(nvmem)) { 4705a99ae00SKeerthy nvmem_device_read(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4715a99ae00SKeerthy 4, (void *)&rtc_magic_val); 4725a99ae00SKeerthy if ((rtc_magic_val & 0xffff) != RTC_REG_BOOT_MAGIC) 4735a99ae00SKeerthy pr_warn("PM: bootloader does not support rtc-only!\n"); 4745a99ae00SKeerthy 4755a99ae00SKeerthy nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4765a99ae00SKeerthy 4, (void *)&val); 4775a99ae00SKeerthy val = pm_sram->resume_address; 4785a99ae00SKeerthy nvmem_device_write(nvmem, RTC_SCRATCH_RESUME_REG * 4, 4795a99ae00SKeerthy 4, (void *)&val); 4805a99ae00SKeerthy } 4815a99ae00SKeerthy } else { 4825a99ae00SKeerthy pr_warn("PM: no-rtc available, rtc-only mode disabled.\n"); 4835a99ae00SKeerthy } 4845a99ae00SKeerthy 4855a99ae00SKeerthy return 0; 4862152fbbdSTony Lindgren 4872152fbbdSTony Lindgren err_iounmap: 4882152fbbdSTony Lindgren iounmap(rtc_base_virt); 4892152fbbdSTony Lindgren err_clk_put: 4902152fbbdSTony Lindgren clk_put(rtc_fck); 4912152fbbdSTony Lindgren 4922152fbbdSTony Lindgren return error; 4935a99ae00SKeerthy } 4945a99ae00SKeerthy 495afe761f8SDave Gerlach static int am33xx_pm_probe(struct platform_device *pdev) 496afe761f8SDave Gerlach { 497afe761f8SDave Gerlach struct device *dev = &pdev->dev; 498afe761f8SDave Gerlach int ret; 499afe761f8SDave Gerlach 500afe761f8SDave Gerlach if (!of_machine_is_compatible("ti,am33xx") && 501afe761f8SDave Gerlach !of_machine_is_compatible("ti,am43")) 502afe761f8SDave Gerlach return -ENODEV; 503afe761f8SDave Gerlach 504afe761f8SDave Gerlach pm_ops = dev->platform_data; 505afe761f8SDave Gerlach if (!pm_ops) { 506afe761f8SDave Gerlach dev_err(dev, "PM: Cannot get core PM ops!\n"); 507afe761f8SDave Gerlach return -ENODEV; 508afe761f8SDave Gerlach } 509afe761f8SDave Gerlach 5105a99ae00SKeerthy ret = am43xx_map_gic(); 5115a99ae00SKeerthy if (ret) { 5125a99ae00SKeerthy pr_err("PM: Could not ioremap GIC base\n"); 5135a99ae00SKeerthy return ret; 5145a99ae00SKeerthy } 5155a99ae00SKeerthy 516afe761f8SDave Gerlach pm_sram = pm_ops->get_sram_addrs(); 517afe761f8SDave Gerlach if (!pm_sram) { 518afe761f8SDave Gerlach dev_err(dev, "PM: Cannot get PM asm function addresses!!\n"); 519afe761f8SDave Gerlach return -ENODEV; 520afe761f8SDave Gerlach } 521afe761f8SDave Gerlach 5225a99ae00SKeerthy m3_ipc = wkup_m3_ipc_get(); 5235a99ae00SKeerthy if (!m3_ipc) { 5245a99ae00SKeerthy pr_err("PM: Cannot get wkup_m3_ipc handle\n"); 5255a99ae00SKeerthy return -EPROBE_DEFER; 5265a99ae00SKeerthy } 5275a99ae00SKeerthy 528afe761f8SDave Gerlach pm33xx_dev = dev; 529afe761f8SDave Gerlach 530afe761f8SDave Gerlach ret = am33xx_pm_alloc_sram(); 531afe761f8SDave Gerlach if (ret) 532afe761f8SDave Gerlach return ret; 533afe761f8SDave Gerlach 5345a99ae00SKeerthy ret = am33xx_pm_rtc_setup(); 535afe761f8SDave Gerlach if (ret) 536afe761f8SDave Gerlach goto err_free_sram; 537afe761f8SDave Gerlach 5385a99ae00SKeerthy ret = am33xx_push_sram_idle(); 5395a99ae00SKeerthy if (ret) 540afe761f8SDave Gerlach goto err_free_sram; 541afe761f8SDave Gerlach 542afe761f8SDave Gerlach am33xx_pm_set_ipc_ops(); 543afe761f8SDave Gerlach 544afe761f8SDave Gerlach #ifdef CONFIG_SUSPEND 545afe761f8SDave Gerlach suspend_set_ops(&am33xx_pm_ops); 546afe761f8SDave Gerlach 54774655749SDave Gerlach /* 54874655749SDave Gerlach * For a system suspend we must flush the caches, we want 54974655749SDave Gerlach * the DDR in self-refresh, we want to save the context 55074655749SDave Gerlach * of the EMIF, and we want the wkup_m3 to handle low-power 55174655749SDave Gerlach * transition. 55274655749SDave Gerlach */ 55374655749SDave Gerlach suspend_wfi_flags |= WFI_FLAG_FLUSH_CACHE; 55474655749SDave Gerlach suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH; 55574655749SDave Gerlach suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF; 55674655749SDave Gerlach suspend_wfi_flags |= WFI_FLAG_WAKE_M3; 5575a99ae00SKeerthy #endif /* CONFIG_SUSPEND */ 55874655749SDave Gerlach 559*74033131STony Lindgren pm_runtime_enable(dev); 560*74033131STony Lindgren ret = pm_runtime_get_sync(dev); 561*74033131STony Lindgren if (ret < 0) { 562*74033131STony Lindgren pm_runtime_put_noidle(dev); 563*74033131STony Lindgren goto err_pm_runtime_disable; 564*74033131STony Lindgren } 565*74033131STony Lindgren 5666afaff1cSDave Gerlach ret = pm_ops->init(am33xx_do_sram_idle); 567afe761f8SDave Gerlach if (ret) { 568afe761f8SDave Gerlach dev_err(dev, "Unable to call core pm init!\n"); 569afe761f8SDave Gerlach ret = -ENODEV; 570*74033131STony Lindgren goto err_pm_runtime_put; 571afe761f8SDave Gerlach } 572afe761f8SDave Gerlach 573afe761f8SDave Gerlach return 0; 574afe761f8SDave Gerlach 575*74033131STony Lindgren err_pm_runtime_put: 576*74033131STony Lindgren pm_runtime_put_sync(dev); 577*74033131STony Lindgren err_pm_runtime_disable: 578*74033131STony Lindgren pm_runtime_disable(dev); 579afe761f8SDave Gerlach wkup_m3_ipc_put(m3_ipc); 580afe761f8SDave Gerlach err_free_sram: 581afe761f8SDave Gerlach am33xx_pm_free_sram(); 582afe761f8SDave Gerlach pm33xx_dev = NULL; 583afe761f8SDave Gerlach return ret; 584afe761f8SDave Gerlach } 585afe761f8SDave Gerlach 586afe761f8SDave Gerlach static int am33xx_pm_remove(struct platform_device *pdev) 587afe761f8SDave Gerlach { 588*74033131STony Lindgren pm_runtime_put_sync(&pdev->dev); 589*74033131STony Lindgren pm_runtime_disable(&pdev->dev); 5906afaff1cSDave Gerlach if (pm_ops->deinit) 5916afaff1cSDave Gerlach pm_ops->deinit(); 592afe761f8SDave Gerlach suspend_set_ops(NULL); 593afe761f8SDave Gerlach wkup_m3_ipc_put(m3_ipc); 594afe761f8SDave Gerlach am33xx_pm_free_sram(); 5952152fbbdSTony Lindgren iounmap(rtc_base_virt); 5962152fbbdSTony Lindgren clk_put(rtc_fck); 597afe761f8SDave Gerlach return 0; 598afe761f8SDave Gerlach } 599afe761f8SDave Gerlach 600afe761f8SDave Gerlach static struct platform_driver am33xx_pm_driver = { 601afe761f8SDave Gerlach .driver = { 602afe761f8SDave Gerlach .name = "pm33xx", 603afe761f8SDave Gerlach }, 604afe761f8SDave Gerlach .probe = am33xx_pm_probe, 605afe761f8SDave Gerlach .remove = am33xx_pm_remove, 606afe761f8SDave Gerlach }; 607afe761f8SDave Gerlach module_platform_driver(am33xx_pm_driver); 608afe761f8SDave Gerlach 609afe761f8SDave Gerlach MODULE_ALIAS("platform:pm33xx"); 610afe761f8SDave Gerlach MODULE_LICENSE("GPL v2"); 611afe761f8SDave Gerlach MODULE_DESCRIPTION("am33xx power management driver"); 612