0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) "DT idle-states: " fmt
0010
0011 #include <linux/cpuidle.h>
0012 #include <linux/cpumask.h>
0013 #include <linux/errno.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/of.h>
0017 #include <linux/of_device.h>
0018
0019 #include "dt_idle_states.h"
0020
0021 static int init_state_node(struct cpuidle_state *idle_state,
0022 const struct of_device_id *match_id,
0023 struct device_node *state_node)
0024 {
0025 int err;
0026 const char *desc;
0027
0028
0029
0030
0031
0032
0033 idle_state->enter = match_id->data;
0034
0035
0036
0037
0038
0039 idle_state->enter_s2idle = match_id->data;
0040
0041 err = of_property_read_u32(state_node, "wakeup-latency-us",
0042 &idle_state->exit_latency);
0043 if (err) {
0044 u32 entry_latency, exit_latency;
0045
0046 err = of_property_read_u32(state_node, "entry-latency-us",
0047 &entry_latency);
0048 if (err) {
0049 pr_debug(" * %pOF missing entry-latency-us property\n",
0050 state_node);
0051 return -EINVAL;
0052 }
0053
0054 err = of_property_read_u32(state_node, "exit-latency-us",
0055 &exit_latency);
0056 if (err) {
0057 pr_debug(" * %pOF missing exit-latency-us property\n",
0058 state_node);
0059 return -EINVAL;
0060 }
0061
0062
0063
0064
0065 idle_state->exit_latency = entry_latency + exit_latency;
0066 }
0067
0068 err = of_property_read_u32(state_node, "min-residency-us",
0069 &idle_state->target_residency);
0070 if (err) {
0071 pr_debug(" * %pOF missing min-residency-us property\n",
0072 state_node);
0073 return -EINVAL;
0074 }
0075
0076 err = of_property_read_string(state_node, "idle-state-name", &desc);
0077 if (err)
0078 desc = state_node->name;
0079
0080 idle_state->flags = 0;
0081 if (of_property_read_bool(state_node, "local-timer-stop"))
0082 idle_state->flags |= CPUIDLE_FLAG_TIMER_STOP;
0083
0084
0085
0086
0087
0088 strncpy(idle_state->name, state_node->name, CPUIDLE_NAME_LEN - 1);
0089 strncpy(idle_state->desc, desc, CPUIDLE_DESC_LEN - 1);
0090 return 0;
0091 }
0092
0093
0094
0095
0096
0097 static bool idle_state_valid(struct device_node *state_node, unsigned int idx,
0098 const cpumask_t *cpumask)
0099 {
0100 int cpu;
0101 struct device_node *cpu_node, *curr_state_node;
0102 bool valid = true;
0103
0104
0105
0106
0107
0108
0109
0110
0111 for (cpu = cpumask_next(cpumask_first(cpumask), cpumask);
0112 cpu < nr_cpu_ids; cpu = cpumask_next(cpu, cpumask)) {
0113 cpu_node = of_cpu_device_node_get(cpu);
0114 curr_state_node = of_get_cpu_state_node(cpu_node, idx);
0115 if (state_node != curr_state_node)
0116 valid = false;
0117
0118 of_node_put(curr_state_node);
0119 of_node_put(cpu_node);
0120 if (!valid)
0121 break;
0122 }
0123
0124 return valid;
0125 }
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149 int dt_init_idle_driver(struct cpuidle_driver *drv,
0150 const struct of_device_id *matches,
0151 unsigned int start_idx)
0152 {
0153 struct cpuidle_state *idle_state;
0154 struct device_node *state_node, *cpu_node;
0155 const struct of_device_id *match_id;
0156 int i, err = 0;
0157 const cpumask_t *cpumask;
0158 unsigned int state_idx = start_idx;
0159
0160 if (state_idx >= CPUIDLE_STATE_MAX)
0161 return -EINVAL;
0162
0163
0164
0165
0166
0167
0168 cpumask = drv->cpumask ? : cpu_possible_mask;
0169 cpu_node = of_cpu_device_node_get(cpumask_first(cpumask));
0170
0171 for (i = 0; ; i++) {
0172 state_node = of_get_cpu_state_node(cpu_node, i);
0173 if (!state_node)
0174 break;
0175
0176 match_id = of_match_node(matches, state_node);
0177 if (!match_id) {
0178 err = -ENODEV;
0179 break;
0180 }
0181
0182 if (!of_device_is_available(state_node)) {
0183 of_node_put(state_node);
0184 continue;
0185 }
0186
0187 if (!idle_state_valid(state_node, i, cpumask)) {
0188 pr_warn("%pOF idle state not valid, bailing out\n",
0189 state_node);
0190 err = -EINVAL;
0191 break;
0192 }
0193
0194 if (state_idx == CPUIDLE_STATE_MAX) {
0195 pr_warn("State index reached static CPU idle driver states array size\n");
0196 break;
0197 }
0198
0199 idle_state = &drv->states[state_idx++];
0200 err = init_state_node(idle_state, match_id, state_node);
0201 if (err) {
0202 pr_err("Parsing idle state node %pOF failed with err %d\n",
0203 state_node, err);
0204 err = -EINVAL;
0205 break;
0206 }
0207 of_node_put(state_node);
0208 }
0209
0210 of_node_put(state_node);
0211 of_node_put(cpu_node);
0212 if (err)
0213 return err;
0214
0215
0216
0217
0218 if (i)
0219 drv->state_count = state_idx;
0220
0221
0222
0223
0224
0225
0226 return i;
0227 }
0228 EXPORT_SYMBOL_GPL(dt_init_idle_driver);