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 14 #include "cm33xx.h" 15 #include "common.h" 16 #include "control.h" 17 #include "clockdomain.h" 18 #include "iomap.h" 19 #include "omap_hwmod.h" 20 #include "pm.h" 21 #include "powerdomain.h" 22 #include "prm33xx.h" 23 #include "soc.h" 24 #include "sram.h" 25 26 static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm; 27 static struct clockdomain *gfx_l4ls_clkdm; 28 static void __iomem *scu_base; 29 static struct omap_hwmod *rtc_oh; 30 31 static int am43xx_map_scu(void) 32 { 33 scu_base = ioremap(scu_a9_get_base(), SZ_256); 34 35 if (!scu_base) 36 return -ENOMEM; 37 38 return 0; 39 } 40 41 static int amx3_common_init(void) 42 { 43 gfx_pwrdm = pwrdm_lookup("gfx_pwrdm"); 44 per_pwrdm = pwrdm_lookup("per_pwrdm"); 45 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); 46 47 if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm)) 48 return -ENODEV; 49 50 (void)clkdm_for_each(omap_pm_clkdms_setup, NULL); 51 52 /* CEFUSE domain can be turned off post bootup */ 53 cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm"); 54 if (cefuse_pwrdm) 55 omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF); 56 else 57 pr_err("PM: Failed to get cefuse_pwrdm\n"); 58 59 return 0; 60 } 61 62 static int am33xx_suspend_init(void) 63 { 64 int ret; 65 66 gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm"); 67 68 if (!gfx_l4ls_clkdm) { 69 pr_err("PM: Cannot lookup gfx_l4ls_clkdm clockdomains\n"); 70 return -ENODEV; 71 } 72 73 ret = amx3_common_init(); 74 75 return ret; 76 } 77 78 static int am43xx_suspend_init(void) 79 { 80 int ret = 0; 81 82 ret = am43xx_map_scu(); 83 if (ret) { 84 pr_err("PM: Could not ioremap SCU\n"); 85 return ret; 86 } 87 88 ret = amx3_common_init(); 89 90 return ret; 91 } 92 93 static void amx3_pre_suspend_common(void) 94 { 95 omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF); 96 } 97 98 static void amx3_post_suspend_common(void) 99 { 100 int status; 101 /* 102 * Because gfx_pwrdm is the only one under MPU control, 103 * comment on transition status 104 */ 105 status = pwrdm_read_pwrst(gfx_pwrdm); 106 if (status != PWRDM_POWER_OFF) 107 pr_err("PM: GFX domain did not transition: %x\n", status); 108 } 109 110 static int am33xx_suspend(unsigned int state, int (*fn)(unsigned long), 111 unsigned long args) 112 { 113 int ret = 0; 114 115 amx3_pre_suspend_common(); 116 ret = cpu_suspend(args, fn); 117 amx3_post_suspend_common(); 118 119 /* 120 * BUG: GFX_L4LS clock domain needs to be woken up to 121 * ensure thet L4LS clock domain does not get stuck in 122 * transition. If that happens L3 module does not get 123 * disabled, thereby leading to PER power domain 124 * transition failing 125 */ 126 127 clkdm_wakeup(gfx_l4ls_clkdm); 128 clkdm_sleep(gfx_l4ls_clkdm); 129 130 return ret; 131 } 132 133 static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long), 134 unsigned long args) 135 { 136 int ret = 0; 137 138 amx3_pre_suspend_common(); 139 scu_power_mode(scu_base, SCU_PM_POWEROFF); 140 ret = cpu_suspend(args, fn); 141 scu_power_mode(scu_base, SCU_PM_NORMAL); 142 amx3_post_suspend_common(); 143 144 return ret; 145 } 146 147 static struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void) 148 { 149 if (soc_is_am33xx()) 150 return &am33xx_pm_sram; 151 else if (soc_is_am437x()) 152 return &am43xx_pm_sram; 153 else 154 return NULL; 155 } 156 157 void __iomem *am43xx_get_rtc_base_addr(void) 158 { 159 rtc_oh = omap_hwmod_lookup("rtc"); 160 161 return omap_hwmod_get_mpu_rt_va(rtc_oh); 162 } 163 164 static struct am33xx_pm_platform_data am33xx_ops = { 165 .init = am33xx_suspend_init, 166 .soc_suspend = am33xx_suspend, 167 .get_sram_addrs = amx3_get_sram_addrs, 168 .get_rtc_base_addr = am43xx_get_rtc_base_addr, 169 }; 170 171 static struct am33xx_pm_platform_data am43xx_ops = { 172 .init = am43xx_suspend_init, 173 .soc_suspend = am43xx_suspend, 174 .get_sram_addrs = amx3_get_sram_addrs, 175 .get_rtc_base_addr = am43xx_get_rtc_base_addr, 176 }; 177 178 static struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void) 179 { 180 if (soc_is_am33xx()) 181 return &am33xx_ops; 182 else if (soc_is_am437x()) 183 return &am43xx_ops; 184 else 185 return NULL; 186 } 187 188 int __init amx3_common_pm_init(void) 189 { 190 struct am33xx_pm_platform_data *pdata; 191 struct platform_device_info devinfo; 192 193 pdata = am33xx_pm_get_pdata(); 194 195 memset(&devinfo, 0, sizeof(devinfo)); 196 devinfo.name = "pm33xx"; 197 devinfo.data = pdata; 198 devinfo.size_data = sizeof(*pdata); 199 devinfo.id = -1; 200 platform_device_register_full(&devinfo); 201 202 return 0; 203 } 204