^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) * OMAP powerdomain control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2007-2008, 2011 Texas Instruments, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2007-2011 Nokia Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Written by Paul Walmsley
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * State counting code by Tero Kristo <tero.kristo@nokia.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #undef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/cpu_pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <trace/events/power.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "cm2xxx_3xxx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include "prcm44xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include "cm44xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "prm2xxx_3xxx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "prm44xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <asm/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include "powerdomain.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include "clockdomain.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include "voltage.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include "soc.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include "pm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define PWRDM_TRACE_STATES_FLAG (1<<31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) void pwrdms_save_context(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) void pwrdms_restore_context(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) PWRDM_STATE_NOW = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) PWRDM_STATE_PREV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * Types of sleep_switch used internally in omap_set_pwrdm_state()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * and its associated static functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * XXX Better documentation is needed here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define ALREADYACTIVE_SWITCH 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define FORCEWAKEUP_SWITCH 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define LOWPOWERSTATE_SWITCH 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* pwrdm_list contains all registered struct powerdomains */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static LIST_HEAD(pwrdm_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static struct pwrdm_ops *arch_pwrdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* Private functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static struct powerdomain *_pwrdm_lookup(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct powerdomain *pwrdm, *temp_pwrdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) pwrdm = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (!strcmp(name, temp_pwrdm->name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) pwrdm = temp_pwrdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return pwrdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * _pwrdm_register - register a powerdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * @pwrdm: struct powerdomain * to register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * Adds a powerdomain to the internal powerdomain list. Returns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * -EINVAL if given a null pointer, -EEXIST if a powerdomain is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * already registered by the provided name, or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static int _pwrdm_register(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct voltagedomain *voltdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (!pwrdm || !pwrdm->name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (cpu_is_omap44xx() &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) pwrdm->prcm_partition == OMAP4430_INVALID_PRCM_PARTITION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) pr_err("powerdomain: %s: missing OMAP4 PRCM partition ID\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) pwrdm->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (_pwrdm_lookup(pwrdm->name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (arch_pwrdm && arch_pwrdm->pwrdm_has_voltdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (!arch_pwrdm->pwrdm_has_voltdm())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) goto skip_voltdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) voltdm = voltdm_lookup(pwrdm->voltdm.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (!voltdm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) pr_err("powerdomain: %s: voltagedomain %s does not exist\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) pwrdm->name, pwrdm->voltdm.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) pwrdm->voltdm.ptr = voltdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) INIT_LIST_HEAD(&pwrdm->voltdm_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) skip_voltdm:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) spin_lock_init(&pwrdm->_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) list_add(&pwrdm->node, &pwrdm_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /* Initialize the powerdomain's state counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) pwrdm->state_counter[i] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) pwrdm->ret_logic_off_counter = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) for (i = 0; i < pwrdm->banks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) pwrdm->ret_mem_off_counter[i] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (arch_pwrdm && arch_pwrdm->pwrdm_wait_transition)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) arch_pwrdm->pwrdm_wait_transition(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) pwrdm->state = pwrdm_read_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) pwrdm->state_counter[pwrdm->state] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) pr_debug("powerdomain: registered %s\n", pwrdm->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static void _update_logic_membank_counters(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) u8 prev_logic_pwrst, prev_mem_pwrst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) prev_logic_pwrst = pwrdm_read_prev_logic_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) (prev_logic_pwrst == PWRDM_POWER_OFF))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) pwrdm->ret_logic_off_counter++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) for (i = 0; i < pwrdm->banks; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) prev_mem_pwrst = pwrdm_read_prev_mem_pwrst(pwrdm, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if ((pwrdm->pwrsts_mem_ret[i] == PWRSTS_OFF_RET) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) (prev_mem_pwrst == PWRDM_POWER_OFF))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) pwrdm->ret_mem_off_counter[i]++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) int prev, next, state, trace_state = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (pwrdm == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) state = pwrdm_read_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) switch (flag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) case PWRDM_STATE_NOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) prev = pwrdm->state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) case PWRDM_STATE_PREV:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) prev = pwrdm_read_prev_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (pwrdm->state != prev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) pwrdm->state_counter[prev]++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (prev == PWRDM_POWER_RET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) _update_logic_membank_counters(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * If the power domain did not hit the desired state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * generate a trace event with both the desired and hit states
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) next = pwrdm_read_next_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (next != prev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) trace_state = (PWRDM_TRACE_STATES_FLAG |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) ((next & OMAP_POWERSTATE_MASK) << 8) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) ((prev & OMAP_POWERSTATE_MASK) << 0));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) trace_power_domain_target_rcuidle(pwrdm->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) trace_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) raw_smp_processor_id());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (state != prev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) pwrdm->state_counter[state]++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) pm_dbg_update_time(pwrdm, prev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) pwrdm->state = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) pwrdm_clear_all_prev_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * _pwrdm_save_clkdm_state_and_activate - prepare for power state change
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * @pwrdm: struct powerdomain * to operate on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * @curr_pwrst: current power state of @pwrdm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * @pwrst: power state to switch to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * Determine whether the powerdomain needs to be turned on before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * attempting to switch power states. Called by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * omap_set_pwrdm_state(). NOTE that if the powerdomain contains
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) * multiple clockdomains, this code assumes that the first clockdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) * supports software-supervised wakeup mode - potentially a problem.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * Returns the power state switch mode currently in use (see the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * "Types of sleep_switch" comment above).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) u8 curr_pwrst, u8 pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) u8 sleep_switch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (curr_pwrst < PWRDM_POWER_ON) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (curr_pwrst > pwrst &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) arch_pwrdm->pwrdm_set_lowpwrstchange) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) sleep_switch = LOWPOWERSTATE_SWITCH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) clkdm_deny_idle_nolock(pwrdm->pwrdm_clkdms[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) sleep_switch = FORCEWAKEUP_SWITCH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) sleep_switch = ALREADYACTIVE_SWITCH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return sleep_switch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * _pwrdm_restore_clkdm_state - restore the clkdm hwsup state after pwrst change
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * @pwrdm: struct powerdomain * to operate on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * @sleep_switch: return value from _pwrdm_save_clkdm_state_and_activate()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) * Restore the clockdomain state perturbed by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) * _pwrdm_save_clkdm_state_and_activate(), and call the power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) * bookkeeping code. Called by omap_set_pwrdm_state(). NOTE that if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) * the powerdomain contains multiple clockdomains, this assumes that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) * the first associated clockdomain supports either
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) * hardware-supervised idle control in the register, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * software-supervised sleep. No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) u8 sleep_switch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) switch (sleep_switch) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) case FORCEWAKEUP_SWITCH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) clkdm_allow_idle_nolock(pwrdm->pwrdm_clkdms[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) case LOWPOWERSTATE_SWITCH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) arch_pwrdm->pwrdm_set_lowpwrstchange)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) pwrdm_state_switch_nolock(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) /* Public functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * pwrdm_register_platform_funcs - register powerdomain implementation fns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * @po: func pointers for arch specific implementations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) * Register the list of function pointers used to implement the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) * powerdomain functions on different OMAP SoCs. Should be called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) * before any other pwrdm_register*() function. Returns -EINVAL if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) * @po is null, -EEXIST if platform functions have already been
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) * registered, or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) int pwrdm_register_platform_funcs(struct pwrdm_ops *po)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (!po)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) if (arch_pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) arch_pwrdm = po;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) * pwrdm_register_pwrdms - register SoC powerdomains
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) * @ps: pointer to an array of struct powerdomain to register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) * Register the powerdomains available on a particular OMAP SoC. Must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) * be called after pwrdm_register_platform_funcs(). May be called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) * multiple times. Returns -EACCES if called before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) * pwrdm_register_platform_funcs(); -EINVAL if the argument @ps is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) * null; or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) int pwrdm_register_pwrdms(struct powerdomain **ps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) struct powerdomain **p = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (!arch_pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (!ps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) for (p = ps; *p; p++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) _pwrdm_register(*p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static int cpu_notifier(struct notifier_block *nb, unsigned long cmd, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) case CPU_CLUSTER_PM_ENTER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (enable_off_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) pwrdms_save_context();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) case CPU_CLUSTER_PM_EXIT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (enable_off_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) pwrdms_restore_context();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return NOTIFY_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) * pwrdm_complete_init - set up the powerdomain layer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) * Do whatever is necessary to initialize registered powerdomains and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) * powerdomain code. Currently, this programs the next power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) * for each powerdomain to ON. This prevents powerdomains from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) * unexpectedly losing context or entering high wakeup latency modes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) * with non-power-management-enabled kernels. Must be called after
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) * pwrdm_register_pwrdms(). Returns -EACCES if called before
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) * pwrdm_register_pwrdms(), or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) int pwrdm_complete_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) struct powerdomain *temp_p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) static struct notifier_block nb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) if (list_empty(&pwrdm_list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return -EACCES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) list_for_each_entry(temp_p, &pwrdm_list, node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) pwrdm_set_next_pwrst(temp_p, PWRDM_POWER_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) /* Only AM43XX can lose pwrdm context during rtc-ddr suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (soc_is_am43xx()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) nb.notifier_call = cpu_notifier;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) cpu_pm_register_notifier(&nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * pwrdm_lock - acquire a Linux spinlock on a powerdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * @pwrdm: struct powerdomain * to lock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * Acquire the powerdomain spinlock on @pwrdm. No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) void pwrdm_lock(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) __acquires(&pwrdm->_lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) spin_lock_irqsave(&pwrdm->_lock, pwrdm->_lock_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * pwrdm_unlock - release a Linux spinlock on a powerdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) * @pwrdm: struct powerdomain * to unlock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) * Release the powerdomain spinlock on @pwrdm. No return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) void pwrdm_unlock(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) __releases(&pwrdm->_lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) spin_unlock_irqrestore(&pwrdm->_lock, pwrdm->_lock_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) * pwrdm_lookup - look up a powerdomain by name, return a pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) * @name: name of powerdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) * Find a registered powerdomain by its name @name. Returns a pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) * to the struct powerdomain if found, or NULL otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) struct powerdomain *pwrdm_lookup(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct powerdomain *pwrdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (!name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) pwrdm = _pwrdm_lookup(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) return pwrdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * pwrdm_for_each - call function on each registered clockdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * @fn: callback function *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * Call the supplied function @fn for each registered powerdomain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) * The callback function @fn can return anything but 0 to bail out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) * early from the iterator. Returns the last return value of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) * callback function, which should be 0 for success or anything else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) * to indicate failure; or -EINVAL if the function pointer is null.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) void *user)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) struct powerdomain *temp_pwrdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) if (!fn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) ret = (*fn)(temp_pwrdm, user);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) * pwrdm_add_clkdm - add a clockdomain to a powerdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) * @pwrdm: struct powerdomain * to add the clockdomain to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) * @clkdm: struct clockdomain * to associate with a powerdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) * Associate the clockdomain @clkdm with a powerdomain @pwrdm. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) * enables the use of pwrdm_for_each_clkdm(). Returns -EINVAL if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) * presented with invalid pointers; -ENOMEM if memory could not be allocated;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) * or 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (!pwrdm || !clkdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) pr_debug("powerdomain: %s: associating clockdomain %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) pwrdm->name, clkdm->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) for (i = 0; i < PWRDM_MAX_CLKDMS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) if (!pwrdm->pwrdm_clkdms[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (pwrdm->pwrdm_clkdms[i] == clkdm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) goto pac_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) if (i == PWRDM_MAX_CLKDMS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) pr_debug("powerdomain: %s: increase PWRDM_MAX_CLKDMS for clkdm %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) pwrdm->name, clkdm->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) WARN_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) goto pac_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) pwrdm->pwrdm_clkdms[i] = clkdm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) pac_exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) * @pwrdm: struct powerdomain *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) * Return the number of controllable memory banks in powerdomain @pwrdm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) * starting with 1. Returns -EINVAL if the powerdomain pointer is null.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) return pwrdm->banks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) * pwrdm_set_next_pwrst - set next powerdomain power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) * @pwrdm: struct powerdomain * to set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) * @pwrst: one of the PWRDM_POWER_* macros
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) * Set the powerdomain @pwrdm's next power state to @pwrst. The powerdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) * may not enter this state immediately if the preconditions for this state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) * have not been satisfied. Returns -EINVAL if the powerdomain pointer is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) * null or if the power state is invalid for the powerdomin, or returns 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (!(pwrdm->pwrsts & (1 << pwrst)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) pr_debug("powerdomain: %s: setting next powerstate to %0x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) pwrdm->name, pwrst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (arch_pwrdm && arch_pwrdm->pwrdm_set_next_pwrst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) /* Trace the pwrdm desired target state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) trace_power_domain_target_rcuidle(pwrdm->name, pwrst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) raw_smp_processor_id());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) /* Program the pwrdm desired target state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) ret = arch_pwrdm->pwrdm_set_next_pwrst(pwrdm, pwrst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * pwrdm_read_next_pwrst - get next powerdomain power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * @pwrdm: struct powerdomain * to get power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * Return the powerdomain @pwrdm's next power state. Returns -EINVAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * if the powerdomain pointer is null or returns the next power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (arch_pwrdm && arch_pwrdm->pwrdm_read_next_pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) ret = arch_pwrdm->pwrdm_read_next_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) * pwrdm_read_pwrst - get current powerdomain power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) * @pwrdm: struct powerdomain * to get power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) * Return the powerdomain @pwrdm's current power state. Returns -EINVAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) * if the powerdomain pointer is null or returns the current power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) * upon success. Note that if the power domain only supports the ON state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) * then just return ON as the current state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) int pwrdm_read_pwrst(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (pwrdm->pwrsts == PWRSTS_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) return PWRDM_POWER_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (arch_pwrdm && arch_pwrdm->pwrdm_read_pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) ret = arch_pwrdm->pwrdm_read_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) * pwrdm_read_prev_pwrst - get previous powerdomain power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) * @pwrdm: struct powerdomain * to get previous power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) * Return the powerdomain @pwrdm's previous power state. Returns -EINVAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) * if the powerdomain pointer is null or returns the previous power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) * upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) ret = arch_pwrdm->pwrdm_read_prev_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) * @pwrdm: struct powerdomain * to set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) * @pwrst: one of the PWRDM_POWER_* macros
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) * Set the next power state @pwrst that the logic portion of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) * powerdomain @pwrdm will enter when the powerdomain enters retention.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) * This will be either RETENTION or OFF, if supported. Returns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) * -EINVAL if the powerdomain pointer is null or the target power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * state is not not supported, or returns 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) pr_debug("powerdomain: %s: setting next logic powerstate to %0x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) pwrdm->name, pwrst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (arch_pwrdm && arch_pwrdm->pwrdm_set_logic_retst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) ret = arch_pwrdm->pwrdm_set_logic_retst(pwrdm, pwrst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) * pwrdm_set_mem_onst - set memory power state while powerdomain ON
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) * @pwrdm: struct powerdomain * to set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) * @bank: memory bank number to set (0-3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) * @pwrst: one of the PWRDM_POWER_* macros
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) * Set the next power state @pwrst that memory bank @bank of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) * powerdomain @pwrdm will enter when the powerdomain enters the ON
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) * state. @bank will be a number from 0 to 3, and represents different
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) * types of memory, depending on the powerdomain. Returns -EINVAL if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) * the powerdomain pointer is null or the target power state is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) * not supported for this memory bank, -EEXIST if the target memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) * bank does not exist or is not controllable, or returns 0 upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) * success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) if (pwrdm->banks < (bank + 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-ON to %0x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) pwrdm->name, bank, pwrst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_onst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) ret = arch_pwrdm->pwrdm_set_mem_onst(pwrdm, bank, pwrst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) * @pwrdm: struct powerdomain * to set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) * @bank: memory bank number to set (0-3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * @pwrst: one of the PWRDM_POWER_* macros
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) * Set the next power state @pwrst that memory bank @bank of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) * powerdomain @pwrdm will enter when the powerdomain enters the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) * RETENTION state. Bank will be a number from 0 to 3, and represents
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) * different types of memory, depending on the powerdomain. @pwrst
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) * will be either RETENTION or OFF, if supported. Returns -EINVAL if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) * the powerdomain pointer is null or the target power state is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) * not supported for this memory bank, -EEXIST if the target memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) * bank does not exist or is not controllable, or returns 0 upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) * success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) if (pwrdm->banks < (bank + 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) pr_debug("powerdomain: %s: setting next memory powerstate for bank %0x while pwrdm-RET to %0x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) pwrdm->name, bank, pwrst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) if (arch_pwrdm && arch_pwrdm->pwrdm_set_mem_retst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) ret = arch_pwrdm->pwrdm_set_mem_retst(pwrdm, bank, pwrst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) * @pwrdm: struct powerdomain * to get current logic retention power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) * Return the power state that the logic portion of powerdomain @pwrdm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) * will enter when the powerdomain enters retention. Returns -EINVAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) * if the powerdomain pointer is null or returns the logic retention
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) * power state upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) ret = arch_pwrdm->pwrdm_read_logic_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) * @pwrdm: struct powerdomain * to get previous logic power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) * Return the powerdomain @pwrdm's previous logic power state. Returns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) * -EINVAL if the powerdomain pointer is null or returns the previous
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) * logic power state upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_logic_pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) ret = arch_pwrdm->pwrdm_read_prev_logic_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) * pwrdm_read_logic_retst - get next powerdomain logic power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) * @pwrdm: struct powerdomain * to get next logic power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) * Return the powerdomain pwrdm's logic power state. Returns -EINVAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) * if the powerdomain pointer is null or returns the next logic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) * power state upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) int pwrdm_read_logic_retst(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) if (arch_pwrdm && arch_pwrdm->pwrdm_read_logic_retst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) ret = arch_pwrdm->pwrdm_read_logic_retst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) * pwrdm_read_mem_pwrst - get current memory bank power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) * @pwrdm: struct powerdomain * to get current memory bank power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) * @bank: memory bank number (0-3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) * Return the powerdomain @pwrdm's current memory power state for bank
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) * @bank. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) * the target memory bank does not exist or is not controllable, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) * returns the current memory power state upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) if (pwrdm->banks < (bank + 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) bank = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) ret = arch_pwrdm->pwrdm_read_mem_pwrst(pwrdm, bank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) * pwrdm_read_prev_mem_pwrst - get previous memory bank power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) * @pwrdm: struct powerdomain * to get previous memory bank power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) * @bank: memory bank number (0-3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) * Return the powerdomain @pwrdm's previous memory power state for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) * bank @bank. Returns -EINVAL if the powerdomain pointer is null,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) * -EEXIST if the target memory bank does not exist or is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) * controllable, or returns the previous memory power state upon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) * success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if (pwrdm->banks < (bank + 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) if (pwrdm->flags & PWRDM_HAS_MPU_QUIRK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) bank = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (arch_pwrdm && arch_pwrdm->pwrdm_read_prev_mem_pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) ret = arch_pwrdm->pwrdm_read_prev_mem_pwrst(pwrdm, bank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) * pwrdm_read_mem_retst - get next memory bank power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) * @pwrdm: struct powerdomain * to get mext memory bank power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) * @bank: memory bank number (0-3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) * Return the powerdomain pwrdm's next memory power state for bank
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) * x. Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) * the target memory bank does not exist or is not controllable, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) * returns the next memory power state upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) int pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) if (pwrdm->banks < (bank + 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) if (arch_pwrdm && arch_pwrdm->pwrdm_read_mem_retst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) ret = arch_pwrdm->pwrdm_read_mem_retst(pwrdm, bank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) * @pwrdm: struct powerdomain * to clear
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) * Clear the powerdomain's previous power state register @pwrdm.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) * Clears the entire register, including logic and memory bank
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) * previous power states. Returns -EINVAL if the powerdomain pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) * is null, or returns 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) * XXX should get the powerdomain's current state here;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) * warn & fail if it is not ON.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) pr_debug("powerdomain: %s: clearing previous power state reg\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) pwrdm->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) if (arch_pwrdm && arch_pwrdm->pwrdm_clear_all_prev_pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) ret = arch_pwrdm->pwrdm_clear_all_prev_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) * pwrdm_enable_hdwr_sar - enable automatic hardware SAR for a pwrdm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) * @pwrdm: struct powerdomain *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) * Enable automatic context save-and-restore upon power state change
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) * for some devices in the powerdomain @pwrdm. Warning: this only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) * affects a subset of devices in a powerdomain; check the TRM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) * closely. Returns -EINVAL if the powerdomain pointer is null or if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) * the powerdomain does not support automatic save-and-restore, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) * returns 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n", pwrdm->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) if (arch_pwrdm && arch_pwrdm->pwrdm_enable_hdwr_sar)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) ret = arch_pwrdm->pwrdm_enable_hdwr_sar(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) * pwrdm_disable_hdwr_sar - disable automatic hardware SAR for a pwrdm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) * @pwrdm: struct powerdomain *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) * Disable automatic context save-and-restore upon power state change
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) * for some devices in the powerdomain @pwrdm. Warning: this only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) * affects a subset of devices in a powerdomain; check the TRM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) * closely. Returns -EINVAL if the powerdomain pointer is null or if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) * the powerdomain does not support automatic save-and-restore, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) * returns 0 upon success.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) if (!pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n", pwrdm->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) if (arch_pwrdm && arch_pwrdm->pwrdm_disable_hdwr_sar)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) ret = arch_pwrdm->pwrdm_disable_hdwr_sar(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) * pwrdm_has_hdwr_sar - test whether powerdomain supports hardware SAR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) * @pwrdm: struct powerdomain *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) * Returns 1 if powerdomain @pwrdm supports hardware save-and-restore
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) * for some devices, or 0 if it does not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) int pwrdm_state_switch_nolock(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) if (!pwrdm || !arch_pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) ret = arch_pwrdm->pwrdm_wait_transition(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) int __deprecated pwrdm_state_switch(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) pwrdm_lock(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) ret = pwrdm_state_switch_nolock(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) pwrdm_unlock(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) int pwrdm_pre_transition(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) if (pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) _pwrdm_pre_transition_cb(pwrdm, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) int pwrdm_post_transition(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) if (pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) _pwrdm_post_transition_cb(pwrdm, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) pwrdm_for_each(_pwrdm_post_transition_cb, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) * pwrdm_get_valid_lp_state() - Find best match deep power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) * @pwrdm: power domain for which we want to find best match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) * @is_logic_state: Are we looking for logic state match here? Should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) * be one of PWRDM_xxx macro values
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) * @req_state: requested power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) * Returns: closest match for requested power state. default fallback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) * is RET for logic state and ON for power state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) * This does a search from the power domain data looking for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) * closest valid power domain state that the hardware can achieve.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) * PRCM definitions for PWRSTCTRL allows us to program whatever
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) * configuration we'd like, and PRCM will actually attempt such
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) * a transition, however if the powerdomain does not actually support it,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) * we endup with a hung system. The valid power domain states are already
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) * available in our powerdomain data files. So this function tries to do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) * the following:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) * a) find if we have an exact match to the request - no issues.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) * b) else find if a deeper power state is possible.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) * c) failing which, it tries to find closest higher power state for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) * request.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) u8 pwrdm_get_valid_lp_state(struct powerdomain *pwrdm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) bool is_logic_state, u8 req_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) u8 pwrdm_states = is_logic_state ? pwrdm->pwrsts_logic_ret :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) pwrdm->pwrsts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) /* For logic, ret is highest and others, ON is highest */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) u8 default_pwrst = is_logic_state ? PWRDM_POWER_RET : PWRDM_POWER_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) u8 new_pwrst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) bool found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) /* If it is already supported, nothing to search */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) if (pwrdm_states & BIT(req_state))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) return req_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) if (!req_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) goto up_search;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) * So, we dont have a exact match
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) * Can we get a deeper power state match?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) new_pwrst = req_state - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) while (!(pwrdm_states & BIT(new_pwrst))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) /* No match even at OFF? Not available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) if (new_pwrst == PWRDM_POWER_OFF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) new_pwrst--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) if (found)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) up_search:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) /* OK, no deeper ones, can we get a higher match? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) new_pwrst = req_state + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) while (!(pwrdm_states & BIT(new_pwrst))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) if (new_pwrst > PWRDM_POWER_ON) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) WARN(1, "powerdomain: %s: Fix max powerstate to ON\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) pwrdm->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) return PWRDM_POWER_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) if (new_pwrst == default_pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) new_pwrst++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) return new_pwrst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) * omap_set_pwrdm_state - change a powerdomain's current power state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) * @pwrdm: struct powerdomain * to change the power state of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) * @pwrst: power state to change to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) * Change the current hardware power state of the powerdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) * represented by @pwrdm to the power state represented by @pwrst.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) * Returns -EINVAL if @pwrdm is null or invalid or if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) * powerdomain's current power state could not be read, or returns 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) * upon success or if @pwrdm does not support @pwrst or any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) * lower-power state. XXX Should not return 0 if the @pwrdm does not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) * support @pwrst or any lower-power state: this should be an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) u8 next_pwrst, sleep_switch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) int curr_pwrst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) if (!pwrdm || IS_ERR(pwrdm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) while (!(pwrdm->pwrsts & (1 << pwrst))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) if (pwrst == PWRDM_POWER_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) pwrst--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) pwrdm_lock(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) curr_pwrst = pwrdm_read_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) if (curr_pwrst < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) goto osps_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) next_pwrst = pwrdm_read_next_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) if (curr_pwrst == pwrst && next_pwrst == pwrst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) goto osps_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) pwrst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) pr_err("%s: unable to set power state of powerdomain: %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) __func__, pwrdm->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) _pwrdm_restore_clkdm_state(pwrdm, sleep_switch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) osps_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) pwrdm_unlock(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) * pwrdm_get_context_loss_count - get powerdomain's context loss count
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) * @pwrdm: struct powerdomain * to wait for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) * Context loss count is the sum of powerdomain off-mode counter, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) * logic off counter and the per-bank memory off counter. Returns negative
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) * (and WARNs) upon error, otherwise, returns the context loss count.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) int pwrdm_get_context_loss_count(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) int i, count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) if (!pwrdm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) WARN(1, "powerdomain: %s: pwrdm is null\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) count = pwrdm->state_counter[PWRDM_POWER_OFF];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) count += pwrdm->ret_logic_off_counter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) for (i = 0; i < pwrdm->banks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) count += pwrdm->ret_mem_off_counter[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) * Context loss count has to be a non-negative value. Clear the sign
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) * bit to get a value range from 0 to INT_MAX.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) count &= INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) pr_debug("powerdomain: %s: context loss count = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) pwrdm->name, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) * pwrdm_can_ever_lose_context - can this powerdomain ever lose context?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) * @pwrdm: struct powerdomain *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) * Given a struct powerdomain * @pwrdm, returns 1 if the powerdomain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) * can lose either memory or logic context or if @pwrdm is invalid, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) * returns 0 otherwise. This function is not concerned with how the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) * powerdomain registers are programmed (i.e., to go off or not); it's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) * concerned with whether it's ever possible for this powerdomain to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) * go off while some other part of the chip is active. This function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) * assumes that every powerdomain can go to either ON or INACTIVE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) if (!pwrdm) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) pr_debug("powerdomain: %s: invalid powerdomain pointer\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) if (pwrdm->pwrsts & PWRSTS_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) if (pwrdm->pwrsts & PWRSTS_RET) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) if (pwrdm->pwrsts_logic_ret & PWRSTS_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) for (i = 0; i < pwrdm->banks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) if (pwrdm->pwrsts_mem_ret[i] & PWRSTS_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) for (i = 0; i < pwrdm->banks; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) if (pwrdm->pwrsts_mem_on[i] & PWRSTS_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) * pwrdm_save_context - save powerdomain registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) * Register state is going to be lost due to a suspend or hibernate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) * event. Save the powerdomain registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) static int pwrdm_save_context(struct powerdomain *pwrdm, void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) if (arch_pwrdm && arch_pwrdm->pwrdm_save_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) arch_pwrdm->pwrdm_save_context(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) * pwrdm_save_context - restore powerdomain registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) * Restore powerdomain control registers after a suspend or resume
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) * event.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) static int pwrdm_restore_context(struct powerdomain *pwrdm, void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) if (arch_pwrdm && arch_pwrdm->pwrdm_restore_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) arch_pwrdm->pwrdm_restore_context(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) static int pwrdm_lost_power(struct powerdomain *pwrdm, void *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) int state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) * Power has been lost across all powerdomains, increment the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) * counter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) state = pwrdm_read_pwrst(pwrdm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) if (state != PWRDM_POWER_OFF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) pwrdm->state_counter[state]++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) pwrdm->state_counter[PWRDM_POWER_OFF]++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) pwrdm->state = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) void pwrdms_save_context(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) pwrdm_for_each(pwrdm_save_context, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) void pwrdms_restore_context(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) pwrdm_for_each(pwrdm_restore_context, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) void pwrdms_lost_power(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) pwrdm_for_each(pwrdm_lost_power, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) }