cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

apple-pmgr-pwrstate.c (9161B)


      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
    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
    137static 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
    155static 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
    168static 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
    178const 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
    185static int apple_pmgr_reset_xlate(struct reset_controller_dev *rcdev,
    186				  const struct of_phandle_args *reset_spec)
    187{
    188	return 0;
    189}
    190
    191static 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;
    299err_remove:
    300	of_genpd_del_provider(node);
    301	pm_genpd_remove(&ps->genpd);
    302	return ret;
    303}
    304
    305static const struct of_device_id apple_pmgr_ps_of_match[] = {
    306	{ .compatible = "apple,pmgr-pwrstate" },
    307	{}
    308};
    309
    310MODULE_DEVICE_TABLE(of, apple_pmgr_ps_of_match);
    311
    312static 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
    320MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
    321MODULE_DESCRIPTION("PMGR power state driver for Apple SoCs");
    322MODULE_LICENSE("GPL v2");
    323
    324module_platform_driver(apple_pmgr_ps_driver);