GNU Linux-libre 5.4.200-gnu1
[releases.git] / drivers / soc / qcom / rpmhpd.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2018, The Linux Foundation. All rights reserved.*/
3
4 #include <linux/err.h>
5 #include <linux/init.h>
6 #include <linux/kernel.h>
7 #include <linux/mutex.h>
8 #include <linux/pm_domain.h>
9 #include <linux/slab.h>
10 #include <linux/of.h>
11 #include <linux/of_device.h>
12 #include <linux/platform_device.h>
13 #include <linux/pm_opp.h>
14 #include <soc/qcom/cmd-db.h>
15 #include <soc/qcom/rpmh.h>
16 #include <dt-bindings/power/qcom-rpmpd.h>
17
18 #define domain_to_rpmhpd(domain) container_of(domain, struct rpmhpd, pd)
19
20 #define RPMH_ARC_MAX_LEVELS     16
21
22 /**
23  * struct rpmhpd - top level RPMh power domain resource data structure
24  * @dev:                rpmh power domain controller device
25  * @pd:                 generic_pm_domain corrresponding to the power domain
26  * @peer:               A peer power domain in case Active only Voting is
27  *                      supported
28  * @active_only:        True if it represents an Active only peer
29  * @level:              An array of level (vlvl) to corner (hlvl) mappings
30  *                      derived from cmd-db
31  * @level_count:        Number of levels supported by the power domain. max
32  *                      being 16 (0 - 15)
33  * @enabled:            true if the power domain is enabled
34  * @res_name:           Resource name used for cmd-db lookup
35  * @addr:               Resource address as looped up using resource name from
36  *                      cmd-db
37  */
38 struct rpmhpd {
39         struct device   *dev;
40         struct generic_pm_domain pd;
41         struct generic_pm_domain *parent;
42         struct rpmhpd   *peer;
43         const bool      active_only;
44         unsigned int    corner;
45         unsigned int    active_corner;
46         u32             level[RPMH_ARC_MAX_LEVELS];
47         size_t          level_count;
48         bool            enabled;
49         const char      *res_name;
50         u32             addr;
51 };
52
53 struct rpmhpd_desc {
54         struct rpmhpd **rpmhpds;
55         size_t num_pds;
56 };
57
58 static DEFINE_MUTEX(rpmhpd_lock);
59
60 /* SDM845 RPMH powerdomains */
61
62 static struct rpmhpd sdm845_ebi = {
63         .pd = { .name = "ebi", },
64         .res_name = "ebi.lvl",
65 };
66
67 static struct rpmhpd sdm845_lmx = {
68         .pd = { .name = "lmx", },
69         .res_name = "lmx.lvl",
70 };
71
72 static struct rpmhpd sdm845_lcx = {
73         .pd = { .name = "lcx", },
74         .res_name = "lcx.lvl",
75 };
76
77 static struct rpmhpd sdm845_gfx = {
78         .pd = { .name = "gfx", },
79         .res_name = "gfx.lvl",
80 };
81
82 static struct rpmhpd sdm845_mss = {
83         .pd = { .name = "mss", },
84         .res_name = "mss.lvl",
85 };
86
87 static struct rpmhpd sdm845_mx_ao;
88 static struct rpmhpd sdm845_mx = {
89         .pd = { .name = "mx", },
90         .peer = &sdm845_mx_ao,
91         .res_name = "mx.lvl",
92 };
93
94 static struct rpmhpd sdm845_mx_ao = {
95         .pd = { .name = "mx_ao", },
96         .active_only = true,
97         .peer = &sdm845_mx,
98         .res_name = "mx.lvl",
99 };
100
101 static struct rpmhpd sdm845_cx_ao;
102 static struct rpmhpd sdm845_cx = {
103         .pd = { .name = "cx", },
104         .peer = &sdm845_cx_ao,
105         .parent = &sdm845_mx.pd,
106         .res_name = "cx.lvl",
107 };
108
109 static struct rpmhpd sdm845_cx_ao = {
110         .pd = { .name = "cx_ao", },
111         .active_only = true,
112         .peer = &sdm845_cx,
113         .parent = &sdm845_mx_ao.pd,
114         .res_name = "cx.lvl",
115 };
116
117 static struct rpmhpd *sdm845_rpmhpds[] = {
118         [SDM845_EBI] = &sdm845_ebi,
119         [SDM845_MX] = &sdm845_mx,
120         [SDM845_MX_AO] = &sdm845_mx_ao,
121         [SDM845_CX] = &sdm845_cx,
122         [SDM845_CX_AO] = &sdm845_cx_ao,
123         [SDM845_LMX] = &sdm845_lmx,
124         [SDM845_LCX] = &sdm845_lcx,
125         [SDM845_GFX] = &sdm845_gfx,
126         [SDM845_MSS] = &sdm845_mss,
127 };
128
129 static const struct rpmhpd_desc sdm845_desc = {
130         .rpmhpds = sdm845_rpmhpds,
131         .num_pds = ARRAY_SIZE(sdm845_rpmhpds),
132 };
133
134 static const struct of_device_id rpmhpd_match_table[] = {
135         { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
136         { }
137 };
138
139 static int rpmhpd_send_corner(struct rpmhpd *pd, int state,
140                               unsigned int corner, bool sync)
141 {
142         struct tcs_cmd cmd = {
143                 .addr = pd->addr,
144                 .data = corner,
145         };
146
147         /*
148          * Wait for an ack only when we are increasing the
149          * perf state of the power domain
150          */
151         if (sync)
152                 return rpmh_write(pd->dev, state, &cmd, 1);
153         else
154                 return rpmh_write_async(pd->dev, state, &cmd, 1);
155 }
156
157 static void to_active_sleep(struct rpmhpd *pd, unsigned int corner,
158                             unsigned int *active, unsigned int *sleep)
159 {
160         *active = corner;
161
162         if (pd->active_only)
163                 *sleep = 0;
164         else
165                 *sleep = *active;
166 }
167
168 /*
169  * This function is used to aggregate the votes across the active only
170  * resources and its peers. The aggregated votes are sent to RPMh as
171  * ACTIVE_ONLY votes (which take effect immediately), as WAKE_ONLY votes
172  * (applied by RPMh on system wakeup) and as SLEEP votes (applied by RPMh
173  * on system sleep).
174  * We send ACTIVE_ONLY votes for resources without any peers. For others,
175  * which have an active only peer, all 3 votes are sent.
176  */
177 static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)
178 {
179         int ret;
180         struct rpmhpd *peer = pd->peer;
181         unsigned int active_corner, sleep_corner;
182         unsigned int this_active_corner = 0, this_sleep_corner = 0;
183         unsigned int peer_active_corner = 0, peer_sleep_corner = 0;
184
185         to_active_sleep(pd, corner, &this_active_corner, &this_sleep_corner);
186
187         if (peer && peer->enabled)
188                 to_active_sleep(peer, peer->corner, &peer_active_corner,
189                                 &peer_sleep_corner);
190
191         active_corner = max(this_active_corner, peer_active_corner);
192
193         ret = rpmhpd_send_corner(pd, RPMH_ACTIVE_ONLY_STATE, active_corner,
194                                  active_corner > pd->active_corner);
195         if (ret)
196                 return ret;
197
198         pd->active_corner = active_corner;
199
200         if (peer) {
201                 peer->active_corner = active_corner;
202
203                 ret = rpmhpd_send_corner(pd, RPMH_WAKE_ONLY_STATE,
204                                          active_corner, false);
205                 if (ret)
206                         return ret;
207
208                 sleep_corner = max(this_sleep_corner, peer_sleep_corner);
209
210                 return rpmhpd_send_corner(pd, RPMH_SLEEP_STATE, sleep_corner,
211                                           false);
212         }
213
214         return ret;
215 }
216
217 static int rpmhpd_power_on(struct generic_pm_domain *domain)
218 {
219         struct rpmhpd *pd = domain_to_rpmhpd(domain);
220         int ret = 0;
221
222         mutex_lock(&rpmhpd_lock);
223
224         if (pd->corner)
225                 ret = rpmhpd_aggregate_corner(pd, pd->corner);
226
227         if (!ret)
228                 pd->enabled = true;
229
230         mutex_unlock(&rpmhpd_lock);
231
232         return ret;
233 }
234
235 static int rpmhpd_power_off(struct generic_pm_domain *domain)
236 {
237         struct rpmhpd *pd = domain_to_rpmhpd(domain);
238         int ret;
239
240         mutex_lock(&rpmhpd_lock);
241
242         ret = rpmhpd_aggregate_corner(pd, 0);
243         if (!ret)
244                 pd->enabled = false;
245
246         mutex_unlock(&rpmhpd_lock);
247
248         return ret;
249 }
250
251 static int rpmhpd_set_performance_state(struct generic_pm_domain *domain,
252                                         unsigned int level)
253 {
254         struct rpmhpd *pd = domain_to_rpmhpd(domain);
255         int ret = 0, i;
256
257         mutex_lock(&rpmhpd_lock);
258
259         for (i = 0; i < pd->level_count; i++)
260                 if (level <= pd->level[i])
261                         break;
262
263         /*
264          * If the level requested is more than that supported by the
265          * max corner, just set it to max anyway.
266          */
267         if (i == pd->level_count)
268                 i--;
269
270         if (pd->enabled) {
271                 ret = rpmhpd_aggregate_corner(pd, i);
272                 if (ret)
273                         goto out;
274         }
275
276         pd->corner = i;
277 out:
278         mutex_unlock(&rpmhpd_lock);
279
280         return ret;
281 }
282
283 static unsigned int rpmhpd_get_performance_state(struct generic_pm_domain *genpd,
284                                                  struct dev_pm_opp *opp)
285 {
286         return dev_pm_opp_get_level(opp);
287 }
288
289 static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
290 {
291         int i;
292         const u16 *buf;
293
294         buf = cmd_db_read_aux_data(rpmhpd->res_name, &rpmhpd->level_count);
295         if (IS_ERR(buf))
296                 return PTR_ERR(buf);
297
298         /* 2 bytes used for each command DB aux data entry */
299         rpmhpd->level_count >>= 1;
300
301         if (rpmhpd->level_count > RPMH_ARC_MAX_LEVELS)
302                 return -EINVAL;
303
304         for (i = 0; i < rpmhpd->level_count; i++) {
305                 rpmhpd->level[i] = buf[i];
306
307                 /*
308                  * The AUX data may be zero padded.  These 0 valued entries at
309                  * the end of the map must be ignored.
310                  */
311                 if (i > 0 && rpmhpd->level[i] == 0) {
312                         rpmhpd->level_count = i;
313                         break;
314                 }
315                 pr_debug("%s: ARC hlvl=%2d --> vlvl=%4u\n", rpmhpd->res_name, i,
316                          rpmhpd->level[i]);
317         }
318
319         return 0;
320 }
321
322 static int rpmhpd_probe(struct platform_device *pdev)
323 {
324         int i, ret;
325         size_t num_pds;
326         struct device *dev = &pdev->dev;
327         struct genpd_onecell_data *data;
328         struct rpmhpd **rpmhpds;
329         const struct rpmhpd_desc *desc;
330
331         desc = of_device_get_match_data(dev);
332         if (!desc)
333                 return -EINVAL;
334
335         rpmhpds = desc->rpmhpds;
336         num_pds = desc->num_pds;
337
338         data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
339         if (!data)
340                 return -ENOMEM;
341
342         data->domains = devm_kcalloc(dev, num_pds, sizeof(*data->domains),
343                                      GFP_KERNEL);
344         if (!data->domains)
345                 return -ENOMEM;
346
347         data->num_domains = num_pds;
348
349         for (i = 0; i < num_pds; i++) {
350                 if (!rpmhpds[i]) {
351                         dev_warn(dev, "rpmhpds[%d] is empty\n", i);
352                         continue;
353                 }
354
355                 rpmhpds[i]->dev = dev;
356                 rpmhpds[i]->addr = cmd_db_read_addr(rpmhpds[i]->res_name);
357                 if (!rpmhpds[i]->addr) {
358                         dev_err(dev, "Could not find RPMh address for resource %s\n",
359                                 rpmhpds[i]->res_name);
360                         return -ENODEV;
361                 }
362
363                 ret = cmd_db_read_slave_id(rpmhpds[i]->res_name);
364                 if (ret != CMD_DB_HW_ARC) {
365                         dev_err(dev, "RPMh slave ID mismatch\n");
366                         return -EINVAL;
367                 }
368
369                 ret = rpmhpd_update_level_mapping(rpmhpds[i]);
370                 if (ret)
371                         return ret;
372
373                 rpmhpds[i]->pd.power_off = rpmhpd_power_off;
374                 rpmhpds[i]->pd.power_on = rpmhpd_power_on;
375                 rpmhpds[i]->pd.set_performance_state = rpmhpd_set_performance_state;
376                 rpmhpds[i]->pd.opp_to_performance_state = rpmhpd_get_performance_state;
377                 pm_genpd_init(&rpmhpds[i]->pd, NULL, true);
378
379                 data->domains[i] = &rpmhpds[i]->pd;
380         }
381
382         /* Add subdomains */
383         for (i = 0; i < num_pds; i++) {
384                 if (!rpmhpds[i])
385                         continue;
386                 if (rpmhpds[i]->parent)
387                         pm_genpd_add_subdomain(rpmhpds[i]->parent,
388                                                &rpmhpds[i]->pd);
389         }
390
391         return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
392 }
393
394 static struct platform_driver rpmhpd_driver = {
395         .driver = {
396                 .name = "qcom-rpmhpd",
397                 .of_match_table = rpmhpd_match_table,
398                 .suppress_bind_attrs = true,
399         },
400         .probe = rpmhpd_probe,
401 };
402
403 static int __init rpmhpd_init(void)
404 {
405         return platform_driver_register(&rpmhpd_driver);
406 }
407 core_initcall(rpmhpd_init);