blob: 91276761a31d94581abece9e0095febff4d166ea [file] [log] [blame]
Daniel Lezcanoe4465562022-01-28 17:35:36 +01001// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright 2021 Linaro Limited
4 *
5 * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
6 *
7 * The devfreq device combined with the energy model and the load can
8 * give an estimation of the power consumption as well as limiting the
9 * power.
10 *
11 */
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14#include <linux/cpumask.h>
15#include <linux/devfreq.h>
16#include <linux/dtpm.h>
17#include <linux/energy_model.h>
18#include <linux/of.h>
19#include <linux/pm_qos.h>
20#include <linux/slab.h>
21#include <linux/units.h>
22
23struct dtpm_devfreq {
24 struct dtpm dtpm;
25 struct dev_pm_qos_request qos_req;
26 struct devfreq *devfreq;
27};
28
29static struct dtpm_devfreq *to_dtpm_devfreq(struct dtpm *dtpm)
30{
31 return container_of(dtpm, struct dtpm_devfreq, dtpm);
32}
33
34static int update_pd_power_uw(struct dtpm *dtpm)
35{
36 struct dtpm_devfreq *dtpm_devfreq = to_dtpm_devfreq(dtpm);
37 struct devfreq *devfreq = dtpm_devfreq->devfreq;
38 struct device *dev = devfreq->dev.parent;
39 struct em_perf_domain *pd = em_pd_get(dev);
40
41 dtpm->power_min = pd->table[0].power;
42 dtpm->power_min *= MICROWATT_PER_MILLIWATT;
43
44 dtpm->power_max = pd->table[pd->nr_perf_states - 1].power;
45 dtpm->power_max *= MICROWATT_PER_MILLIWATT;
46
47 return 0;
48}
49
50static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit)
51{
52 struct dtpm_devfreq *dtpm_devfreq = to_dtpm_devfreq(dtpm);
53 struct devfreq *devfreq = dtpm_devfreq->devfreq;
54 struct device *dev = devfreq->dev.parent;
55 struct em_perf_domain *pd = em_pd_get(dev);
56 unsigned long freq;
57 u64 power;
58 int i;
59
60 for (i = 0; i < pd->nr_perf_states; i++) {
61
62 power = pd->table[i].power * MICROWATT_PER_MILLIWATT;
63 if (power > power_limit)
64 break;
65 }
66
67 freq = pd->table[i - 1].frequency;
68
69 dev_pm_qos_update_request(&dtpm_devfreq->qos_req, freq);
70
71 power_limit = pd->table[i - 1].power * MICROWATT_PER_MILLIWATT;
72
73 return power_limit;
74}
75
76static void _normalize_load(struct devfreq_dev_status *status)
77{
78 if (status->total_time > 0xfffff) {
79 status->total_time >>= 10;
80 status->busy_time >>= 10;
81 }
82
83 status->busy_time <<= 10;
84 status->busy_time /= status->total_time ? : 1;
85
86 status->busy_time = status->busy_time ? : 1;
87 status->total_time = 1024;
88}
89
90static u64 get_pd_power_uw(struct dtpm *dtpm)
91{
92 struct dtpm_devfreq *dtpm_devfreq = to_dtpm_devfreq(dtpm);
93 struct devfreq *devfreq = dtpm_devfreq->devfreq;
94 struct device *dev = devfreq->dev.parent;
95 struct em_perf_domain *pd = em_pd_get(dev);
96 struct devfreq_dev_status status;
97 unsigned long freq;
98 u64 power;
99 int i;
100
101 mutex_lock(&devfreq->lock);
102 status = devfreq->last_status;
103 mutex_unlock(&devfreq->lock);
104
105 freq = DIV_ROUND_UP(status.current_frequency, HZ_PER_KHZ);
106 _normalize_load(&status);
107
108 for (i = 0; i < pd->nr_perf_states; i++) {
109
110 if (pd->table[i].frequency < freq)
111 continue;
112
113 power = pd->table[i].power * MICROWATT_PER_MILLIWATT;
114 power *= status.busy_time;
115 power >>= 10;
116
117 return power;
118 }
119
120 return 0;
121}
122
123static void pd_release(struct dtpm *dtpm)
124{
125 struct dtpm_devfreq *dtpm_devfreq = to_dtpm_devfreq(dtpm);
126
127 if (dev_pm_qos_request_active(&dtpm_devfreq->qos_req))
128 dev_pm_qos_remove_request(&dtpm_devfreq->qos_req);
129
130 kfree(dtpm_devfreq);
131}
132
133static struct dtpm_ops dtpm_ops = {
134 .set_power_uw = set_pd_power_limit,
135 .get_power_uw = get_pd_power_uw,
136 .update_power_uw = update_pd_power_uw,
137 .release = pd_release,
138};
139
140static int __dtpm_devfreq_setup(struct devfreq *devfreq, struct dtpm *parent)
141{
142 struct device *dev = devfreq->dev.parent;
143 struct dtpm_devfreq *dtpm_devfreq;
144 struct em_perf_domain *pd;
145 int ret = -ENOMEM;
146
147 pd = em_pd_get(dev);
148 if (!pd) {
149 ret = dev_pm_opp_of_register_em(dev, NULL);
150 if (ret) {
151 pr_err("No energy model available for '%s'\n", dev_name(dev));
152 return -EINVAL;
153 }
154 }
155
156 dtpm_devfreq = kzalloc(sizeof(*dtpm_devfreq), GFP_KERNEL);
157 if (!dtpm_devfreq)
158 return -ENOMEM;
159
160 dtpm_init(&dtpm_devfreq->dtpm, &dtpm_ops);
161
162 dtpm_devfreq->devfreq = devfreq;
163
164 ret = dtpm_register(dev_name(dev), &dtpm_devfreq->dtpm, parent);
165 if (ret) {
166 pr_err("Failed to register '%s': %d\n", dev_name(dev), ret);
167 kfree(dtpm_devfreq);
168 return ret;
169 }
170
171 ret = dev_pm_qos_add_request(dev, &dtpm_devfreq->qos_req,
172 DEV_PM_QOS_MAX_FREQUENCY,
173 PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
174 if (ret) {
175 pr_err("Failed to add QoS request: %d\n", ret);
176 goto out_dtpm_unregister;
177 }
178
179 dtpm_update_power(&dtpm_devfreq->dtpm);
180
181 return 0;
182
183out_dtpm_unregister:
184 dtpm_unregister(&dtpm_devfreq->dtpm);
185
186 return ret;
187}
188
189static int dtpm_devfreq_setup(struct dtpm *dtpm, struct device_node *np)
190{
191 struct devfreq *devfreq;
192
193 devfreq = devfreq_get_devfreq_by_node(np);
194 if (IS_ERR(devfreq))
195 return 0;
196
197 return __dtpm_devfreq_setup(devfreq, dtpm);
198}
199
200struct dtpm_subsys_ops dtpm_devfreq_ops = {
201 .name = KBUILD_MODNAME,
202 .setup = dtpm_devfreq_setup,
203};