blob: 164a7d8439b148de97d7a3f4153786c52277df5b [file] [log] [blame]
Sascha Hauerc84e3582015-06-24 08:17:04 +02001/*
2 * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de>
3 *
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.
7 *
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.
12 */
13#include <linux/clk.h>
14#include <linux/delay.h>
15#include <linux/io.h>
16#include <linux/kernel.h>
17#include <linux/mfd/syscon.h>
Matthias Brugger9dd068a2015-07-31 17:03:13 +020018#include <linux/module.h>
Sascha Hauerc84e3582015-06-24 08:17:04 +020019#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>
25
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
38
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)
44
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)
55
56enum clk_id {
57 MT8173_CLK_MM,
58 MT8173_CLK_MFG,
59 MT8173_CLK_NONE,
60 MT8173_CLK_MAX = MT8173_CLK_NONE,
61};
62
63struct scp_domain_data {
64 const char *name;
65 u32 sta_mask;
66 int ctl_offs;
67 u32 sram_pdn_bits;
68 u32 sram_pdn_ack_bits;
69 u32 bus_prot_mask;
70 enum clk_id clk_id;
71};
72
73static const struct scp_domain_data scp_domain_data[] __initconst = {
74 [MT8173_POWER_DOMAIN_VDEC] = {
75 .name = "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,
81 },
82 [MT8173_POWER_DOMAIN_VENC] = {
83 .name = "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,
89 },
90 [MT8173_POWER_DOMAIN_ISP] = {
91 .name = "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,
97 },
98 [MT8173_POWER_DOMAIN_MM] = {
99 .name = "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,
107 },
108 [MT8173_POWER_DOMAIN_VENC_LT] = {
109 .name = "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,
115 },
116 [MT8173_POWER_DOMAIN_AUDIO] = {
117 .name = "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,
123 },
124 [MT8173_POWER_DOMAIN_USB] = {
125 .name = "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,
131 },
132 [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
133 .name = "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,
139 },
140 [MT8173_POWER_DOMAIN_MFG_2D] = {
141 .name = "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,
147 },
148 [MT8173_POWER_DOMAIN_MFG] = {
149 .name = "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,
159 },
160};
161
162#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data)
163
164struct scp;
165
166struct scp_domain {
167 struct generic_pm_domain genpd;
168 struct scp *scp;
169 struct clk *clk;
170 u32 sta_mask;
171 void __iomem *ctl_addr;
172 u32 sram_pdn_bits;
173 u32 sram_pdn_ack_bits;
174 u32 bus_prot_mask;
175};
176
177struct scp {
178 struct scp_domain domains[NUM_DOMAINS];
179 struct genpd_onecell_data pd_data;
180 struct device *dev;
181 void __iomem *base;
182 struct regmap *infracfg;
183};
184
185static int scpsys_domain_is_on(struct scp_domain *scpd)
186{
187 struct scp *scp = scpd->scp;
188
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;
191
192 /*
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
195 */
196
197 if (status && status2)
198 return true;
199 if (!status && !status2)
200 return false;
201
202 return -EINVAL;
203}
204
205static int scpsys_power_on(struct generic_pm_domain *genpd)
206{
207 struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
208 struct scp *scp = scpd->scp;
209 unsigned long timeout;
210 bool expired;
211 void __iomem *ctl_addr = scpd->ctl_addr;
212 u32 sram_pdn_ack = scpd->sram_pdn_ack_bits;
213 u32 val;
214 int ret;
215
216 if (scpd->clk) {
217 ret = clk_prepare_enable(scpd->clk);
218 if (ret)
219 goto err_clk;
220 }
221
222 val = readl(ctl_addr);
223 val |= PWR_ON_BIT;
224 writel(val, ctl_addr);
225 val |= PWR_ON_2ND_BIT;
226 writel(val, ctl_addr);
227
228 /* wait until PWR_ACK = 1 */
229 timeout = jiffies + HZ;
230 expired = false;
231 while (1) {
232 ret = scpsys_domain_is_on(scpd);
233 if (ret > 0)
234 break;
235
236 if (expired) {
237 ret = -ETIMEDOUT;
238 goto err_pwr_ack;
239 }
240
241 cpu_relax();
242
243 if (time_after(jiffies, timeout))
244 expired = true;
245 }
246
247 val &= ~PWR_CLK_DIS_BIT;
248 writel(val, ctl_addr);
249
250 val &= ~PWR_ISO_BIT;
251 writel(val, ctl_addr);
252
253 val |= PWR_RST_B_BIT;
254 writel(val, ctl_addr);
255
256 val &= ~scpd->sram_pdn_bits;
257 writel(val, ctl_addr);
258
259 /* wait until SRAM_PDN_ACK all 0 */
260 timeout = jiffies + HZ;
261 expired = false;
262 while (sram_pdn_ack && (readl(ctl_addr) & sram_pdn_ack)) {
263
264 if (expired) {
265 ret = -ETIMEDOUT;
266 goto err_pwr_ack;
267 }
268
269 cpu_relax();
270
271 if (time_after(jiffies, timeout))
272 expired = true;
273 }
274
275 if (scpd->bus_prot_mask) {
276 ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
277 scpd->bus_prot_mask);
278 if (ret)
279 goto err_pwr_ack;
280 }
281
282 return 0;
283
284err_pwr_ack:
285 clk_disable_unprepare(scpd->clk);
286err_clk:
287 dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
288
289 return ret;
290}
291
292static int scpsys_power_off(struct generic_pm_domain *genpd)
293{
294 struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
295 struct scp *scp = scpd->scp;
296 unsigned long timeout;
297 bool expired;
298 void __iomem *ctl_addr = scpd->ctl_addr;
299 u32 pdn_ack = scpd->sram_pdn_ack_bits;
300 u32 val;
301 int ret;
302
303 if (scpd->bus_prot_mask) {
304 ret = mtk_infracfg_set_bus_protection(scp->infracfg,
305 scpd->bus_prot_mask);
306 if (ret)
307 goto out;
308 }
309
310 val = readl(ctl_addr);
311 val |= scpd->sram_pdn_bits;
312 writel(val, ctl_addr);
313
314 /* wait until SRAM_PDN_ACK all 1 */
315 timeout = jiffies + HZ;
316 expired = false;
317 while (pdn_ack && (readl(ctl_addr) & pdn_ack) != pdn_ack) {
318 if (expired) {
319 ret = -ETIMEDOUT;
320 goto out;
321 }
322
323 cpu_relax();
324
325 if (time_after(jiffies, timeout))
326 expired = true;
327 }
328
329 val |= PWR_ISO_BIT;
330 writel(val, ctl_addr);
331
332 val &= ~PWR_RST_B_BIT;
333 writel(val, ctl_addr);
334
335 val |= PWR_CLK_DIS_BIT;
336 writel(val, ctl_addr);
337
338 val &= ~PWR_ON_BIT;
339 writel(val, ctl_addr);
340
341 val &= ~PWR_ON_2ND_BIT;
342 writel(val, ctl_addr);
343
344 /* wait until PWR_ACK = 0 */
345 timeout = jiffies + HZ;
346 expired = false;
347 while (1) {
348 ret = scpsys_domain_is_on(scpd);
349 if (ret == 0)
350 break;
351
352 if (expired) {
353 ret = -ETIMEDOUT;
354 goto out;
355 }
356
357 cpu_relax();
358
359 if (time_after(jiffies, timeout))
360 expired = true;
361 }
362
363 if (scpd->clk)
364 clk_disable_unprepare(scpd->clk);
365
366 return 0;
367
368out:
369 dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name);
370
371 return ret;
372}
373
374static int __init scpsys_probe(struct platform_device *pdev)
375{
376 struct genpd_onecell_data *pd_data;
377 struct resource *res;
378 int i, ret;
379 struct scp *scp;
380 struct clk *clk[MT8173_CLK_MAX];
381
382 scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
383 if (!scp)
384 return -ENOMEM;
385
386 scp->dev = &pdev->dev;
387
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);
392
393 pd_data = &scp->pd_data;
394
395 pd_data->domains = devm_kzalloc(&pdev->dev,
396 sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
397 if (!pd_data->domains)
398 return -ENOMEM;
399
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]);
403
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]);
407
408 scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
409 "infracfg");
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);
414 }
415
416 pd_data->num_domains = NUM_DOMAINS;
417
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];
422
423 pd_data->domains[i] = genpd;
424 scpd->scp = scp;
425
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];
433
434 genpd->name = data->name;
435 genpd->power_off = scpsys_power_off;
436 genpd->power_on = scpsys_power_on;
437
438 /*
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
442 * late_init time.
443 */
444 genpd->power_on(genpd);
445
446 pm_genpd_init(genpd, NULL, false);
447 }
448
449 /*
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
452 * valid.
453 */
454
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);
459
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);
464
465 ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
466 if (ret)
467 dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
468
469 return 0;
470}
471
472static const struct of_device_id of_scpsys_match_tbl[] = {
473 {
474 .compatible = "mediatek,mt8173-scpsys",
475 }, {
476 /* sentinel */
477 }
478};
479
480static struct platform_driver scpsys_drv = {
481 .driver = {
482 .name = "mtk-scpsys",
483 .owner = THIS_MODULE,
484 .of_match_table = of_match_ptr(of_scpsys_match_tbl),
485 },
486};
487
488module_platform_driver_probe(scpsys_drv, scpsys_probe);