^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * pm.c - Common OMAP2+ power management-related code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2010 Texas Instruments, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2010 Nokia Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/pm_opp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/suspend.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/system_misc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "omap_device.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include "soc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include "prcm-common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "voltage.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "powerdomain.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include "clockdomain.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include "pm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u32 enable_off_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #ifdef CONFIG_SUSPEND
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * omap_pm_suspend: points to a function that does the SoC-specific
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * suspend work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static int (*omap_pm_suspend)(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * struct omap2_oscillator - Describe the board main oscillator latencies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * @startup_time: oscillator startup latency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * @shutdown_time: oscillator shutdown latency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct omap2_oscillator {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) u32 startup_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) u32 shutdown_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static struct omap2_oscillator oscillator = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) .startup_time = ULONG_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .shutdown_time = ULONG_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) void omap_pm_setup_oscillator(u32 tstart, u32 tshut)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) oscillator.startup_time = tstart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) oscillator.shutdown_time = tshut;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) void omap_pm_get_oscillator(u32 *tstart, u32 *tshut)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (!tstart || !tshut)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *tstart = oscillator.startup_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) *tshut = oscillator.shutdown_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) clkdm_allow_idle(clkdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #ifdef CONFIG_SUSPEND
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int omap_pm_enter(suspend_state_t suspend_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (!omap_pm_suspend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return -ENOENT; /* XXX doublecheck */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) switch (suspend_state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) case PM_SUSPEND_MEM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ret = omap_pm_suspend();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static int omap_pm_begin(suspend_state_t state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) cpu_idle_poll_ctrl(true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (soc_is_omap34xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) omap_prcm_irq_prepare();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static void omap_pm_end(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) cpu_idle_poll_ctrl(false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static void omap_pm_wake(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (soc_is_omap34xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) omap_prcm_irq_complete();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static const struct platform_suspend_ops omap_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .begin = omap_pm_begin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .end = omap_pm_end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .enter = omap_pm_enter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .wake = omap_pm_wake,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .valid = suspend_valid_only_mem,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * omap_common_suspend_init - Set common suspend routines for OMAP SoCs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * @pm_suspend: function pointer to SoC specific suspend function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) void omap_common_suspend_init(void *pm_suspend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) omap_pm_suspend = pm_suspend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) suspend_set_ops(&omap_pm_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #endif /* CONFIG_SUSPEND */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int __maybe_unused omap_pm_nop_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) int (*omap_pm_soc_init)(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) int __init omap2_common_pm_late_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (!omap_pm_soc_init)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* Init the voltage layer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) omap3_twl_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) omap4_twl_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) omap4_cpcap_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) omap_voltage_late_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /* Smartreflex device init */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) omap_devinit_smartreflex();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) error = omap_pm_soc_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) pr_warn("%s: pm soc init failed: %i\n", __func__, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) omap2_clk_enable_autoidle_all();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) omap_late_initcall(omap2_common_pm_late_init);