Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  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
 40struct 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
 52static 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
 92static 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
106static 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
111static 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
116static 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
138static 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
157static 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
170static 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
180static 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
187static int apple_pmgr_reset_xlate(struct reset_controller_dev *rcdev,
188				  const struct of_phandle_args *reset_spec)
189{
190	return 0;
191}
192
193static 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;
302err_remove:
303	of_genpd_del_provider(node);
304	pm_genpd_remove(&ps->genpd);
305	return ret;
306}
307
308static const struct of_device_id apple_pmgr_ps_of_match[] = {
309	{ .compatible = "apple,pmgr-pwrstate" },
310	{}
311};
312
313MODULE_DEVICE_TABLE(of, apple_pmgr_ps_of_match);
314
315static 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
323MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
324MODULE_DESCRIPTION("PMGR power state driver for Apple SoCs");
325
326module_platform_driver(apple_pmgr_ps_driver);