1ee4df236SLubomir Rintel // SPDX-License-Identifier: GPL-2.0-or-later
2ee4df236SLubomir Rintel /*
3ee4df236SLubomir Rintel * MMP PMU power island support
4ee4df236SLubomir Rintel *
5ee4df236SLubomir Rintel * Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk>
6ee4df236SLubomir Rintel */
7ee4df236SLubomir Rintel
8ee4df236SLubomir Rintel #include <linux/pm_domain.h>
9ee4df236SLubomir Rintel #include <linux/slab.h>
10ee4df236SLubomir Rintel #include <linux/io.h>
11ee4df236SLubomir Rintel
12ee4df236SLubomir Rintel #include "clk.h"
13ee4df236SLubomir Rintel
14ee4df236SLubomir Rintel #define to_mmp_pm_domain(genpd) container_of(genpd, struct mmp_pm_domain, genpd)
15ee4df236SLubomir Rintel
16ee4df236SLubomir Rintel struct mmp_pm_domain {
17ee4df236SLubomir Rintel struct generic_pm_domain genpd;
18ee4df236SLubomir Rintel void __iomem *reg;
19ee4df236SLubomir Rintel spinlock_t *lock;
20ee4df236SLubomir Rintel u32 power_on;
21ee4df236SLubomir Rintel u32 reset;
22ee4df236SLubomir Rintel u32 clock_enable;
23ee4df236SLubomir Rintel unsigned int flags;
24ee4df236SLubomir Rintel };
25ee4df236SLubomir Rintel
mmp_pm_domain_power_on(struct generic_pm_domain * genpd)26ee4df236SLubomir Rintel static int mmp_pm_domain_power_on(struct generic_pm_domain *genpd)
27ee4df236SLubomir Rintel {
28ee4df236SLubomir Rintel struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd);
29ee4df236SLubomir Rintel unsigned long flags = 0;
30ee4df236SLubomir Rintel u32 val;
31ee4df236SLubomir Rintel
32ee4df236SLubomir Rintel if (pm_domain->lock)
33ee4df236SLubomir Rintel spin_lock_irqsave(pm_domain->lock, flags);
34ee4df236SLubomir Rintel
35ee4df236SLubomir Rintel val = readl(pm_domain->reg);
36ee4df236SLubomir Rintel
37ee4df236SLubomir Rintel /* Turn on the power island */
38ee4df236SLubomir Rintel val |= pm_domain->power_on;
39ee4df236SLubomir Rintel writel(val, pm_domain->reg);
40ee4df236SLubomir Rintel
41ee4df236SLubomir Rintel /* Disable isolation */
42ee4df236SLubomir Rintel val |= 0x100;
43ee4df236SLubomir Rintel writel(val, pm_domain->reg);
44ee4df236SLubomir Rintel
45ee4df236SLubomir Rintel /* Some blocks need to be reset after a power up */
46ee4df236SLubomir Rintel if (pm_domain->reset || pm_domain->clock_enable) {
47ee4df236SLubomir Rintel u32 after_power_on = val;
48ee4df236SLubomir Rintel
49ee4df236SLubomir Rintel val &= ~pm_domain->reset;
50ee4df236SLubomir Rintel writel(val, pm_domain->reg);
51ee4df236SLubomir Rintel
52ee4df236SLubomir Rintel val |= pm_domain->clock_enable;
53ee4df236SLubomir Rintel writel(val, pm_domain->reg);
54ee4df236SLubomir Rintel
55ee4df236SLubomir Rintel val |= pm_domain->reset;
56ee4df236SLubomir Rintel writel(val, pm_domain->reg);
57ee4df236SLubomir Rintel
58ee4df236SLubomir Rintel writel(after_power_on, pm_domain->reg);
59ee4df236SLubomir Rintel }
60ee4df236SLubomir Rintel
61ee4df236SLubomir Rintel if (pm_domain->lock)
62ee4df236SLubomir Rintel spin_unlock_irqrestore(pm_domain->lock, flags);
63ee4df236SLubomir Rintel
64ee4df236SLubomir Rintel return 0;
65ee4df236SLubomir Rintel }
66ee4df236SLubomir Rintel
mmp_pm_domain_power_off(struct generic_pm_domain * genpd)67ee4df236SLubomir Rintel static int mmp_pm_domain_power_off(struct generic_pm_domain *genpd)
68ee4df236SLubomir Rintel {
69ee4df236SLubomir Rintel struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd);
70ee4df236SLubomir Rintel unsigned long flags = 0;
71ee4df236SLubomir Rintel u32 val;
72ee4df236SLubomir Rintel
73ee4df236SLubomir Rintel if (pm_domain->flags & MMP_PM_DOMAIN_NO_DISABLE)
74ee4df236SLubomir Rintel return 0;
75ee4df236SLubomir Rintel
76ee4df236SLubomir Rintel if (pm_domain->lock)
77ee4df236SLubomir Rintel spin_lock_irqsave(pm_domain->lock, flags);
78ee4df236SLubomir Rintel
79*7c55e8efSTom Rix /* Turn off and isolate the power island. */
80ee4df236SLubomir Rintel val = readl(pm_domain->reg);
81ee4df236SLubomir Rintel val &= ~pm_domain->power_on;
82ee4df236SLubomir Rintel val &= ~0x100;
83ee4df236SLubomir Rintel writel(val, pm_domain->reg);
84ee4df236SLubomir Rintel
85ee4df236SLubomir Rintel if (pm_domain->lock)
86ee4df236SLubomir Rintel spin_unlock_irqrestore(pm_domain->lock, flags);
87ee4df236SLubomir Rintel
88ee4df236SLubomir Rintel return 0;
89ee4df236SLubomir Rintel }
90ee4df236SLubomir Rintel
mmp_pm_domain_register(const char * name,void __iomem * reg,u32 power_on,u32 reset,u32 clock_enable,unsigned int flags,spinlock_t * lock)91ee4df236SLubomir Rintel struct generic_pm_domain *mmp_pm_domain_register(const char *name,
92ee4df236SLubomir Rintel void __iomem *reg,
93ee4df236SLubomir Rintel u32 power_on, u32 reset, u32 clock_enable,
94ee4df236SLubomir Rintel unsigned int flags, spinlock_t *lock)
95ee4df236SLubomir Rintel {
96ee4df236SLubomir Rintel struct mmp_pm_domain *pm_domain;
97ee4df236SLubomir Rintel
98ee4df236SLubomir Rintel pm_domain = kzalloc(sizeof(*pm_domain), GFP_KERNEL);
99ee4df236SLubomir Rintel if (!pm_domain)
100ee4df236SLubomir Rintel return ERR_PTR(-ENOMEM);
101ee4df236SLubomir Rintel
102ee4df236SLubomir Rintel pm_domain->reg = reg;
103ee4df236SLubomir Rintel pm_domain->power_on = power_on;
104ee4df236SLubomir Rintel pm_domain->reset = reset;
105ee4df236SLubomir Rintel pm_domain->clock_enable = clock_enable;
106ee4df236SLubomir Rintel pm_domain->flags = flags;
107ee4df236SLubomir Rintel pm_domain->lock = lock;
108ee4df236SLubomir Rintel
109ee4df236SLubomir Rintel pm_genpd_init(&pm_domain->genpd, NULL, true);
110ee4df236SLubomir Rintel pm_domain->genpd.name = name;
111ee4df236SLubomir Rintel pm_domain->genpd.power_on = mmp_pm_domain_power_on;
112ee4df236SLubomir Rintel pm_domain->genpd.power_off = mmp_pm_domain_power_off;
113ee4df236SLubomir Rintel
114ee4df236SLubomir Rintel return &pm_domain->genpd;
115ee4df236SLubomir Rintel }
116