1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * AM33XX Arch Power Management Routines 4 * 5 * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/ 6 * Dave Gerlach 7 */ 8 9 #include <asm/smp_scu.h> 10 #include <asm/suspend.h> 11 #include <linux/errno.h> 12 #include <linux/platform_data/pm33xx.h> 13 #include <linux/clk.h> 14 #include <linux/platform_data/gpio-omap.h> 15 #include <linux/pinctrl/pinmux.h> 16 #include <linux/wkup_m3_ipc.h> 17 #include <linux/of.h> 18 #include <linux/rtc.h> 19 20 #include "cm33xx.h" 21 #include "common.h" 22 #include "control.h" 23 #include "clockdomain.h" 24 #include "iomap.h" 25 #include "omap_hwmod.h" 26 #include "pm.h" 27 #include "powerdomain.h" 28 #include "prm33xx.h" 29 #include "soc.h" 30 #include "sram.h" 31 32 static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm; 33 static struct clockdomain *gfx_l4ls_clkdm; 34 static void __iomem *scu_base; 35 static struct omap_hwmod *rtc_oh; 36 37 static int am43xx_map_scu(void) 38 { 39 scu_base = ioremap(scu_a9_get_base(), SZ_256); 40 41 if (!scu_base) 42 return -ENOMEM; 43 44 return 0; 45 } 46 47 static int am33xx_check_off_mode_enable(void) 48 { 49 if (enable_off_mode) 50 pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n"); 51 52 /* off mode not supported on am335x so return 0 always */ 53 return 0; 54 } 55 56 static int am43xx_check_off_mode_enable(void) 57 { 58 /* 59 * Check for am437x-gp-evm which has the right Hardware design to 60 * support this mode reliably. 61 */ 62 if (of_machine_is_compatible("ti,am437x-gp-evm") && enable_off_mode) 63 return enable_off_mode; 64 else if (enable_off_mode) 65 pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n"); 66 67 return 0; 68 } 69 70 static int amx3_common_init(void) 71 { 72 gfx_pwrdm = pwrdm_lookup("gfx_pwrdm"); 73 per_pwrdm = pwrdm_lookup("per_pwrdm"); 74 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); 75 76 if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm)) 77 return -ENODEV; 78 79 (void)clkdm_for_each(omap_pm_clkdms_setup, NULL); 80 81 /* CEFUSE domain can be turned off post bootup */ 82 cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm"); 83 if (!cefuse_pwrdm) 84 pr_err("PM: Failed to get cefuse_pwrdm\n"); 85 else if (omap_type() != OMAP2_DEVICE_TYPE_GP) 86 pr_info("PM: Leaving EFUSE power domain active\n"); 87 else 88 omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF); 89 90 return 0; 91 } 92 93 static int am33xx_suspend_init(void) 94 { 95 int ret; 96 97 gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm"); 98 99 if (!gfx_l4ls_clkdm) { 100 pr_err("PM: Cannot lookup gfx_l4ls_clkdm clockdomains\n"); 101 return -ENODEV; 102 } 103 104 ret = amx3_common_init(); 105 106 return ret; 107 } 108 109 static int am43xx_suspend_init(void) 110 { 111 int ret = 0; 112 113 ret = am43xx_map_scu(); 114 if (ret) { 115 pr_err("PM: Could not ioremap SCU\n"); 116 return ret; 117 } 118 119 ret = amx3_common_init(); 120 121 return ret; 122 } 123 124 static void amx3_pre_suspend_common(void) 125 { 126 omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF); 127 } 128 129 static void amx3_post_suspend_common(void) 130 { 131 int status; 132 /* 133 * Because gfx_pwrdm is the only one under MPU control, 134 * comment on transition status 135 */ 136 status = pwrdm_read_pwrst(gfx_pwrdm); 137 if (status != PWRDM_POWER_OFF) 138 pr_err("PM: GFX domain did not transition: %x\n", status); 139 } 140 141 static int am33xx_suspend(unsigned int state, int (*fn)(unsigned long), 142 unsigned long args) 143 { 144 int ret = 0; 145 146 amx3_pre_suspend_common(); 147 ret = cpu_suspend(args, fn); 148 amx3_post_suspend_common(); 149 150 /* 151 * BUG: GFX_L4LS clock domain needs to be woken up to 152 * ensure thet L4LS clock domain does not get stuck in 153 * transition. If that happens L3 module does not get 154 * disabled, thereby leading to PER power domain 155 * transition failing 156 */ 157 158 clkdm_wakeup(gfx_l4ls_clkdm); 159 clkdm_sleep(gfx_l4ls_clkdm); 160 161 return ret; 162 } 163 164 static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long), 165 unsigned long args) 166 { 167 int ret = 0; 168 169 amx3_pre_suspend_common(); 170 scu_power_mode(scu_base, SCU_PM_POWEROFF); 171 ret = cpu_suspend(args, fn); 172 scu_power_mode(scu_base, SCU_PM_NORMAL); 173 174 if (!am43xx_check_off_mode_enable()) 175 amx3_post_suspend_common(); 176 177 return ret; 178 } 179 180 static struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void) 181 { 182 if (soc_is_am33xx()) 183 return &am33xx_pm_sram; 184 else if (soc_is_am437x()) 185 return &am43xx_pm_sram; 186 else 187 return NULL; 188 } 189 190 void __iomem *am43xx_get_rtc_base_addr(void) 191 { 192 rtc_oh = omap_hwmod_lookup("rtc"); 193 194 return omap_hwmod_get_mpu_rt_va(rtc_oh); 195 } 196 197 static void am43xx_save_context(void) 198 { 199 } 200 201 static void am33xx_save_context(void) 202 { 203 omap_intc_save_context(); 204 } 205 206 static void am33xx_restore_context(void) 207 { 208 omap_intc_restore_context(); 209 } 210 211 static void am43xx_restore_context(void) 212 { 213 /* 214 * HACK: restore dpll_per_clkdcoldo register contents, to avoid 215 * breaking suspend-resume 216 */ 217 writel_relaxed(0x0, AM33XX_L4_WK_IO_ADDRESS(0x44df2e14)); 218 } 219 220 static void am43xx_prepare_rtc_suspend(void) 221 { 222 omap_hwmod_enable(rtc_oh); 223 } 224 225 static void am43xx_prepare_rtc_resume(void) 226 { 227 omap_hwmod_idle(rtc_oh); 228 } 229 230 static struct am33xx_pm_platform_data am33xx_ops = { 231 .init = am33xx_suspend_init, 232 .soc_suspend = am33xx_suspend, 233 .get_sram_addrs = amx3_get_sram_addrs, 234 .save_context = am33xx_save_context, 235 .restore_context = am33xx_restore_context, 236 .prepare_rtc_suspend = am43xx_prepare_rtc_suspend, 237 .prepare_rtc_resume = am43xx_prepare_rtc_resume, 238 .check_off_mode_enable = am33xx_check_off_mode_enable, 239 .get_rtc_base_addr = am43xx_get_rtc_base_addr, 240 }; 241 242 static struct am33xx_pm_platform_data am43xx_ops = { 243 .init = am43xx_suspend_init, 244 .soc_suspend = am43xx_suspend, 245 .get_sram_addrs = amx3_get_sram_addrs, 246 .save_context = am43xx_save_context, 247 .restore_context = am43xx_restore_context, 248 .prepare_rtc_suspend = am43xx_prepare_rtc_suspend, 249 .prepare_rtc_resume = am43xx_prepare_rtc_resume, 250 .check_off_mode_enable = am43xx_check_off_mode_enable, 251 .get_rtc_base_addr = am43xx_get_rtc_base_addr, 252 }; 253 254 static struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void) 255 { 256 if (soc_is_am33xx()) 257 return &am33xx_ops; 258 else if (soc_is_am437x()) 259 return &am43xx_ops; 260 else 261 return NULL; 262 } 263 264 int __init amx3_common_pm_init(void) 265 { 266 struct am33xx_pm_platform_data *pdata; 267 struct platform_device_info devinfo; 268 269 pdata = am33xx_pm_get_pdata(); 270 271 memset(&devinfo, 0, sizeof(devinfo)); 272 devinfo.name = "pm33xx"; 273 devinfo.data = pdata; 274 devinfo.size_data = sizeof(*pdata); 275 devinfo.id = -1; 276 platform_device_register_full(&devinfo); 277 278 return 0; 279 } 280