1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2020 Collabora Ltd.
6 #include <linux/clk-provider.h>
7 #include <linux/init.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>
18 #include "mt8173-pm-domains.h"
19 #include "mt8183-pm-domains.h"
20 #include "mt8192-pm-domains.h"
22 #define MTK_POLL_DELAY_US 10
23 #define MTK_POLL_TIMEOUT USEC_PER_SEC
25 #define PWR_RST_B_BIT BIT(0)
26 #define PWR_ISO_BIT BIT(1)
27 #define PWR_ON_BIT BIT(2)
28 #define PWR_ON_2ND_BIT BIT(3)
29 #define PWR_CLK_DIS_BIT BIT(4)
30 #define PWR_SRAM_CLKISO_BIT BIT(5)
31 #define PWR_SRAM_ISOINT_B_BIT BIT(6)
33 struct scpsys_domain
{
34 struct generic_pm_domain genpd
;
35 const struct scpsys_domain_data
*data
;
36 struct scpsys
*scpsys
;
38 struct clk_bulk_data
*clks
;
40 struct clk_bulk_data
*subsys_clks
;
41 struct regmap
*infracfg
;
48 const struct scpsys_soc_data
*soc_data
;
49 struct genpd_onecell_data pd_data
;
50 struct generic_pm_domain
*domains
[];
53 #define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd)
55 static bool scpsys_domain_is_on(struct scpsys_domain
*pd
)
57 struct scpsys
*scpsys
= pd
->scpsys
;
60 regmap_read(scpsys
->base
, scpsys
->soc_data
->pwr_sta_offs
, &status
);
61 status
&= pd
->data
->sta_mask
;
63 regmap_read(scpsys
->base
, scpsys
->soc_data
->pwr_sta2nd_offs
, &status2
);
64 status2
&= pd
->data
->sta_mask
;
66 /* A domain is on when both status bits are set. */
67 return status
&& status2
;
70 static int scpsys_sram_enable(struct scpsys_domain
*pd
)
72 u32 pdn_ack
= pd
->data
->sram_pdn_ack_bits
;
73 struct scpsys
*scpsys
= pd
->scpsys
;
77 regmap_clear_bits(scpsys
->base
, pd
->data
->ctl_offs
, pd
->data
->sram_pdn_bits
);
79 /* Either wait until SRAM_PDN_ACK all 1 or 0 */
80 ret
= regmap_read_poll_timeout(scpsys
->base
, pd
->data
->ctl_offs
, tmp
,
81 (tmp
& pdn_ack
) == 0, MTK_POLL_DELAY_US
, MTK_POLL_TIMEOUT
);
85 if (MTK_SCPD_CAPS(pd
, MTK_SCPD_SRAM_ISO
)) {
86 regmap_set_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_SRAM_ISOINT_B_BIT
);
88 regmap_clear_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_SRAM_CLKISO_BIT
);
94 static int scpsys_sram_disable(struct scpsys_domain
*pd
)
96 u32 pdn_ack
= pd
->data
->sram_pdn_ack_bits
;
97 struct scpsys
*scpsys
= pd
->scpsys
;
100 if (MTK_SCPD_CAPS(pd
, MTK_SCPD_SRAM_ISO
)) {
101 regmap_set_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_SRAM_CLKISO_BIT
);
103 regmap_clear_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_SRAM_ISOINT_B_BIT
);
106 regmap_set_bits(scpsys
->base
, pd
->data
->ctl_offs
, pd
->data
->sram_pdn_bits
);
108 /* Either wait until SRAM_PDN_ACK all 1 or 0 */
109 return regmap_read_poll_timeout(scpsys
->base
, pd
->data
->ctl_offs
, tmp
,
110 (tmp
& pdn_ack
) == pdn_ack
, MTK_POLL_DELAY_US
,
114 static int _scpsys_bus_protect_enable(const struct scpsys_bus_prot_data
*bpd
, struct regmap
*regmap
)
118 for (i
= 0; i
< SPM_MAX_BUS_PROT_DATA
; i
++) {
119 u32 val
, mask
= bpd
[i
].bus_prot_mask
;
124 if (bpd
[i
].bus_prot_reg_update
)
125 regmap_set_bits(regmap
, bpd
[i
].bus_prot_set
, mask
);
127 regmap_write(regmap
, bpd
[i
].bus_prot_set
, mask
);
129 ret
= regmap_read_poll_timeout(regmap
, bpd
[i
].bus_prot_sta
,
130 val
, (val
& mask
) == mask
,
131 MTK_POLL_DELAY_US
, MTK_POLL_TIMEOUT
);
139 static int scpsys_bus_protect_enable(struct scpsys_domain
*pd
)
143 ret
= _scpsys_bus_protect_enable(pd
->data
->bp_infracfg
, pd
->infracfg
);
147 return _scpsys_bus_protect_enable(pd
->data
->bp_smi
, pd
->smi
);
150 static int _scpsys_bus_protect_disable(const struct scpsys_bus_prot_data
*bpd
,
151 struct regmap
*regmap
)
155 for (i
= SPM_MAX_BUS_PROT_DATA
- 1; i
>= 0; i
--) {
156 u32 val
, mask
= bpd
[i
].bus_prot_mask
;
161 if (bpd
[i
].bus_prot_reg_update
)
162 regmap_clear_bits(regmap
, bpd
[i
].bus_prot_clr
, mask
);
164 regmap_write(regmap
, bpd
[i
].bus_prot_clr
, mask
);
166 if (bpd
[i
].ignore_clr_ack
)
169 ret
= regmap_read_poll_timeout(regmap
, bpd
[i
].bus_prot_sta
,
171 MTK_POLL_DELAY_US
, MTK_POLL_TIMEOUT
);
179 static int scpsys_bus_protect_disable(struct scpsys_domain
*pd
)
183 ret
= _scpsys_bus_protect_disable(pd
->data
->bp_smi
, pd
->smi
);
187 return _scpsys_bus_protect_disable(pd
->data
->bp_infracfg
, pd
->infracfg
);
190 static int scpsys_power_on(struct generic_pm_domain
*genpd
)
192 struct scpsys_domain
*pd
= container_of(genpd
, struct scpsys_domain
, genpd
);
193 struct scpsys
*scpsys
= pd
->scpsys
;
197 ret
= clk_bulk_enable(pd
->num_clks
, pd
->clks
);
201 /* subsys power on */
202 regmap_set_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_ON_BIT
);
203 regmap_set_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_ON_2ND_BIT
);
205 /* wait until PWR_ACK = 1 */
206 ret
= readx_poll_timeout(scpsys_domain_is_on
, pd
, tmp
, tmp
, MTK_POLL_DELAY_US
,
211 regmap_clear_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_CLK_DIS_BIT
);
212 regmap_clear_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_ISO_BIT
);
213 regmap_set_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_RST_B_BIT
);
215 ret
= clk_bulk_enable(pd
->num_subsys_clks
, pd
->subsys_clks
);
219 ret
= scpsys_sram_enable(pd
);
221 goto err_disable_subsys_clks
;
223 ret
= scpsys_bus_protect_disable(pd
);
225 goto err_disable_sram
;
230 scpsys_sram_disable(pd
);
231 err_disable_subsys_clks
:
232 clk_bulk_disable(pd
->num_subsys_clks
, pd
->subsys_clks
);
234 clk_bulk_disable(pd
->num_clks
, pd
->clks
);
238 static int scpsys_power_off(struct generic_pm_domain
*genpd
)
240 struct scpsys_domain
*pd
= container_of(genpd
, struct scpsys_domain
, genpd
);
241 struct scpsys
*scpsys
= pd
->scpsys
;
245 ret
= scpsys_bus_protect_enable(pd
);
249 ret
= scpsys_sram_disable(pd
);
253 clk_bulk_disable(pd
->num_subsys_clks
, pd
->subsys_clks
);
255 /* subsys power off */
256 regmap_clear_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_RST_B_BIT
);
257 regmap_set_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_ISO_BIT
);
258 regmap_set_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_CLK_DIS_BIT
);
259 regmap_clear_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_ON_2ND_BIT
);
260 regmap_clear_bits(scpsys
->base
, pd
->data
->ctl_offs
, PWR_ON_BIT
);
262 /* wait until PWR_ACK = 0 */
263 ret
= readx_poll_timeout(scpsys_domain_is_on
, pd
, tmp
, !tmp
, MTK_POLL_DELAY_US
,
268 clk_bulk_disable(pd
->num_clks
, pd
->clks
);
274 generic_pm_domain
*scpsys_add_one_domain(struct scpsys
*scpsys
, struct device_node
*node
)
276 const struct scpsys_domain_data
*domain_data
;
277 struct scpsys_domain
*pd
;
278 struct property
*prop
;
279 const char *clk_name
;
280 int i
, ret
, num_clks
;
285 ret
= of_property_read_u32(node
, "reg", &id
);
287 dev_err(scpsys
->dev
, "%pOF: failed to retrieve domain id from reg: %d\n",
289 return ERR_PTR(-EINVAL
);
292 if (id
>= scpsys
->soc_data
->num_domains
) {
293 dev_err(scpsys
->dev
, "%pOF: invalid domain id %d\n", node
, id
);
294 return ERR_PTR(-EINVAL
);
297 domain_data
= &scpsys
->soc_data
->domains_data
[id
];
298 if (domain_data
->sta_mask
== 0) {
299 dev_err(scpsys
->dev
, "%pOF: undefined domain id %d\n", node
, id
);
300 return ERR_PTR(-EINVAL
);
303 pd
= devm_kzalloc(scpsys
->dev
, sizeof(*pd
), GFP_KERNEL
);
305 return ERR_PTR(-ENOMEM
);
307 pd
->data
= domain_data
;
310 pd
->infracfg
= syscon_regmap_lookup_by_phandle_optional(node
, "mediatek,infracfg");
311 if (IS_ERR(pd
->infracfg
))
312 return ERR_CAST(pd
->infracfg
);
314 pd
->smi
= syscon_regmap_lookup_by_phandle_optional(node
, "mediatek,smi");
316 return ERR_CAST(pd
->smi
);
318 num_clks
= of_clk_get_parent_count(node
);
320 /* Calculate number of subsys_clks */
321 of_property_for_each_string(node
, "clock-names", prop
, clk_name
) {
324 subsys
= strchr(clk_name
, '-');
326 pd
->num_subsys_clks
++;
331 pd
->clks
= devm_kcalloc(scpsys
->dev
, pd
->num_clks
, sizeof(*pd
->clks
), GFP_KERNEL
);
333 return ERR_PTR(-ENOMEM
);
335 pd
->subsys_clks
= devm_kcalloc(scpsys
->dev
, pd
->num_subsys_clks
,
336 sizeof(*pd
->subsys_clks
), GFP_KERNEL
);
337 if (!pd
->subsys_clks
)
338 return ERR_PTR(-ENOMEM
);
342 for (i
= 0; i
< pd
->num_clks
; i
++) {
343 clk
= of_clk_get(node
, i
);
346 dev_err_probe(scpsys
->dev
, ret
,
347 "%pOF: failed to get clk at index %d: %d\n", node
, i
, ret
);
351 pd
->clks
[clk_ind
++].clk
= clk
;
354 for (i
= 0; i
< pd
->num_subsys_clks
; i
++) {
355 clk
= of_clk_get(node
, i
+ clk_ind
);
358 dev_err_probe(scpsys
->dev
, ret
,
359 "%pOF: failed to get clk at index %d: %d\n", node
,
361 goto err_put_subsys_clocks
;
364 pd
->subsys_clks
[i
].clk
= clk
;
367 ret
= clk_bulk_prepare(pd
->num_clks
, pd
->clks
);
369 goto err_put_subsys_clocks
;
371 ret
= clk_bulk_prepare(pd
->num_subsys_clks
, pd
->subsys_clks
);
373 goto err_unprepare_clocks
;
376 * Initially turn on all domains to make the domains usable
377 * with !CONFIG_PM and to get the hardware in sync with the
378 * software. The unused domains will be switched off during
381 if (MTK_SCPD_CAPS(pd
, MTK_SCPD_KEEP_DEFAULT_OFF
)) {
382 if (scpsys_domain_is_on(pd
))
383 dev_warn(scpsys
->dev
,
384 "%pOF: A default off power domain has been ON\n", node
);
386 ret
= scpsys_power_on(&pd
->genpd
);
388 dev_err(scpsys
->dev
, "%pOF: failed to power on domain: %d\n", node
, ret
);
389 goto err_unprepare_clocks
;
393 if (scpsys
->domains
[id
]) {
396 "power domain with id %d already exists, check your device-tree\n", id
);
397 goto err_unprepare_subsys_clocks
;
400 pd
->genpd
.name
= node
->name
;
401 pd
->genpd
.power_off
= scpsys_power_off
;
402 pd
->genpd
.power_on
= scpsys_power_on
;
404 if (MTK_SCPD_CAPS(pd
, MTK_SCPD_KEEP_DEFAULT_OFF
))
405 pm_genpd_init(&pd
->genpd
, NULL
, true);
407 pm_genpd_init(&pd
->genpd
, NULL
, false);
409 scpsys
->domains
[id
] = &pd
->genpd
;
411 return scpsys
->pd_data
.domains
[id
];
413 err_unprepare_subsys_clocks
:
414 clk_bulk_unprepare(pd
->num_subsys_clks
, pd
->subsys_clks
);
415 err_unprepare_clocks
:
416 clk_bulk_unprepare(pd
->num_clks
, pd
->clks
);
417 err_put_subsys_clocks
:
418 clk_bulk_put(pd
->num_subsys_clks
, pd
->subsys_clks
);
420 clk_bulk_put(pd
->num_clks
, pd
->clks
);
424 static int scpsys_add_subdomain(struct scpsys
*scpsys
, struct device_node
*parent
)
426 struct generic_pm_domain
*child_pd
, *parent_pd
;
427 struct device_node
*child
;
430 for_each_child_of_node(parent
, child
) {
433 ret
= of_property_read_u32(parent
, "reg", &id
);
435 dev_err(scpsys
->dev
, "%pOF: failed to get parent domain id\n", child
);
439 if (!scpsys
->pd_data
.domains
[id
]) {
441 dev_err(scpsys
->dev
, "power domain with id %d does not exist\n", id
);
445 parent_pd
= scpsys
->pd_data
.domains
[id
];
447 child_pd
= scpsys_add_one_domain(scpsys
, child
);
448 if (IS_ERR(child_pd
)) {
449 ret
= PTR_ERR(child_pd
);
450 dev_err(scpsys
->dev
, "%pOF: failed to get child domain id\n", child
);
454 ret
= pm_genpd_add_subdomain(parent_pd
, child_pd
);
456 dev_err(scpsys
->dev
, "failed to add %s subdomain to parent %s\n",
457 child_pd
->name
, parent_pd
->name
);
460 dev_dbg(scpsys
->dev
, "%s add subdomain: %s\n", parent_pd
->name
,
464 /* recursive call to add all subdomains */
465 ret
= scpsys_add_subdomain(scpsys
, child
);
477 static void scpsys_remove_one_domain(struct scpsys_domain
*pd
)
481 if (scpsys_domain_is_on(pd
))
482 scpsys_power_off(&pd
->genpd
);
485 * We're in the error cleanup already, so we only complain,
486 * but won't emit another error on top of the original one.
488 ret
= pm_genpd_remove(&pd
->genpd
);
490 dev_err(pd
->scpsys
->dev
,
491 "failed to remove domain '%s' : %d - state may be inconsistent\n",
492 pd
->genpd
.name
, ret
);
494 clk_bulk_unprepare(pd
->num_clks
, pd
->clks
);
495 clk_bulk_put(pd
->num_clks
, pd
->clks
);
497 clk_bulk_unprepare(pd
->num_subsys_clks
, pd
->subsys_clks
);
498 clk_bulk_put(pd
->num_subsys_clks
, pd
->subsys_clks
);
501 static void scpsys_domain_cleanup(struct scpsys
*scpsys
)
503 struct generic_pm_domain
*genpd
;
504 struct scpsys_domain
*pd
;
507 for (i
= scpsys
->pd_data
.num_domains
- 1; i
>= 0; i
--) {
508 genpd
= scpsys
->pd_data
.domains
[i
];
510 pd
= to_scpsys_domain(genpd
);
511 scpsys_remove_one_domain(pd
);
516 static const struct of_device_id scpsys_of_match
[] = {
518 .compatible
= "mediatek,mt8173-power-controller",
519 .data
= &mt8173_scpsys_data
,
522 .compatible
= "mediatek,mt8183-power-controller",
523 .data
= &mt8183_scpsys_data
,
526 .compatible
= "mediatek,mt8192-power-controller",
527 .data
= &mt8192_scpsys_data
,
532 static int scpsys_probe(struct platform_device
*pdev
)
534 struct device
*dev
= &pdev
->dev
;
535 struct device_node
*np
= dev
->of_node
;
536 const struct scpsys_soc_data
*soc
;
537 struct device_node
*node
;
538 struct device
*parent
;
539 struct scpsys
*scpsys
;
542 soc
= of_device_get_match_data(&pdev
->dev
);
544 dev_err(&pdev
->dev
, "no power controller data\n");
548 scpsys
= devm_kzalloc(dev
, struct_size(scpsys
, domains
, soc
->num_domains
), GFP_KERNEL
);
553 scpsys
->soc_data
= soc
;
555 scpsys
->pd_data
.domains
= scpsys
->domains
;
556 scpsys
->pd_data
.num_domains
= soc
->num_domains
;
558 parent
= dev
->parent
;
560 dev_err(dev
, "no parent for syscon devices\n");
564 scpsys
->base
= syscon_node_to_regmap(parent
->of_node
);
565 if (IS_ERR(scpsys
->base
)) {
566 dev_err(dev
, "no regmap available\n");
567 return PTR_ERR(scpsys
->base
);
571 for_each_available_child_of_node(np
, node
) {
572 struct generic_pm_domain
*domain
;
574 domain
= scpsys_add_one_domain(scpsys
, node
);
575 if (IS_ERR(domain
)) {
576 ret
= PTR_ERR(domain
);
578 goto err_cleanup_domains
;
581 ret
= scpsys_add_subdomain(scpsys
, node
);
584 goto err_cleanup_domains
;
589 dev_dbg(dev
, "no power domains present\n");
593 ret
= of_genpd_add_provider_onecell(np
, &scpsys
->pd_data
);
595 dev_err(dev
, "failed to add provider: %d\n", ret
);
596 goto err_cleanup_domains
;
602 scpsys_domain_cleanup(scpsys
);
606 static struct platform_driver scpsys_pm_domain_driver
= {
607 .probe
= scpsys_probe
,
609 .name
= "mtk-power-controller",
610 .suppress_bind_attrs
= true,
611 .of_match_table
= scpsys_of_match
,
614 builtin_platform_driver(scpsys_pm_domain_driver
);