blob: fc6b5ffa790fc2cf5a3791ac5c2c6e4a525dae87 [file] [log] [blame]
developer2cdaeb12022-10-04 20:25:05 +08001// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2020 Collabora Ltd.
4 */
5#include <linux/clk.h>
6#include <linux/clk-provider.h>
7#include <linux/init.h>
8#include <linux/io.h>
9#include <linux/iopoll.h>
10#include <linux/mfd/syscon.h>
11#include <linux/of_clk.h>
12#include <linux/of_device.h>
13#include <linux/platform_device.h>
14#include <linux/pm_domain.h>
15#include <linux/regmap.h>
16#include <linux/soc/mediatek/infracfg.h>
17#include <linux/regulator/consumer.h>
18
19#include "mt7988-pm-domains.h"
20
21#define MTK_POLL_DELAY_US 30
22#define MTK_POLL_TIMEOUT USEC_PER_SEC
23
24struct scpsys_domain {
25 struct generic_pm_domain genpd;
26 const struct scpsys_domain_data *data;
27 struct scpsys *scpsys;
28 int num_clks;
29 struct clk_bulk_data *clks;
30 int num_subsys_clks;
31 struct clk_bulk_data *subsys_clks;
32 struct regmap *infracfg;
33 struct regulator *supply;
34};
35
36struct scpsys {
37 struct device *dev;
38 struct regmap *base;
39 const struct scpsys_soc_data *soc_data;
40 struct genpd_onecell_data pd_data;
41 struct generic_pm_domain *domains[];
42};
43
44static inline int mtk_regmap_set_bits(struct regmap *map, unsigned int reg,
45 unsigned int bits)
46{
47 return regmap_update_bits_base(map, reg, bits, bits, NULL, false,
48 false);
49}
50
51static inline int mtk_regmap_clear_bits(struct regmap *map, unsigned int reg,
52 unsigned int bits)
53{
54 return regmap_update_bits_base(map, reg, bits, 0, NULL, false, false);
55}
56
57#define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd)
58
59static bool scpsys_domain_is_on(struct scpsys_domain *pd)
60{
61 struct scpsys *scpsys = pd->scpsys;
62 u32 status = 0, status2 = 0;
63
64 regmap_read(scpsys->base, pd->data->pwr_sta_offs, &status);
65 status &= pd->data->sta_mask;
66
67 regmap_read(scpsys->base, pd->data->pwr_sta_2nd_offs, &status2);
68 status2 &= pd->data->sta_2nd_mask;
69
70 /* A domain is on when both status bits are set. */
71 return status && status2;
72}
73
74static int scpsys_sram_enable(struct scpsys_domain *pd)
75{
76 u32 pdn_ack = pd->data->sram_pdn_ack_bit;
77 u32 pdn_2nd_ack = pd->data->sram_2nd_pdn_ack_bit;
78 struct scpsys *scpsys = pd->scpsys;
79 unsigned int tmp = 0;
80 int ret;
81
82 if (pd->data->sram_pdn_bit) {
83 mtk_regmap_clear_bits(scpsys->base, pd->data->sram_ctrl_offs,
84 pd->data->sram_pdn_bit);
85
86 /* Either wait until SRAM_PDN_ACK all 1 or 0 */
87 ret = regmap_read_poll_timeout(scpsys->base,
88 pd->data->sram_ctrl_offs, tmp,
89 (tmp & pdn_ack) == 0,
90 MTK_POLL_DELAY_US,
91 MTK_POLL_TIMEOUT);
92 if (ret < 0)
93 return ret;
94 }
95 if (pd->data->sram_2nd_pdn_bit) {
96 /* sram pdn 2nd for special mtcmos */
97 mtk_regmap_clear_bits(scpsys->base,
98 pd->data->sram_2nd_ctrl_offs,
99 pd->data->sram_2nd_pdn_bit);
100
101 ret = regmap_read_poll_timeout(scpsys->base,
102 pd->data->sram_2nd_ctrl_offs,
103 tmp, (tmp & pdn_2nd_ack) == 0,
104 MTK_POLL_DELAY_US,
105 MTK_POLL_TIMEOUT);
106 if (ret < 0)
107 return ret;
108 }
109 if (pd->data->sram_clk_iso_bit) {
110 mtk_regmap_clear_bits(scpsys->base, pd->data->sram_ctrl_offs,
111 pd->data->sram_clk_iso_bit);
112 }
113 if (pd->data->sram_clk_dis_bit) {
114 mtk_regmap_clear_bits(scpsys->base, pd->data->sram_ctrl_offs,
115 pd->data->sram_clk_dis_bit);
116 }
117 if (pd->data->sram_2nd_clk_iso_bit) {
118 mtk_regmap_clear_bits(scpsys->base,
119 pd->data->sram_2nd_ctrl_offs,
120 pd->data->sram_2nd_clk_iso_bit);
121 }
122 if (pd->data->sram_2nd_clk_dis_bit) {
123 mtk_regmap_clear_bits(scpsys->base,
124 pd->data->sram_2nd_ctrl_offs,
125 pd->data->sram_2nd_clk_dis_bit);
126 }
127
128 return 0;
129}
130
131static int scpsys_sram_disable(struct scpsys_domain *pd)
132{
133 u32 pdn_ack = pd->data->sram_pdn_ack_bit;
134 u32 pdn_2nd_ack = pd->data->sram_2nd_pdn_ack_bit;
135 struct scpsys *scpsys = pd->scpsys;
136 unsigned int tmp = 0;
137 int ret;
138
139 if (pd->data->sram_2nd_clk_dis_bit) {
140 mtk_regmap_set_bits(scpsys->base, pd->data->sram_2nd_ctrl_offs,
141 pd->data->sram_2nd_clk_dis_bit);
142 }
143 if (pd->data->sram_clk_iso_bit) {
144 mtk_regmap_set_bits(scpsys->base, pd->data->sram_ctrl_offs,
145 pd->data->sram_clk_iso_bit);
146 udelay(1);
147 }
148 if (pd->data->sram_pdn_bit) {
149 mtk_regmap_set_bits(scpsys->base, pd->data->sram_ctrl_offs,
150 pd->data->sram_pdn_bit);
151 }
152
153 if (pd->data->sram_2nd_clk_iso_bit) {
154 mtk_regmap_set_bits(scpsys->base, pd->data->sram_2nd_ctrl_offs,
155 pd->data->sram_2nd_clk_iso_bit);
156 udelay(1);
157 }
158 if (pd->data->sram_2nd_pdn_bit) {
159 mtk_regmap_set_bits(scpsys->base, pd->data->sram_2nd_ctrl_offs,
160 pd->data->sram_2nd_pdn_bit);
161 }
162
163 return 0;
164}
165
166static int scpsys_regulator_get(struct generic_pm_domain *genpd)
167{
168 struct scpsys_domain *pd =
169 container_of(genpd, struct scpsys_domain, genpd);
170 struct device_node *node;
171 struct device_node *root;
172
173 if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY) && !pd->supply) {
174 root = pd->scpsys->dev->of_node;
175 node = of_find_node_by_name(root, genpd->name);
176 if (node) {
177 pd->scpsys->dev->of_node = node;
178 pd->supply =
179 devm_regulator_get(pd->scpsys->dev, "domain");
180 pd->scpsys->dev->of_node = root;
181 if (IS_ERR(pd->supply))
182 return -EINVAL;
183 }
184 }
185
186 return 0;
187}
188
189static int scpsys_regulator_enable(struct generic_pm_domain *genpd)
190{
191 struct scpsys_domain *pd =
192 container_of(genpd, struct scpsys_domain, genpd);
193 int ret = scpsys_regulator_get(genpd);
194
195 if (ret)
196 return ret;
197
198 return pd->supply ? regulator_enable(pd->supply) : 0;
199}
200
201static int scpsys_regulator_disable(struct generic_pm_domain *genpd)
202{
203 struct scpsys_domain *pd =
204 container_of(genpd, struct scpsys_domain, genpd);
205
206 return pd->supply ? regulator_disable(pd->supply) : 0;
207}
208
209static int scpsys_power_on(struct generic_pm_domain *genpd)
210{
211 struct scpsys_domain *pd =
212 container_of(genpd, struct scpsys_domain, genpd);
213 struct scpsys *scpsys = pd->scpsys;
214 bool tmp;
215 int ret;
216
217 ret = scpsys_regulator_enable(genpd);
218 if (ret)
219 return ret;
220
221 ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks);
222 if (ret)
223 goto err_pwr_ack;
224
225 /* subsys power on */
226 mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_offs,
227 pd->data->pwr_on_bit);
228 mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_2nd_offs,
229 pd->data->pwr_on_2nd_bit);
230
231 /* wait until PWR_ACK = 1 */
232 ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp,
233 MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
234 if (ret < 0)
235 goto err_pwr_ack;
236 udelay(30);
237
238 if (pd->data->pwr_clamp_bit) {
239 mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_offs,
240 pd->data->pwr_clamp_bit);
241 udelay(30);
242 }
243
244 if (pd->data->pwr_rst_bit)
245 mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_offs,
246 pd->data->pwr_rst_bit);
247
248 ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks);
249 if (ret)
250 goto err_disable_subsys_clks;
251
252 ret = scpsys_sram_enable(pd);
253 if (ret < 0)
254 goto err_disable_sram;
255
256 return 0;
257
258err_disable_sram:
259 scpsys_sram_disable(pd);
260err_disable_subsys_clks:
261 clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
262err_pwr_ack:
263 clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
264err_reg:
265 scpsys_regulator_disable(genpd);
266 return ret;
267}
268
269static int scpsys_power_off(struct generic_pm_domain *genpd)
270{
271 struct scpsys_domain *pd =
272 container_of(genpd, struct scpsys_domain, genpd);
273 struct scpsys *scpsys = pd->scpsys;
274 bool tmp;
275 int ret;
276
277 ret = scpsys_sram_disable(pd);
278 if (ret < 0)
279 return ret;
280
281 clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
282
283 if (pd->data->pwr_clamp_bit) {
284 mtk_regmap_set_bits(scpsys->base, pd->data->pwr_on_offs,
285 pd->data->pwr_clamp_bit);
286 udelay(30);
287 }
288 if (pd->data->pwr_rst_bit)
289 mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_offs,
290 pd->data->pwr_rst_bit);
291
292 mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_offs,
293 pd->data->pwr_on_bit);
294 mtk_regmap_clear_bits(scpsys->base, pd->data->pwr_on_2nd_offs,
295 pd->data->pwr_on_2nd_bit);
296
297 clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
298 scpsys_regulator_disable(genpd);
299
300 return 0;
301}
302
303static struct generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys,
304 struct device_node *node)
305{
306 const struct scpsys_domain_data *domain_data;
307 struct scpsys_domain *pd;
308 struct property *prop;
309 const char *clk_name;
310 int i, ret, num_clks;
311 struct clk *clk;
312 struct device_node *smi_node;
313 struct device_node *larb_node;
314 int clk_ind = 0;
315 u32 id;
316
317 ret = of_property_read_u32(node, "reg", &id);
318 if (ret) {
319 dev_err(scpsys->dev,
320 "%pOF: failed to retrieve domain id from reg: %d\n",
321 node, ret);
322 return ERR_PTR(-EINVAL);
323 }
324
325 if (id >= scpsys->soc_data->num_domains) {
326 dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id);
327 return ERR_PTR(-EINVAL);
328 }
329
330 domain_data = &scpsys->soc_data->domains_data[id];
331 if (domain_data->sta_mask == 0) {
332 dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node,
333 id);
334 return ERR_PTR(-EINVAL);
335 }
336
337 pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL);
338 if (!pd)
339 return ERR_PTR(-ENOMEM);
340
341 pd->data = domain_data;
342 pd->scpsys = scpsys;
343
344 num_clks = of_clk_get_parent_count(node);
345 if (num_clks > 0) {
346 /* Calculate number of subsys_clks */
347 of_property_for_each_string(node, "clock-names", prop,
348 clk_name) {
349 char *subsys;
350
351 subsys = strchr(clk_name, '-');
352 if (subsys)
353 pd->num_subsys_clks++;
354 else
355 pd->num_clks++;
356 }
357
358 pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks,
359 sizeof(*pd->clks), GFP_KERNEL);
360 if (!pd->clks)
361 return ERR_PTR(-ENOMEM);
362
363 pd->subsys_clks =
364 devm_kcalloc(scpsys->dev, pd->num_subsys_clks,
365 sizeof(*pd->subsys_clks), GFP_KERNEL);
366 if (!pd->subsys_clks)
367 return ERR_PTR(-ENOMEM);
368 }
369
370 for (i = 0; i < pd->num_clks; i++) {
371 clk = of_clk_get(node, i);
372 if (IS_ERR(clk)) {
373 ret = PTR_ERR(clk);
374 dev_err(scpsys->dev,
375 "%pOF: failed to get clk at index %d: %d\n",
376 node, i, ret);
377 goto err_put_clocks;
378 }
379
380 pd->clks[clk_ind++].clk = clk;
381 }
382
383 for (i = 0; i < pd->num_subsys_clks; i++) {
384 clk = of_clk_get(node, i + clk_ind);
385 if (IS_ERR(clk)) {
386 ret = PTR_ERR(clk);
387 dev_err(scpsys->dev,
388 "%pOF: failed to get clk at index %d: %d\n",
389 node, i + clk_ind, ret);
390 goto err_put_subsys_clocks;
391 }
392
393 pd->subsys_clks[i].clk = clk;
394 }
395
396 /*
397 * Initially turn on all domains to make the domains usable
398 * with !CONFIG_PM and to get the hardware in sync with the
399 * software. The unused domains will be switched off during
400 * late_init time.
401 */
402 if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) {
403 if (scpsys_domain_is_on(pd))
404 dev_warn(
405 scpsys->dev,
406 "%pOF: A default off power domain has been ON\n",
407 node);
408 } else {
409 ret = scpsys_power_on(&pd->genpd);
410 if (ret < 0) {
411 dev_err(scpsys->dev,
412 "%pOF: failed to power on domain: %d\n", node,
413 ret);
414 goto err_put_subsys_clocks;
415 }
416 }
417
418 if (scpsys->domains[id]) {
419 ret = -EINVAL;
420 dev_err(scpsys->dev,
421 "power domain with id %d already exists, check your device-tree\n",
422 id);
423 goto err_put_subsys_clocks;
424 }
425
426 pd->genpd.name = node->name;
427 pd->genpd.power_off = scpsys_power_off;
428 pd->genpd.power_on = scpsys_power_on;
429
430 if (MTK_SCPD_CAPS(pd, MTK_SCPD_ACTIVE_WAKEUP))
431 pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
432
433 if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF))
434 pm_genpd_init(&pd->genpd, NULL, true);
435 else
436 pm_genpd_init(&pd->genpd, NULL, false);
437
438 scpsys->domains[id] = &pd->genpd;
439
440 return scpsys->pd_data.domains[id];
441
442err_put_subsys_clocks:
443 clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
444err_put_clocks:
445 clk_bulk_put(pd->num_clks, pd->clks);
446 return ERR_PTR(ret);
447}
448
449static int scpsys_add_subdomain(struct scpsys *scpsys,
450 struct device_node *parent)
451{
452 struct generic_pm_domain *child_pd, *parent_pd;
453 struct device_node *child;
454 int ret;
455
456 for_each_child_of_node(parent, child) {
457 u32 id;
458
459 ret = of_property_read_u32(parent, "reg", &id);
460 if (ret) {
461 dev_err(scpsys->dev,
462 "%pOF: failed to get parent domain id\n",
463 child);
464 goto err_put_node;
465 }
466
467 if (!scpsys->pd_data.domains[id]) {
468 ret = -EINVAL;
469 dev_err(scpsys->dev,
470 "power domain with id %d does not exist\n", id);
471 goto err_put_node;
472 }
473
474 parent_pd = scpsys->pd_data.domains[id];
475
476 child_pd = scpsys_add_one_domain(scpsys, child);
477 if (IS_ERR(child_pd)) {
478 ret = PTR_ERR(child_pd);
479 dev_err(scpsys->dev,
480 "%pOF: failed to get child domain id\n", child);
481 goto err_put_node;
482 }
483
484 ret = pm_genpd_add_subdomain(parent_pd, child_pd);
485 if (ret) {
486 dev_err(scpsys->dev,
487 "failed to add %s subdomain to parent %s\n",
488 child_pd->name, parent_pd->name);
489 goto err_put_node;
490 } else {
491 dev_dbg(scpsys->dev, "%s add subdomain: %s\n",
492 parent_pd->name, child_pd->name);
493 }
494
495 /* recursive call to add all subdomains */
496 ret = scpsys_add_subdomain(scpsys, child);
497 if (ret)
498 goto err_put_node;
499 }
500
501 return 0;
502
503err_put_node:
504 of_node_put(child);
505 return ret;
506}
507
508static void scpsys_remove_one_domain(struct scpsys_domain *pd)
509{
510 int ret;
511
512 if (scpsys_domain_is_on(pd))
513 scpsys_power_off(&pd->genpd);
514
515 /*
516 * We're in the error cleanup already, so we only complain,
517 * but won't emit another error on top of the original one.
518 */
519 ret = pm_genpd_remove(&pd->genpd);
520 if (ret < 0)
521 dev_err(pd->scpsys->dev,
522 "failed to remove domain '%s' : %d - state may be inconsistent\n",
523 pd->genpd.name, ret);
524
525 clk_bulk_put(pd->num_clks, pd->clks);
526 clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
527}
528
529static void scpsys_domain_cleanup(struct scpsys *scpsys)
530{
531 struct generic_pm_domain *genpd;
532 struct scpsys_domain *pd;
533 int i;
534
535 for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) {
536 genpd = scpsys->pd_data.domains[i];
537 if (genpd) {
538 pd = to_scpsys_domain(genpd);
539 scpsys_remove_one_domain(pd);
540 }
541 }
542}
543
544static const struct of_device_id scpsys_of_match[] = {
545 {
546 .compatible = "mediatek,mt7988-power-controller",
547 .data = &mt7988_scpsys_data,
548 },
549 {}
550};
551
552static int scpsys_probe(struct platform_device *pdev)
553{
554 struct device *dev = &pdev->dev;
555 struct device_node *np = dev->of_node;
556 const struct scpsys_soc_data *soc;
557 struct device_node *node;
558 struct scpsys *scpsys;
559 struct resource *res;
560 int ret;
561
562 soc = of_device_get_match_data(&pdev->dev);
563 if (!soc) {
564 dev_err(&pdev->dev, "no power controller data\n");
565 return -EINVAL;
566 }
567
568 scpsys = devm_kzalloc(dev,
569 struct_size(scpsys, domains, soc->num_domains),
570 GFP_KERNEL);
571 if (!scpsys)
572 return -ENOMEM;
573
574 scpsys->dev = dev;
575 scpsys->soc_data = soc;
576
577 scpsys->pd_data.domains = scpsys->domains;
578 scpsys->pd_data.num_domains = soc->num_domains;
579 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
580 scpsys->base = syscon_node_to_regmap(np);
581 if (IS_ERR(scpsys->base)) {
582 dev_err(dev, "no regmap available\n");
583 return PTR_ERR(scpsys->base);
584 }
585
586 ret = -ENODEV;
587 for_each_available_child_of_node(np, node) {
588 struct generic_pm_domain *domain;
589
590 domain = scpsys_add_one_domain(scpsys, node);
591 if (IS_ERR(domain)) {
592 ret = PTR_ERR(domain);
593 of_node_put(node);
594 goto err_cleanup_domains;
595 }
596
597 ret = scpsys_add_subdomain(scpsys, node);
598 if (ret) {
599 of_node_put(node);
600 goto err_cleanup_domains;
601 }
602 }
603
604 if (ret) {
605 dev_dbg(dev, "no power domains present\n");
606 return ret;
607 }
608
609 ret = of_genpd_add_provider_onecell(np, &scpsys->pd_data);
610 if (ret) {
611 dev_err(dev, "failed to add provider: %d\n", ret);
612 goto err_cleanup_domains;
613 }
614
615 return 0;
616
617err_cleanup_domains:
618 scpsys_domain_cleanup(scpsys);
619 return ret;
620}
621
622static struct platform_driver scpsys_pm_domain_driver = {
623 .probe = scpsys_probe,
624 .driver = {
625 .name = "mtk-power-controller",
626 .suppress_bind_attrs = true,
627 .of_match_table = scpsys_of_match,
628 },
629};
630builtin_platform_driver(scpsys_pm_domain_driver);