18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AM33XX Arch Power Management Routines 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016-2018 Texas Instruments Incorporated - https://www.ti.com/ 68c2ecf20Sopenharmony_ci * Dave Gerlach 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/cpuidle.h> 108c2ecf20Sopenharmony_ci#include <linux/platform_data/pm33xx.h> 118c2ecf20Sopenharmony_ci#include <linux/suspend.h> 128c2ecf20Sopenharmony_ci#include <asm/cpuidle.h> 138c2ecf20Sopenharmony_ci#include <asm/smp_scu.h> 148c2ecf20Sopenharmony_ci#include <asm/suspend.h> 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/clk.h> 178c2ecf20Sopenharmony_ci#include <linux/cpu.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_data/gpio-omap.h> 198c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 208c2ecf20Sopenharmony_ci#include <linux/wkup_m3_ipc.h> 218c2ecf20Sopenharmony_ci#include <linux/of.h> 228c2ecf20Sopenharmony_ci#include <linux/rtc.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "cm33xx.h" 258c2ecf20Sopenharmony_ci#include "common.h" 268c2ecf20Sopenharmony_ci#include "control.h" 278c2ecf20Sopenharmony_ci#include "clockdomain.h" 288c2ecf20Sopenharmony_ci#include "iomap.h" 298c2ecf20Sopenharmony_ci#include "pm.h" 308c2ecf20Sopenharmony_ci#include "powerdomain.h" 318c2ecf20Sopenharmony_ci#include "prm33xx.h" 328c2ecf20Sopenharmony_ci#include "soc.h" 338c2ecf20Sopenharmony_ci#include "sram.h" 348c2ecf20Sopenharmony_ci#include "omap-secure.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm; 378c2ecf20Sopenharmony_cistatic struct clockdomain *gfx_l4ls_clkdm; 388c2ecf20Sopenharmony_cistatic void __iomem *scu_base; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int (*idle_fn)(u32 wfi_flags); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct amx3_idle_state { 438c2ecf20Sopenharmony_ci int wfi_flags; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic struct amx3_idle_state *idle_states; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int am43xx_map_scu(void) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci scu_base = ioremap(scu_a9_get_base(), SZ_256); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (!scu_base) 538c2ecf20Sopenharmony_ci return -ENOMEM; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci return 0; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int am33xx_check_off_mode_enable(void) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci if (enable_off_mode) 618c2ecf20Sopenharmony_ci pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n"); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* off mode not supported on am335x so return 0 always */ 648c2ecf20Sopenharmony_ci return 0; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int am43xx_check_off_mode_enable(void) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci /* 708c2ecf20Sopenharmony_ci * Check for am437x-gp-evm which has the right Hardware design to 718c2ecf20Sopenharmony_ci * support this mode reliably. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci if (of_machine_is_compatible("ti,am437x-gp-evm") && enable_off_mode) 748c2ecf20Sopenharmony_ci return enable_off_mode; 758c2ecf20Sopenharmony_ci else if (enable_off_mode) 768c2ecf20Sopenharmony_ci pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n"); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int amx3_common_init(int (*idle)(u32 wfi_flags)) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci gfx_pwrdm = pwrdm_lookup("gfx_pwrdm"); 848c2ecf20Sopenharmony_ci per_pwrdm = pwrdm_lookup("per_pwrdm"); 858c2ecf20Sopenharmony_ci mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm)) 888c2ecf20Sopenharmony_ci return -ENODEV; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci (void)clkdm_for_each(omap_pm_clkdms_setup, NULL); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* CEFUSE domain can be turned off post bootup */ 938c2ecf20Sopenharmony_ci cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm"); 948c2ecf20Sopenharmony_ci if (!cefuse_pwrdm) 958c2ecf20Sopenharmony_ci pr_err("PM: Failed to get cefuse_pwrdm\n"); 968c2ecf20Sopenharmony_ci else if (omap_type() != OMAP2_DEVICE_TYPE_GP) 978c2ecf20Sopenharmony_ci pr_info("PM: Leaving EFUSE power domain active\n"); 988c2ecf20Sopenharmony_ci else 998c2ecf20Sopenharmony_ci omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci idle_fn = idle; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int am33xx_suspend_init(int (*idle)(u32 wfi_flags)) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci int ret; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm"); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (!gfx_l4ls_clkdm) { 1138c2ecf20Sopenharmony_ci pr_err("PM: Cannot lookup gfx_l4ls_clkdm clockdomains\n"); 1148c2ecf20Sopenharmony_ci return -ENODEV; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci ret = amx3_common_init(idle); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci return ret; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int am43xx_suspend_init(int (*idle)(u32 wfi_flags)) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci int ret = 0; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci ret = am43xx_map_scu(); 1278c2ecf20Sopenharmony_ci if (ret) { 1288c2ecf20Sopenharmony_ci pr_err("PM: Could not ioremap SCU\n"); 1298c2ecf20Sopenharmony_ci return ret; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci ret = amx3_common_init(idle); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return ret; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int amx3_suspend_deinit(void) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci idle_fn = NULL; 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void amx3_pre_suspend_common(void) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void amx3_post_suspend_common(void) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci int status; 1518c2ecf20Sopenharmony_ci /* 1528c2ecf20Sopenharmony_ci * Because gfx_pwrdm is the only one under MPU control, 1538c2ecf20Sopenharmony_ci * comment on transition status 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_ci status = pwrdm_read_pwrst(gfx_pwrdm); 1568c2ecf20Sopenharmony_ci if (status != PWRDM_POWER_OFF) 1578c2ecf20Sopenharmony_ci pr_err("PM: GFX domain did not transition: %x\n", status); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic int am33xx_suspend(unsigned int state, int (*fn)(unsigned long), 1618c2ecf20Sopenharmony_ci unsigned long args) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci int ret = 0; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci amx3_pre_suspend_common(); 1668c2ecf20Sopenharmony_ci ret = cpu_suspend(args, fn); 1678c2ecf20Sopenharmony_ci amx3_post_suspend_common(); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* 1708c2ecf20Sopenharmony_ci * BUG: GFX_L4LS clock domain needs to be woken up to 1718c2ecf20Sopenharmony_ci * ensure thet L4LS clock domain does not get stuck in 1728c2ecf20Sopenharmony_ci * transition. If that happens L3 module does not get 1738c2ecf20Sopenharmony_ci * disabled, thereby leading to PER power domain 1748c2ecf20Sopenharmony_ci * transition failing 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci clkdm_wakeup(gfx_l4ls_clkdm); 1788c2ecf20Sopenharmony_ci clkdm_sleep(gfx_l4ls_clkdm); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return ret; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int am43xx_suspend(unsigned int state, int (*fn)(unsigned long), 1848c2ecf20Sopenharmony_ci unsigned long args) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci int ret = 0; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Suspend secure side on HS devices */ 1898c2ecf20Sopenharmony_ci if (omap_type() != OMAP2_DEVICE_TYPE_GP) { 1908c2ecf20Sopenharmony_ci if (optee_available) 1918c2ecf20Sopenharmony_ci omap_smccc_smc(AM43xx_PPA_SVC_PM_SUSPEND, 0); 1928c2ecf20Sopenharmony_ci else 1938c2ecf20Sopenharmony_ci omap_secure_dispatcher(AM43xx_PPA_SVC_PM_SUSPEND, 1948c2ecf20Sopenharmony_ci FLAG_START_CRITICAL, 1958c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci amx3_pre_suspend_common(); 1998c2ecf20Sopenharmony_ci scu_power_mode(scu_base, SCU_PM_POWEROFF); 2008c2ecf20Sopenharmony_ci ret = cpu_suspend(args, fn); 2018c2ecf20Sopenharmony_ci scu_power_mode(scu_base, SCU_PM_NORMAL); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (!am43xx_check_off_mode_enable()) 2048c2ecf20Sopenharmony_ci amx3_post_suspend_common(); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * Resume secure side on HS devices. 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * Note that even on systems with OP-TEE available this resume call is 2108c2ecf20Sopenharmony_ci * issued to the ROM. This is because upon waking from suspend the ROM 2118c2ecf20Sopenharmony_ci * is restored as the secure monitor. On systems with OP-TEE ROM will 2128c2ecf20Sopenharmony_ci * restore OP-TEE during this call. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci if (omap_type() != OMAP2_DEVICE_TYPE_GP) 2158c2ecf20Sopenharmony_ci omap_secure_dispatcher(AM43xx_PPA_SVC_PM_RESUME, 2168c2ecf20Sopenharmony_ci FLAG_START_CRITICAL, 2178c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return ret; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int am33xx_cpu_suspend(int (*fn)(unsigned long), unsigned long args) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci int ret = 0; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (omap_irq_pending() || need_resched()) 2278c2ecf20Sopenharmony_ci return ret; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci ret = cpu_suspend(args, fn); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return ret; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int am43xx_cpu_suspend(int (*fn)(unsigned long), unsigned long args) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci int ret = 0; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (!scu_base) 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci scu_power_mode(scu_base, SCU_PM_DORMANT); 2428c2ecf20Sopenharmony_ci ret = cpu_suspend(args, fn); 2438c2ecf20Sopenharmony_ci scu_power_mode(scu_base, SCU_PM_NORMAL); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci return ret; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic void amx3_begin_suspend(void) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci cpu_idle_poll_ctrl(true); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic void amx3_finish_suspend(void) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci cpu_idle_poll_ctrl(false); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci if (soc_is_am33xx()) 2628c2ecf20Sopenharmony_ci return &am33xx_pm_sram; 2638c2ecf20Sopenharmony_ci else if (soc_is_am437x()) 2648c2ecf20Sopenharmony_ci return &am43xx_pm_sram; 2658c2ecf20Sopenharmony_ci else 2668c2ecf20Sopenharmony_ci return NULL; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic void am43xx_save_context(void) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void am33xx_save_context(void) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci omap_intc_save_context(); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void am33xx_restore_context(void) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci omap_intc_restore_context(); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void am43xx_restore_context(void) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci /* 2868c2ecf20Sopenharmony_ci * HACK: restore dpll_per_clkdcoldo register contents, to avoid 2878c2ecf20Sopenharmony_ci * breaking suspend-resume 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_ci writel_relaxed(0x0, AM33XX_L4_WK_IO_ADDRESS(0x44df2e14)); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic struct am33xx_pm_platform_data am33xx_ops = { 2938c2ecf20Sopenharmony_ci .init = am33xx_suspend_init, 2948c2ecf20Sopenharmony_ci .deinit = amx3_suspend_deinit, 2958c2ecf20Sopenharmony_ci .soc_suspend = am33xx_suspend, 2968c2ecf20Sopenharmony_ci .cpu_suspend = am33xx_cpu_suspend, 2978c2ecf20Sopenharmony_ci .begin_suspend = amx3_begin_suspend, 2988c2ecf20Sopenharmony_ci .finish_suspend = amx3_finish_suspend, 2998c2ecf20Sopenharmony_ci .get_sram_addrs = amx3_get_sram_addrs, 3008c2ecf20Sopenharmony_ci .save_context = am33xx_save_context, 3018c2ecf20Sopenharmony_ci .restore_context = am33xx_restore_context, 3028c2ecf20Sopenharmony_ci .check_off_mode_enable = am33xx_check_off_mode_enable, 3038c2ecf20Sopenharmony_ci}; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic struct am33xx_pm_platform_data am43xx_ops = { 3068c2ecf20Sopenharmony_ci .init = am43xx_suspend_init, 3078c2ecf20Sopenharmony_ci .deinit = amx3_suspend_deinit, 3088c2ecf20Sopenharmony_ci .soc_suspend = am43xx_suspend, 3098c2ecf20Sopenharmony_ci .cpu_suspend = am43xx_cpu_suspend, 3108c2ecf20Sopenharmony_ci .begin_suspend = amx3_begin_suspend, 3118c2ecf20Sopenharmony_ci .finish_suspend = amx3_finish_suspend, 3128c2ecf20Sopenharmony_ci .get_sram_addrs = amx3_get_sram_addrs, 3138c2ecf20Sopenharmony_ci .save_context = am43xx_save_context, 3148c2ecf20Sopenharmony_ci .restore_context = am43xx_restore_context, 3158c2ecf20Sopenharmony_ci .check_off_mode_enable = am43xx_check_off_mode_enable, 3168c2ecf20Sopenharmony_ci}; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci if (soc_is_am33xx()) 3218c2ecf20Sopenharmony_ci return &am33xx_ops; 3228c2ecf20Sopenharmony_ci else if (soc_is_am437x()) 3238c2ecf20Sopenharmony_ci return &am43xx_ops; 3248c2ecf20Sopenharmony_ci else 3258c2ecf20Sopenharmony_ci return NULL; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci#ifdef CONFIG_SUSPEND 3298c2ecf20Sopenharmony_ci/* 3308c2ecf20Sopenharmony_ci * Block system suspend initially. Later on pm33xx sets up it's own 3318c2ecf20Sopenharmony_ci * platform_suspend_ops after probe. That depends also on loaded 3328c2ecf20Sopenharmony_ci * wkup_m3_ipc and booted am335x-pm-firmware.elf. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_cistatic int amx3_suspend_block(suspend_state_t state) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci pr_warn("PM not initialized for pm33xx, wkup_m3_ipc, or am335x-pm-firmware.elf\n"); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return -EINVAL; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int amx3_pm_valid(suspend_state_t state) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci switch (state) { 3448c2ecf20Sopenharmony_ci case PM_SUSPEND_STANDBY: 3458c2ecf20Sopenharmony_ci return 1; 3468c2ecf20Sopenharmony_ci default: 3478c2ecf20Sopenharmony_ci return 0; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic const struct platform_suspend_ops amx3_blocked_pm_ops = { 3528c2ecf20Sopenharmony_ci .begin = amx3_suspend_block, 3538c2ecf20Sopenharmony_ci .valid = amx3_pm_valid, 3548c2ecf20Sopenharmony_ci}; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void __init amx3_block_suspend(void) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci suspend_set_ops(&amx3_blocked_pm_ops); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci#else 3618c2ecf20Sopenharmony_cistatic inline void amx3_block_suspend(void) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci#endif /* CONFIG_SUSPEND */ 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ciint __init amx3_common_pm_init(void) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct am33xx_pm_platform_data *pdata; 3698c2ecf20Sopenharmony_ci struct platform_device_info devinfo; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci pdata = am33xx_pm_get_pdata(); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci memset(&devinfo, 0, sizeof(devinfo)); 3748c2ecf20Sopenharmony_ci devinfo.name = "pm33xx"; 3758c2ecf20Sopenharmony_ci devinfo.data = pdata; 3768c2ecf20Sopenharmony_ci devinfo.size_data = sizeof(*pdata); 3778c2ecf20Sopenharmony_ci devinfo.id = -1; 3788c2ecf20Sopenharmony_ci platform_device_register_full(&devinfo); 3798c2ecf20Sopenharmony_ci amx3_block_suspend(); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic int __init amx3_idle_init(struct device_node *cpu_node, int cpu) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct device_node *state_node; 3878c2ecf20Sopenharmony_ci struct amx3_idle_state states[CPUIDLE_STATE_MAX]; 3888c2ecf20Sopenharmony_ci int i; 3898c2ecf20Sopenharmony_ci int state_count = 1; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci for (i = 0; ; i++) { 3928c2ecf20Sopenharmony_ci state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); 3938c2ecf20Sopenharmony_ci if (!state_node) 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (!of_device_is_available(state_node)) 3978c2ecf20Sopenharmony_ci continue; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (i == CPUIDLE_STATE_MAX) { 4008c2ecf20Sopenharmony_ci pr_warn("%s: cpuidle states reached max possible\n", 4018c2ecf20Sopenharmony_ci __func__); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci states[state_count].wfi_flags = 0; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (of_property_read_bool(state_node, "ti,idle-wkup-m3")) 4088c2ecf20Sopenharmony_ci states[state_count].wfi_flags |= WFI_FLAG_WAKE_M3 | 4098c2ecf20Sopenharmony_ci WFI_FLAG_FLUSH_CACHE; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci state_count++; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci idle_states = kcalloc(state_count, sizeof(*idle_states), GFP_KERNEL); 4158c2ecf20Sopenharmony_ci if (!idle_states) 4168c2ecf20Sopenharmony_ci return -ENOMEM; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci for (i = 1; i < state_count; i++) 4198c2ecf20Sopenharmony_ci idle_states[i].wfi_flags = states[i].wfi_flags; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int amx3_idle_enter(unsigned long index) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct amx3_idle_state *idle_state = &idle_states[index]; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (!idle_state) 4298c2ecf20Sopenharmony_ci return -EINVAL; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (idle_fn) 4328c2ecf20Sopenharmony_ci idle_fn(idle_state->wfi_flags); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic struct cpuidle_ops amx3_cpuidle_ops __initdata = { 4388c2ecf20Sopenharmony_ci .init = amx3_idle_init, 4398c2ecf20Sopenharmony_ci .suspend = amx3_idle_enter, 4408c2ecf20Sopenharmony_ci}; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ciCPUIDLE_METHOD_OF_DECLARE(pm33xx_idle, "ti,am3352", &amx3_cpuidle_ops); 4438c2ecf20Sopenharmony_ciCPUIDLE_METHOD_OF_DECLARE(pm43xx_idle, "ti,am4372", &amx3_cpuidle_ops); 444