GNU Linux-libre 6.1.24-gnu
[releases.git] / drivers / soc / apple / apple-pmgr-pwrstate.c
1 // SPDX-License-Identifier: GPL-2.0-only OR MIT
2 /*
3  * Apple SoC PMGR device power state driver
4  *
5  * Copyright The Asahi Linux Contributors
6  */
7
8 #include <linux/bitops.h>
9 #include <linux/bitfield.h>
10 #include <linux/err.h>
11 #include <linux/of.h>
12 #include <linux/of_address.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm_domain.h>
15 #include <linux/regmap.h>
16 #include <linux/mfd/syscon.h>
17 #include <linux/reset-controller.h>
18 #include <linux/module.h>
19
20 #define APPLE_PMGR_RESET        BIT(31)
21 #define APPLE_PMGR_AUTO_ENABLE  BIT(28)
22 #define APPLE_PMGR_PS_AUTO      GENMASK(27, 24)
23 #define APPLE_PMGR_PS_MIN       GENMASK(19, 16)
24 #define APPLE_PMGR_PARENT_OFF   BIT(11)
25 #define APPLE_PMGR_DEV_DISABLE  BIT(10)
26 #define APPLE_PMGR_WAS_CLKGATED BIT(9)
27 #define APPLE_PMGR_WAS_PWRGATED BIT(8)
28 #define APPLE_PMGR_PS_ACTUAL    GENMASK(7, 4)
29 #define APPLE_PMGR_PS_TARGET    GENMASK(3, 0)
30
31 #define APPLE_PMGR_FLAGS        (APPLE_PMGR_WAS_CLKGATED | APPLE_PMGR_WAS_PWRGATED)
32
33 #define APPLE_PMGR_PS_ACTIVE    0xf
34 #define APPLE_PMGR_PS_CLKGATE   0x4
35 #define APPLE_PMGR_PS_PWRGATE   0x0
36
37 #define APPLE_PMGR_PS_SET_TIMEOUT 100
38 #define APPLE_PMGR_RESET_TIME 1
39
40 struct apple_pmgr_ps {
41         struct device *dev;
42         struct generic_pm_domain genpd;
43         struct reset_controller_dev rcdev;
44         struct regmap *regmap;
45         u32 offset;
46         u32 min_state;
47 };
48
49 #define genpd_to_apple_pmgr_ps(_genpd) container_of(_genpd, struct apple_pmgr_ps, genpd)
50 #define rcdev_to_apple_pmgr_ps(_rcdev) container_of(_rcdev, struct apple_pmgr_ps, rcdev)
51
52 static int apple_pmgr_ps_set(struct generic_pm_domain *genpd, u32 pstate, bool auto_enable)
53 {
54         int ret;
55         struct apple_pmgr_ps *ps = genpd_to_apple_pmgr_ps(genpd);
56         u32 reg;
57
58         ret = regmap_read(ps->regmap, ps->offset, &reg);
59         if (ret < 0)
60                 return ret;
61
62         /* Resets are synchronous, and only work if the device is powered and clocked. */
63         if (reg & APPLE_PMGR_RESET && pstate != APPLE_PMGR_PS_ACTIVE)
64                 dev_err(ps->dev, "PS %s: powering off with RESET active\n",
65                         genpd->name);
66
67         reg &= ~(APPLE_PMGR_AUTO_ENABLE | APPLE_PMGR_FLAGS | APPLE_PMGR_PS_TARGET);
68         reg |= FIELD_PREP(APPLE_PMGR_PS_TARGET, pstate);
69
70         dev_dbg(ps->dev, "PS %s: pwrstate = 0x%x: 0x%x\n", genpd->name, pstate, reg);
71
72         regmap_write(ps->regmap, ps->offset, reg);
73
74         ret = regmap_read_poll_timeout_atomic(
75                 ps->regmap, ps->offset, reg,
76                 (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == pstate), 1,
77                 APPLE_PMGR_PS_SET_TIMEOUT);
78         if (ret < 0)
79                 dev_err(ps->dev, "PS %s: Failed to reach power state 0x%x (now: 0x%x)\n",
80                         genpd->name, pstate, reg);
81
82         if (auto_enable) {
83                 /* Not all devices implement this; this is a no-op where not implemented. */
84                 reg &= ~APPLE_PMGR_FLAGS;
85                 reg |= APPLE_PMGR_AUTO_ENABLE;
86                 regmap_write(ps->regmap, ps->offset, reg);
87         }
88
89         return ret;
90 }
91
92 static bool apple_pmgr_ps_is_active(struct apple_pmgr_ps *ps)
93 {
94         u32 reg = 0;
95
96         regmap_read(ps->regmap, ps->offset, &reg);
97         /*
98          * We consider domains as active if they are actually on, or if they have auto-PM
99          * enabled and the intended target is on.
100          */
101         return (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == APPLE_PMGR_PS_ACTIVE ||
102                 (FIELD_GET(APPLE_PMGR_PS_TARGET, reg) == APPLE_PMGR_PS_ACTIVE &&
103                  reg & APPLE_PMGR_AUTO_ENABLE));
104 }
105
106 static int apple_pmgr_ps_power_on(struct generic_pm_domain *genpd)
107 {
108         return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_ACTIVE, true);
109 }
110
111 static int apple_pmgr_ps_power_off(struct generic_pm_domain *genpd)
112 {
113         return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_PWRGATE, false);
114 }
115
116 static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
117 {
118         struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
119
120         mutex_lock(&ps->genpd.mlock);
121
122         if (ps->genpd.status == GENPD_STATE_OFF)
123                 dev_err(ps->dev, "PS 0x%x: asserting RESET while powered down\n", ps->offset);
124
125         dev_dbg(ps->dev, "PS 0x%x: assert reset\n", ps->offset);
126         /* Quiesce device before asserting reset */
127         regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE,
128                            APPLE_PMGR_DEV_DISABLE);
129         regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET,
130                            APPLE_PMGR_RESET);
131
132         mutex_unlock(&ps->genpd.mlock);
133
134         return 0;
135 }
136
137 static int apple_pmgr_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
138 {
139         struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
140
141         mutex_lock(&ps->genpd.mlock);
142
143         dev_dbg(ps->dev, "PS 0x%x: deassert reset\n", ps->offset);
144         regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0);
145         regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, 0);
146
147         if (ps->genpd.status == GENPD_STATE_OFF)
148                 dev_err(ps->dev, "PS 0x%x: RESET was deasserted while powered down\n", ps->offset);
149
150         mutex_unlock(&ps->genpd.mlock);
151
152         return 0;
153 }
154
155 static int apple_pmgr_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
156 {
157         int ret;
158
159         ret = apple_pmgr_reset_assert(rcdev, id);
160         if (ret)
161                 return ret;
162
163         usleep_range(APPLE_PMGR_RESET_TIME, 2 * APPLE_PMGR_RESET_TIME);
164
165         return apple_pmgr_reset_deassert(rcdev, id);
166 }
167
168 static int apple_pmgr_reset_status(struct reset_controller_dev *rcdev, unsigned long id)
169 {
170         struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
171         u32 reg = 0;
172
173         regmap_read(ps->regmap, ps->offset, &reg);
174
175         return !!(reg & APPLE_PMGR_RESET);
176 }
177
178 const struct reset_control_ops apple_pmgr_reset_ops = {
179         .assert         = apple_pmgr_reset_assert,
180         .deassert       = apple_pmgr_reset_deassert,
181         .reset          = apple_pmgr_reset_reset,
182         .status         = apple_pmgr_reset_status,
183 };
184
185 static int apple_pmgr_reset_xlate(struct reset_controller_dev *rcdev,
186                                   const struct of_phandle_args *reset_spec)
187 {
188         return 0;
189 }
190
191 static int apple_pmgr_ps_probe(struct platform_device *pdev)
192 {
193         struct device *dev = &pdev->dev;
194         struct device_node *node = dev->of_node;
195         struct apple_pmgr_ps *ps;
196         struct regmap *regmap;
197         struct of_phandle_iterator it;
198         int ret;
199         const char *name;
200         bool active;
201
202         regmap = syscon_node_to_regmap(node->parent);
203         if (IS_ERR(regmap))
204                 return PTR_ERR(regmap);
205
206         ps = devm_kzalloc(dev, sizeof(*ps), GFP_KERNEL);
207         if (!ps)
208                 return -ENOMEM;
209
210         ps->dev = dev;
211         ps->regmap = regmap;
212
213         ret = of_property_read_string(node, "label", &name);
214         if (ret < 0) {
215                 dev_err(dev, "missing label property\n");
216                 return ret;
217         }
218
219         ret = of_property_read_u32(node, "reg", &ps->offset);
220         if (ret < 0) {
221                 dev_err(dev, "missing reg property\n");
222                 return ret;
223         }
224
225         ps->genpd.name = name;
226         ps->genpd.power_on = apple_pmgr_ps_power_on;
227         ps->genpd.power_off = apple_pmgr_ps_power_off;
228
229         ret = of_property_read_u32(node, "apple,min-state", &ps->min_state);
230         if (ret == 0 && ps->min_state <= APPLE_PMGR_PS_ACTIVE)
231                 regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_PS_MIN,
232                                    FIELD_PREP(APPLE_PMGR_PS_MIN, ps->min_state));
233
234         active = apple_pmgr_ps_is_active(ps);
235         if (of_property_read_bool(node, "apple,always-on")) {
236                 ps->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
237                 if (!active) {
238                         dev_warn(dev, "always-on domain %s is not on at boot\n", name);
239                         /* Turn it on so pm_genpd_init does not fail */
240                         active = apple_pmgr_ps_power_on(&ps->genpd) == 0;
241                 }
242         }
243
244         /* Turn on auto-PM if the domain is already on */
245         if (active)
246                 regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_AUTO_ENABLE,
247                                    APPLE_PMGR_AUTO_ENABLE);
248
249         ret = pm_genpd_init(&ps->genpd, NULL, !active);
250         if (ret < 0) {
251                 dev_err(dev, "pm_genpd_init failed\n");
252                 return ret;
253         }
254
255         ret = of_genpd_add_provider_simple(node, &ps->genpd);
256         if (ret < 0) {
257                 dev_err(dev, "of_genpd_add_provider_simple failed\n");
258                 return ret;
259         }
260
261         of_for_each_phandle(&it, ret, node, "power-domains", "#power-domain-cells", -1) {
262                 struct of_phandle_args parent, child;
263
264                 parent.np = it.node;
265                 parent.args_count = of_phandle_iterator_args(&it, parent.args, MAX_PHANDLE_ARGS);
266                 child.np = node;
267                 child.args_count = 0;
268                 ret = of_genpd_add_subdomain(&parent, &child);
269
270                 if (ret == -EPROBE_DEFER) {
271                         of_node_put(parent.np);
272                         goto err_remove;
273                 } else if (ret < 0) {
274                         dev_err(dev, "failed to add to parent domain: %d (%s -> %s)\n",
275                                 ret, it.node->name, node->name);
276                         of_node_put(parent.np);
277                         goto err_remove;
278                 }
279         }
280
281         /*
282          * Do not participate in regular PM; parent power domains are handled via the
283          * genpd hierarchy.
284          */
285         pm_genpd_remove_device(dev);
286
287         ps->rcdev.owner = THIS_MODULE;
288         ps->rcdev.nr_resets = 1;
289         ps->rcdev.ops = &apple_pmgr_reset_ops;
290         ps->rcdev.of_node = dev->of_node;
291         ps->rcdev.of_reset_n_cells = 0;
292         ps->rcdev.of_xlate = apple_pmgr_reset_xlate;
293
294         ret = devm_reset_controller_register(dev, &ps->rcdev);
295         if (ret < 0)
296                 goto err_remove;
297
298         return 0;
299 err_remove:
300         of_genpd_del_provider(node);
301         pm_genpd_remove(&ps->genpd);
302         return ret;
303 }
304
305 static const struct of_device_id apple_pmgr_ps_of_match[] = {
306         { .compatible = "apple,pmgr-pwrstate" },
307         {}
308 };
309
310 MODULE_DEVICE_TABLE(of, apple_pmgr_ps_of_match);
311
312 static struct platform_driver apple_pmgr_ps_driver = {
313         .probe = apple_pmgr_ps_probe,
314         .driver = {
315                 .name = "apple-pmgr-pwrstate",
316                 .of_match_table = apple_pmgr_ps_of_match,
317         },
318 };
319
320 MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
321 MODULE_DESCRIPTION("PMGR power state driver for Apple SoCs");
322 MODULE_LICENSE("GPL v2");
323
324 module_platform_driver(apple_pmgr_ps_driver);