| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * AM33XX Arch Power Management Routines
- *
- * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
- * Dave Gerlach
- */
- #include <asm/smp_scu.h>
- #include <asm/suspend.h>
- #include <linux/errno.h>
- #include <linux/platform_data/pm33xx.h>
- #include "cm33xx.h"
- #include "common.h"
- #include "control.h"
- #include "clockdomain.h"
- #include "iomap.h"
- #include "omap_hwmod.h"
- #include "pm.h"
- #include "powerdomain.h"
- #include "prm33xx.h"
- #include "soc.h"
- #include "sram.h"
- static struct powerdomain *cefuse_pwrdm, *gfx_pwrdm, *per_pwrdm, *mpu_pwrdm;
- static struct clockdomain *gfx_l4ls_clkdm;
- static void __iomem *scu_base;
- static struct omap_hwmod *rtc_oh;
- static int __init am43xx_map_scu(void)
- {
- scu_base = ioremap(scu_a9_get_base(), SZ_256);
- if (!scu_base)
- return -ENOMEM;
- return 0;
- }
- static int amx3_common_init(void)
- {
- gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
- per_pwrdm = pwrdm_lookup("per_pwrdm");
- mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
- if ((!gfx_pwrdm) || (!per_pwrdm) || (!mpu_pwrdm))
- return -ENODEV;
- (void)clkdm_for_each(omap_pm_clkdms_setup, NULL);
- /* CEFUSE domain can be turned off post bootup */
- cefuse_pwrdm = pwrdm_lookup("cefuse_pwrdm");
- if (!cefuse_pwrdm)
- pr_err("PM: Failed to get cefuse_pwrdm\n");
- else if (omap_type() != OMAP2_DEVICE_TYPE_GP)
- pr_info("PM: Leaving EFUSE power domain active\n");
- else
- omap_set_pwrdm_state(cefuse_pwrdm, PWRDM_POWER_OFF);
- return 0;
- }
- static int am33xx_suspend_init(void)
- {
- int ret;
- gfx_l4ls_clkdm = clkdm_lookup("gfx_l4ls_gfx_clkdm");
- if (!gfx_l4ls_clkdm) {
- pr_err("PM: Cannot lookup gfx_l4ls_clkdm clockdomains\n");
- return -ENODEV;
- }
- ret = amx3_common_init();
- return ret;
- }
- static int am43xx_suspend_init(void)
- {
- int ret = 0;
- ret = am43xx_map_scu();
- if (ret) {
- pr_err("PM: Could not ioremap SCU\n");
- return ret;
- }
- ret = amx3_common_init();
- return ret;
- }
- static void amx3_pre_suspend_common(void)
- {
- omap_set_pwrdm_state(gfx_pwrdm, PWRDM_POWER_OFF);
- }
- static void amx3_post_suspend_common(void)
- {
- int status;
- /*
- * Because gfx_pwrdm is the only one under MPU control,
- * comment on transition status
- */
- status = pwrdm_read_pwrst(gfx_pwrdm);
- if (status != PWRDM_POWER_OFF)
- pr_err("PM: GFX domain did not transition: %x\n", status);
- }
- static int am33xx_suspend(unsigned int state, int (*fn)(unsigned long),
- unsigned long args)
- {
- int ret = 0;
- amx3_pre_suspend_common();
- ret = cpu_suspend(args, fn);
- amx3_post_suspend_common();
- /*
- * BUG: GFX_L4LS clock domain needs to be woken up to
- * ensure thet L4LS clock domain does not get stuck in
- * transition. If that happens L3 module does not get
- * disabled, thereby leading to PER power domain
- * transition failing
- */
- clkdm_wakeup(gfx_l4ls_clkdm);
- clkdm_sleep(gfx_l4ls_clkdm);
- return ret;
- }
- static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long),
- unsigned long args)
- {
- int ret = 0;
- amx3_pre_suspend_common();
- scu_power_mode(scu_base, SCU_PM_POWEROFF);
- ret = cpu_suspend(args, fn);
- scu_power_mode(scu_base, SCU_PM_NORMAL);
- amx3_post_suspend_common();
- return ret;
- }
- static struct am33xx_pm_sram_addr *amx3_get_sram_addrs(void)
- {
- if (soc_is_am33xx())
- return &am33xx_pm_sram;
- else if (soc_is_am437x())
- return &am43xx_pm_sram;
- else
- return NULL;
- }
- void __iomem *am43xx_get_rtc_base_addr(void)
- {
- rtc_oh = omap_hwmod_lookup("rtc");
- return omap_hwmod_get_mpu_rt_va(rtc_oh);
- }
- static struct am33xx_pm_platform_data am33xx_ops = {
- .init = am33xx_suspend_init,
- .soc_suspend = am33xx_suspend,
- .get_sram_addrs = amx3_get_sram_addrs,
- .get_rtc_base_addr = am43xx_get_rtc_base_addr,
- };
- static struct am33xx_pm_platform_data am43xx_ops = {
- .init = am43xx_suspend_init,
- .soc_suspend = am43xx_suspend,
- .get_sram_addrs = amx3_get_sram_addrs,
- .get_rtc_base_addr = am43xx_get_rtc_base_addr,
- };
- static struct am33xx_pm_platform_data *am33xx_pm_get_pdata(void)
- {
- if (soc_is_am33xx())
- return &am33xx_ops;
- else if (soc_is_am437x())
- return &am43xx_ops;
- else
- return NULL;
- }
- int __init amx3_common_pm_init(void)
- {
- struct am33xx_pm_platform_data *pdata;
- struct platform_device_info devinfo;
- pdata = am33xx_pm_get_pdata();
- memset(&devinfo, 0, sizeof(devinfo));
- devinfo.name = "pm33xx";
- devinfo.data = pdata;
- devinfo.size_data = sizeof(*pdata);
- devinfo.id = -1;
- platform_device_register_full(&devinfo);
- return 0;
- }
|