Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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) }