xref: /linux/drivers/pmdomain/apple/pmgr-pwrstate.c (revision 06a130e42a5bfc84795464bff023bff4c16f58c5)
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 	unsigned long flags;
120 
121 	spin_lock_irqsave(&ps->genpd.slock, flags);
122 
123 	if (ps->genpd.status == GENPD_STATE_OFF)
124 		dev_err(ps->dev, "PS 0x%x: asserting RESET while powered down\n", ps->offset);
125 
126 	dev_dbg(ps->dev, "PS 0x%x: assert reset\n", ps->offset);
127 	/* Quiesce device before asserting reset */
128 	regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE,
129 			   APPLE_PMGR_DEV_DISABLE);
130 	regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET,
131 			   APPLE_PMGR_RESET);
132 
133 	spin_unlock_irqrestore(&ps->genpd.slock, flags);
134 
135 	return 0;
136 }
137 
138 static int apple_pmgr_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
139 {
140 	struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
141 	unsigned long flags;
142 
143 	spin_lock_irqsave(&ps->genpd.slock, flags);
144 
145 	dev_dbg(ps->dev, "PS 0x%x: deassert reset\n", ps->offset);
146 	regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0);
147 	regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, 0);
148 
149 	if (ps->genpd.status == GENPD_STATE_OFF)
150 		dev_err(ps->dev, "PS 0x%x: RESET was deasserted while powered down\n", ps->offset);
151 
152 	spin_unlock_irqrestore(&ps->genpd.slock, flags);
153 
154 	return 0;
155 }
156 
157 static int apple_pmgr_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
158 {
159 	int ret;
160 
161 	ret = apple_pmgr_reset_assert(rcdev, id);
162 	if (ret)
163 		return ret;
164 
165 	usleep_range(APPLE_PMGR_RESET_TIME, 2 * APPLE_PMGR_RESET_TIME);
166 
167 	return apple_pmgr_reset_deassert(rcdev, id);
168 }
169 
170 static int apple_pmgr_reset_status(struct reset_controller_dev *rcdev, unsigned long id)
171 {
172 	struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev);
173 	u32 reg = 0;
174 
175 	regmap_read(ps->regmap, ps->offset, &reg);
176 
177 	return !!(reg & APPLE_PMGR_RESET);
178 }
179 
180 static const struct reset_control_ops apple_pmgr_reset_ops = {
181 	.assert		= apple_pmgr_reset_assert,
182 	.deassert	= apple_pmgr_reset_deassert,
183 	.reset		= apple_pmgr_reset_reset,
184 	.status		= apple_pmgr_reset_status,
185 };
186 
187 static int apple_pmgr_reset_xlate(struct reset_controller_dev *rcdev,
188 				  const struct of_phandle_args *reset_spec)
189 {
190 	return 0;
191 }
192 
193 static int apple_pmgr_ps_probe(struct platform_device *pdev)
194 {
195 	struct device *dev = &pdev->dev;
196 	struct device_node *node = dev->of_node;
197 	struct apple_pmgr_ps *ps;
198 	struct regmap *regmap;
199 	struct of_phandle_iterator it;
200 	int ret;
201 	const char *name;
202 	bool active;
203 
204 	regmap = syscon_node_to_regmap(node->parent);
205 	if (IS_ERR(regmap))
206 		return PTR_ERR(regmap);
207 
208 	ps = devm_kzalloc(dev, sizeof(*ps), GFP_KERNEL);
209 	if (!ps)
210 		return -ENOMEM;
211 
212 	ps->dev = dev;
213 	ps->regmap = regmap;
214 
215 	ret = of_property_read_string(node, "label", &name);
216 	if (ret < 0) {
217 		dev_err(dev, "missing label property\n");
218 		return ret;
219 	}
220 
221 	ret = of_property_read_u32(node, "reg", &ps->offset);
222 	if (ret < 0) {
223 		dev_err(dev, "missing reg property\n");
224 		return ret;
225 	}
226 
227 	ps->genpd.flags |= GENPD_FLAG_IRQ_SAFE;
228 	ps->genpd.name = name;
229 	ps->genpd.power_on = apple_pmgr_ps_power_on;
230 	ps->genpd.power_off = apple_pmgr_ps_power_off;
231 
232 	ret = of_property_read_u32(node, "apple,min-state", &ps->min_state);
233 	if (ret == 0 && ps->min_state <= APPLE_PMGR_PS_ACTIVE)
234 		regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_PS_MIN,
235 				   FIELD_PREP(APPLE_PMGR_PS_MIN, ps->min_state));
236 
237 	active = apple_pmgr_ps_is_active(ps);
238 	if (of_property_read_bool(node, "apple,always-on")) {
239 		ps->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
240 		if (!active) {
241 			dev_warn(dev, "always-on domain %s is not on at boot\n", name);
242 			/* Turn it on so pm_genpd_init does not fail */
243 			active = apple_pmgr_ps_power_on(&ps->genpd) == 0;
244 		}
245 	}
246 
247 	/* Turn on auto-PM if the domain is already on */
248 	if (active)
249 		regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_AUTO_ENABLE,
250 				   APPLE_PMGR_AUTO_ENABLE);
251 
252 	ret = pm_genpd_init(&ps->genpd, NULL, !active);
253 	if (ret < 0) {
254 		dev_err(dev, "pm_genpd_init failed\n");
255 		return ret;
256 	}
257 
258 	ret = of_genpd_add_provider_simple(node, &ps->genpd);
259 	if (ret < 0) {
260 		dev_err(dev, "of_genpd_add_provider_simple failed\n");
261 		return ret;
262 	}
263 
264 	of_for_each_phandle(&it, ret, node, "power-domains", "#power-domain-cells", -1) {
265 		struct of_phandle_args parent, child;
266 
267 		parent.np = it.node;
268 		parent.args_count = of_phandle_iterator_args(&it, parent.args, MAX_PHANDLE_ARGS);
269 		child.np = node;
270 		child.args_count = 0;
271 		ret = of_genpd_add_subdomain(&parent, &child);
272 
273 		if (ret == -EPROBE_DEFER) {
274 			of_node_put(parent.np);
275 			goto err_remove;
276 		} else if (ret < 0) {
277 			dev_err(dev, "failed to add to parent domain: %d (%s -> %s)\n",
278 				ret, it.node->name, node->name);
279 			of_node_put(parent.np);
280 			goto err_remove;
281 		}
282 	}
283 
284 	/*
285 	 * Do not participate in regular PM; parent power domains are handled via the
286 	 * genpd hierarchy.
287 	 */
288 	pm_genpd_remove_device(dev);
289 
290 	ps->rcdev.owner = THIS_MODULE;
291 	ps->rcdev.nr_resets = 1;
292 	ps->rcdev.ops = &apple_pmgr_reset_ops;
293 	ps->rcdev.of_node = dev->of_node;
294 	ps->rcdev.of_reset_n_cells = 0;
295 	ps->rcdev.of_xlate = apple_pmgr_reset_xlate;
296 
297 	ret = devm_reset_controller_register(dev, &ps->rcdev);
298 	if (ret < 0)
299 		goto err_remove;
300 
301 	return 0;
302 err_remove:
303 	of_genpd_del_provider(node);
304 	pm_genpd_remove(&ps->genpd);
305 	return ret;
306 }
307 
308 static const struct of_device_id apple_pmgr_ps_of_match[] = {
309 	{ .compatible = "apple,pmgr-pwrstate" },
310 	{}
311 };
312 
313 MODULE_DEVICE_TABLE(of, apple_pmgr_ps_of_match);
314 
315 static struct platform_driver apple_pmgr_ps_driver = {
316 	.probe = apple_pmgr_ps_probe,
317 	.driver = {
318 		.name = "apple-pmgr-pwrstate",
319 		.of_match_table = apple_pmgr_ps_of_match,
320 	},
321 };
322 
323 MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
324 MODULE_DESCRIPTION("PMGR power state driver for Apple SoCs");
325 
326 module_platform_driver(apple_pmgr_ps_driver);
327