2 * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 #include <linux/clk.h>
14 #include <linux/delay.h>
16 #include <linux/kernel.h>
17 #include <linux/mfd/syscon.h>
18 #include <linux/module.h>
19 #include <linux/of_device.h>
20 #include <linux/platform_device.h>
21 #include <linux/pm_domain.h>
22 #include <linux/regmap.h>
23 #include <linux/soc/mediatek/infracfg.h>
24 #include <dt-bindings/power/mt8173-power.h>
26 #define SPM_VDE_PWR_CON 0x0210
27 #define SPM_MFG_PWR_CON 0x0214
28 #define SPM_VEN_PWR_CON 0x0230
29 #define SPM_ISP_PWR_CON 0x0238
30 #define SPM_DIS_PWR_CON 0x023c
31 #define SPM_VEN2_PWR_CON 0x0298
32 #define SPM_AUDIO_PWR_CON 0x029c
33 #define SPM_MFG_2D_PWR_CON 0x02c0
34 #define SPM_MFG_ASYNC_PWR_CON 0x02c4
35 #define SPM_USB_PWR_CON 0x02cc
36 #define SPM_PWR_STATUS 0x060c
37 #define SPM_PWR_STATUS_2ND 0x0610
39 #define PWR_RST_B_BIT BIT(0)
40 #define PWR_ISO_BIT BIT(1)
41 #define PWR_ON_BIT BIT(2)
42 #define PWR_ON_2ND_BIT BIT(3)
43 #define PWR_CLK_DIS_BIT BIT(4)
45 #define PWR_STATUS_DISP BIT(3)
46 #define PWR_STATUS_MFG BIT(4)
47 #define PWR_STATUS_ISP BIT(5)
48 #define PWR_STATUS_VDEC BIT(7)
49 #define PWR_STATUS_VENC_LT BIT(20)
50 #define PWR_STATUS_VENC BIT(21)
51 #define PWR_STATUS_MFG_2D BIT(22)
52 #define PWR_STATUS_MFG_ASYNC BIT(23)
53 #define PWR_STATUS_AUDIO BIT(24)
54 #define PWR_STATUS_USB BIT(25)
60 MT8173_CLK_MAX = MT8173_CLK_NONE,
63 struct scp_domain_data {
68 u32 sram_pdn_ack_bits;
73 static const struct scp_domain_data scp_domain_data[] __initconst = {
74 [MT8173_POWER_DOMAIN_VDEC] = {
76 .sta_mask = PWR_STATUS_VDEC,
77 .ctl_offs = SPM_VDE_PWR_CON,
78 .sram_pdn_bits = GENMASK(11, 8),
79 .sram_pdn_ack_bits = GENMASK(12, 12),
80 .clk_id = MT8173_CLK_MM,
82 [MT8173_POWER_DOMAIN_VENC] = {
84 .sta_mask = PWR_STATUS_VENC,
85 .ctl_offs = SPM_VEN_PWR_CON,
86 .sram_pdn_bits = GENMASK(11, 8),
87 .sram_pdn_ack_bits = GENMASK(15, 12),
88 .clk_id = MT8173_CLK_MM,
90 [MT8173_POWER_DOMAIN_ISP] = {
92 .sta_mask = PWR_STATUS_ISP,
93 .ctl_offs = SPM_ISP_PWR_CON,
94 .sram_pdn_bits = GENMASK(11, 8),
95 .sram_pdn_ack_bits = GENMASK(13, 12),
96 .clk_id = MT8173_CLK_MM,
98 [MT8173_POWER_DOMAIN_MM] = {
100 .sta_mask = PWR_STATUS_DISP,
101 .ctl_offs = SPM_DIS_PWR_CON,
102 .sram_pdn_bits = GENMASK(11, 8),
103 .sram_pdn_ack_bits = GENMASK(12, 12),
104 .clk_id = MT8173_CLK_MM,
105 .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
106 MT8173_TOP_AXI_PROT_EN_MM_M1,
108 [MT8173_POWER_DOMAIN_VENC_LT] = {
110 .sta_mask = PWR_STATUS_VENC_LT,
111 .ctl_offs = SPM_VEN2_PWR_CON,
112 .sram_pdn_bits = GENMASK(11, 8),
113 .sram_pdn_ack_bits = GENMASK(15, 12),
114 .clk_id = MT8173_CLK_MM,
116 [MT8173_POWER_DOMAIN_AUDIO] = {
118 .sta_mask = PWR_STATUS_AUDIO,
119 .ctl_offs = SPM_AUDIO_PWR_CON,
120 .sram_pdn_bits = GENMASK(11, 8),
121 .sram_pdn_ack_bits = GENMASK(15, 12),
122 .clk_id = MT8173_CLK_NONE,
124 [MT8173_POWER_DOMAIN_USB] = {
126 .sta_mask = PWR_STATUS_USB,
127 .ctl_offs = SPM_USB_PWR_CON,
128 .sram_pdn_bits = GENMASK(11, 8),
129 .sram_pdn_ack_bits = GENMASK(15, 12),
130 .clk_id = MT8173_CLK_NONE,
132 [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
134 .sta_mask = PWR_STATUS_MFG_ASYNC,
135 .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
136 .sram_pdn_bits = GENMASK(11, 8),
137 .sram_pdn_ack_bits = 0,
138 .clk_id = MT8173_CLK_MFG,
140 [MT8173_POWER_DOMAIN_MFG_2D] = {
142 .sta_mask = PWR_STATUS_MFG_2D,
143 .ctl_offs = SPM_MFG_2D_PWR_CON,
144 .sram_pdn_bits = GENMASK(11, 8),
145 .sram_pdn_ack_bits = GENMASK(13, 12),
146 .clk_id = MT8173_CLK_NONE,
148 [MT8173_POWER_DOMAIN_MFG] = {
150 .sta_mask = PWR_STATUS_MFG,
151 .ctl_offs = SPM_MFG_PWR_CON,
152 .sram_pdn_bits = GENMASK(13, 8),
153 .sram_pdn_ack_bits = GENMASK(21, 16),
154 .clk_id = MT8173_CLK_NONE,
155 .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
156 MT8173_TOP_AXI_PROT_EN_MFG_M0 |
157 MT8173_TOP_AXI_PROT_EN_MFG_M1 |
158 MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
162 #define NUM_DOMAINS ARRAY_SIZE(scp_domain_data)
167 struct generic_pm_domain genpd;
171 void __iomem *ctl_addr;
173 u32 sram_pdn_ack_bits;
178 struct scp_domain domains[NUM_DOMAINS];
179 struct genpd_onecell_data pd_data;
182 struct regmap *infracfg;
185 static int scpsys_domain_is_on(struct scp_domain *scpd)
187 struct scp *scp = scpd->scp;
189 u32 status = readl(scp->base + SPM_PWR_STATUS) & scpd->sta_mask;
190 u32 status2 = readl(scp->base + SPM_PWR_STATUS_2ND) & scpd->sta_mask;
193 * A domain is on when both status bits are set. If only one is set
194 * return an error. This happens while powering up a domain
197 if (status && status2)
199 if (!status && !status2)
205 static int scpsys_power_on(struct generic_pm_domain *genpd)
207 struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
208 struct scp *scp = scpd->scp;
209 unsigned long timeout;
211 void __iomem *ctl_addr = scpd->ctl_addr;
212 u32 sram_pdn_ack = scpd->sram_pdn_ack_bits;
217 ret = clk_prepare_enable(scpd->clk);
222 val = readl(ctl_addr);
224 writel(val, ctl_addr);
225 val |= PWR_ON_2ND_BIT;
226 writel(val, ctl_addr);
228 /* wait until PWR_ACK = 1 */
229 timeout = jiffies + HZ;
232 ret = scpsys_domain_is_on(scpd);
243 if (time_after(jiffies, timeout))
247 val &= ~PWR_CLK_DIS_BIT;
248 writel(val, ctl_addr);
251 writel(val, ctl_addr);
253 val |= PWR_RST_B_BIT;
254 writel(val, ctl_addr);
256 val &= ~scpd->sram_pdn_bits;
257 writel(val, ctl_addr);
259 /* wait until SRAM_PDN_ACK all 0 */
260 timeout = jiffies + HZ;
262 while (sram_pdn_ack && (readl(ctl_addr) & sram_pdn_ack)) {
271 if (time_after(jiffies, timeout))
275 if (scpd->bus_prot_mask) {
276 ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
277 scpd->bus_prot_mask);
285 clk_disable_unprepare(scpd->clk);
287 dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
292 static int scpsys_power_off(struct generic_pm_domain *genpd)
294 struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
295 struct scp *scp = scpd->scp;
296 unsigned long timeout;
298 void __iomem *ctl_addr = scpd->ctl_addr;
299 u32 pdn_ack = scpd->sram_pdn_ack_bits;
303 if (scpd->bus_prot_mask) {
304 ret = mtk_infracfg_set_bus_protection(scp->infracfg,
305 scpd->bus_prot_mask);
310 val = readl(ctl_addr);
311 val |= scpd->sram_pdn_bits;
312 writel(val, ctl_addr);
314 /* wait until SRAM_PDN_ACK all 1 */
315 timeout = jiffies + HZ;
317 while (pdn_ack && (readl(ctl_addr) & pdn_ack) != pdn_ack) {
325 if (time_after(jiffies, timeout))
330 writel(val, ctl_addr);
332 val &= ~PWR_RST_B_BIT;
333 writel(val, ctl_addr);
335 val |= PWR_CLK_DIS_BIT;
336 writel(val, ctl_addr);
339 writel(val, ctl_addr);
341 val &= ~PWR_ON_2ND_BIT;
342 writel(val, ctl_addr);
344 /* wait until PWR_ACK = 0 */
345 timeout = jiffies + HZ;
348 ret = scpsys_domain_is_on(scpd);
359 if (time_after(jiffies, timeout))
364 clk_disable_unprepare(scpd->clk);
369 dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name);
374 static int __init scpsys_probe(struct platform_device *pdev)
376 struct genpd_onecell_data *pd_data;
377 struct resource *res;
380 struct clk *clk[MT8173_CLK_MAX];
382 scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
386 scp->dev = &pdev->dev;
388 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
389 scp->base = devm_ioremap_resource(&pdev->dev, res);
390 if (IS_ERR(scp->base))
391 return PTR_ERR(scp->base);
393 pd_data = &scp->pd_data;
395 pd_data->domains = devm_kzalloc(&pdev->dev,
396 sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
397 if (!pd_data->domains)
400 clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
401 if (IS_ERR(clk[MT8173_CLK_MM]))
402 return PTR_ERR(clk[MT8173_CLK_MM]);
404 clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
405 if (IS_ERR(clk[MT8173_CLK_MFG]))
406 return PTR_ERR(clk[MT8173_CLK_MFG]);
408 scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
410 if (IS_ERR(scp->infracfg)) {
411 dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
412 PTR_ERR(scp->infracfg));
413 return PTR_ERR(scp->infracfg);
416 pd_data->num_domains = NUM_DOMAINS;
418 for (i = 0; i < NUM_DOMAINS; i++) {
419 struct scp_domain *scpd = &scp->domains[i];
420 struct generic_pm_domain *genpd = &scpd->genpd;
421 const struct scp_domain_data *data = &scp_domain_data[i];
423 pd_data->domains[i] = genpd;
426 scpd->sta_mask = data->sta_mask;
427 scpd->ctl_addr = scp->base + data->ctl_offs;
428 scpd->sram_pdn_bits = data->sram_pdn_bits;
429 scpd->sram_pdn_ack_bits = data->sram_pdn_ack_bits;
430 scpd->bus_prot_mask = data->bus_prot_mask;
431 if (data->clk_id != MT8173_CLK_NONE)
432 scpd->clk = clk[data->clk_id];
434 genpd->name = data->name;
435 genpd->power_off = scpsys_power_off;
436 genpd->power_on = scpsys_power_on;
439 * Initially turn on all domains to make the domains usable
440 * with !CONFIG_PM and to get the hardware in sync with the
441 * software. The unused domains will be switched off during
444 genpd->power_on(genpd);
446 pm_genpd_init(genpd, NULL, false);
450 * We are not allowed to fail here since there is no way to unregister
451 * a power domain. Once registered above we have to keep the domains
455 ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC],
456 pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]);
457 if (ret && IS_ENABLED(CONFIG_PM))
458 dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
460 ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D],
461 pd_data->domains[MT8173_POWER_DOMAIN_MFG]);
462 if (ret && IS_ENABLED(CONFIG_PM))
463 dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
465 ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
467 dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
472 static const struct of_device_id of_scpsys_match_tbl[] = {
474 .compatible = "mediatek,mt8173-scpsys",
480 static struct platform_driver scpsys_drv = {
482 .name = "mtk-scpsys",
483 .owner = THIS_MODULE,
484 .of_match_table = of_match_ptr(of_scpsys_match_tbl),
488 module_platform_driver_probe(scpsys_drv, scpsys_probe);