// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Copyright 2012 Linaro Ltd.3*/45#include <linux/cpuidle.h>6#include <linux/of.h>7#include <asm/cpuidle.h>89extern struct of_cpuidle_method __cpuidle_method_of_table[];1011static const struct of_cpuidle_method __cpuidle_method_of_table_sentinel12__used __section("__cpuidle_method_of_table_end");1314static struct cpuidle_ops cpuidle_ops[NR_CPUS] __ro_after_init;1516/**17* arm_cpuidle_simple_enter() - a wrapper to cpu_do_idle()18* @dev: not used19* @drv: not used20* @index: not used21*22* A trivial wrapper to allow the cpu_do_idle function to be assigned as a23* cpuidle callback by matching the function signature.24*25* Returns the index passed as parameter26*/27__cpuidle int arm_cpuidle_simple_enter(struct cpuidle_device *dev, struct28cpuidle_driver *drv, int index)29{30cpu_do_idle();3132return index;33}3435/**36* arm_cpuidle_suspend() - function to enter low power idle states37* @index: an integer used as an identifier for the low level PM callbacks38*39* This function calls the underlying arch specific low level PM code as40* registered at the init time.41*42* Returns the result of the suspend callback.43*/44int arm_cpuidle_suspend(int index)45{46int cpu = smp_processor_id();4748return cpuidle_ops[cpu].suspend(index);49}5051/**52* arm_cpuidle_get_ops() - find a registered cpuidle_ops by name53* @method: the method name54*55* Search in the __cpuidle_method_of_table array the cpuidle ops matching the56* method name.57*58* Returns a struct cpuidle_ops pointer, NULL if not found.59*/60static const struct cpuidle_ops *__init arm_cpuidle_get_ops(const char *method)61{62struct of_cpuidle_method *m = __cpuidle_method_of_table;6364for (; m->method; m++)65if (!strcmp(m->method, method))66return m->ops;6768return NULL;69}7071/**72* arm_cpuidle_read_ops() - Initialize the cpuidle ops with the device tree73* @dn: a pointer to a struct device node corresponding to a cpu node74* @cpu: the cpu identifier75*76* Get the method name defined in the 'enable-method' property, retrieve the77* associated cpuidle_ops and do a struct copy. This copy is needed because all78* cpuidle_ops are tagged __initconst and will be unloaded after the init79* process.80*81* Return 0 on sucess, -ENOENT if no 'enable-method' is defined, -EOPNOTSUPP if82* no cpuidle_ops is registered for the 'enable-method', or if either init or83* suspend callback isn't defined.84*/85static int __init arm_cpuidle_read_ops(struct device_node *dn, int cpu)86{87const char *enable_method;88const struct cpuidle_ops *ops;8990enable_method = of_get_property(dn, "enable-method", NULL);91if (!enable_method)92return -ENOENT;9394ops = arm_cpuidle_get_ops(enable_method);95if (!ops) {96pr_warn("%pOF: unsupported enable-method property: %s\n",97dn, enable_method);98return -EOPNOTSUPP;99}100101if (!ops->init || !ops->suspend) {102pr_warn("cpuidle_ops '%s': no init or suspend callback\n",103enable_method);104return -EOPNOTSUPP;105}106107cpuidle_ops[cpu] = *ops; /* structure copy */108109pr_notice("cpuidle: enable-method property '%s'"110" found operations\n", enable_method);111112return 0;113}114115/**116* arm_cpuidle_init() - Initialize cpuidle_ops for a specific cpu117* @cpu: the cpu to be initialized118*119* Initialize the cpuidle ops with the device for the cpu and then call120* the cpu's idle initialization callback. This may fail if the underlying HW121* is not operational.122*123* Returns:124* 0 on success,125* -ENODEV if it fails to find the cpu node in the device tree,126* -EOPNOTSUPP if it does not find a registered and valid cpuidle_ops for127* this cpu,128* -ENOENT if it fails to find an 'enable-method' property,129* -ENXIO if the HW reports a failure or a misconfiguration,130* -ENOMEM if the HW report an memory allocation failure131*/132int __init arm_cpuidle_init(int cpu)133{134struct device_node *cpu_node = of_cpu_device_node_get(cpu);135int ret;136137if (!cpu_node)138return -ENODEV;139140ret = arm_cpuidle_read_ops(cpu_node, cpu);141if (!ret)142ret = cpuidle_ops[cpu].init(cpu_node, cpu);143144of_node_put(cpu_node);145146return ret;147}148149150