1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2021 Mark Kettenis <kettenis@openbsd.org> 4 */ 5 6#include <common.h> 7#include <asm/io.h> 8#include <dm.h> 9#include <dm/device-internal.h> 10#include <linux/err.h> 11#include <linux/bitfield.h> 12#include <power-domain-uclass.h> 13#include <reset-uclass.h> 14#include <regmap.h> 15#include <syscon.h> 16 17#define APPLE_PMGR_RESET BIT(31) 18#define APPLE_PMGR_DEV_DISABLE BIT(10) 19#define APPLE_PMGR_WAS_CLKGATED BIT(9) 20#define APPLE_PMGR_WAS_PWRGATED BIT(8) 21#define APPLE_PMGR_PS_ACTUAL GENMASK(7, 4) 22#define APPLE_PMGR_PS_TARGET GENMASK(3, 0) 23 24#define APPLE_PMGR_FLAGS (APPLE_PMGR_WAS_CLKGATED | APPLE_PMGR_WAS_PWRGATED) 25 26#define APPLE_PMGR_PS_ACTIVE 0xf 27#define APPLE_PMGR_PS_PWRGATE 0x0 28 29#define APPLE_PMGR_PS_SET_TIMEOUT_US 100 30 31struct apple_pmgr_priv { 32 struct regmap *regmap; 33 u32 offset; /* offset within regmap for this domain */ 34}; 35 36static int apple_reset_of_xlate(struct reset_ctl *reset_ctl, 37 struct ofnode_phandle_args *args) 38{ 39 if (args->args_count != 0) 40 return -EINVAL; 41 42 return 0; 43} 44 45static int apple_reset_assert(struct reset_ctl *reset_ctl) 46{ 47 struct apple_pmgr_priv *priv = dev_get_priv(reset_ctl->dev->parent); 48 49 regmap_update_bits(priv->regmap, priv->offset, 50 APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, 51 APPLE_PMGR_DEV_DISABLE); 52 regmap_update_bits(priv->regmap, priv->offset, 53 APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 54 APPLE_PMGR_RESET); 55 56 return 0; 57} 58 59static int apple_reset_deassert(struct reset_ctl *reset_ctl) 60{ 61 struct apple_pmgr_priv *priv = dev_get_priv(reset_ctl->dev->parent); 62 63 regmap_update_bits(priv->regmap, priv->offset, 64 APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0); 65 regmap_update_bits(priv->regmap, priv->offset, 66 APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, 0); 67 68 return 0; 69} 70 71struct reset_ops apple_reset_ops = { 72 .of_xlate = apple_reset_of_xlate, 73 .rst_assert = apple_reset_assert, 74 .rst_deassert = apple_reset_deassert, 75}; 76 77static struct driver apple_reset_driver = { 78 .name = "apple_reset", 79 .id = UCLASS_RESET, 80 .ops = &apple_reset_ops, 81}; 82 83static int apple_pmgr_ps_set(struct power_domain *power_domain, u32 pstate) 84{ 85 struct apple_pmgr_priv *priv = dev_get_priv(power_domain->dev); 86 uint reg; 87 88 regmap_update_bits(priv->regmap, priv->offset, APPLE_PMGR_PS_TARGET, 89 FIELD_PREP(APPLE_PMGR_PS_TARGET, pstate)); 90 91 return regmap_read_poll_timeout( 92 priv->regmap, priv->offset, reg, 93 (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == pstate), 1, 94 APPLE_PMGR_PS_SET_TIMEOUT_US); 95} 96 97static int apple_pmgr_on(struct power_domain *power_domain) 98{ 99 return apple_pmgr_ps_set(power_domain, APPLE_PMGR_PS_ACTIVE); 100} 101 102static int apple_pmgr_of_xlate(struct power_domain *power_domain, 103 struct ofnode_phandle_args *args) 104{ 105 if (args->args_count != 0) { 106 debug("Invalid args_count: %d\n", args->args_count); 107 return -EINVAL; 108 } 109 110 return 0; 111} 112 113static const struct udevice_id apple_pmgr_ids[] = { 114 { .compatible = "apple,pmgr-pwrstate" }, 115 { /* sentinel */ } 116}; 117 118static int apple_pmgr_probe(struct udevice *dev) 119{ 120 struct apple_pmgr_priv *priv = dev_get_priv(dev); 121 struct udevice *child; 122 int ret; 123 124 ret = dev_power_domain_on(dev); 125 if (ret) 126 return ret; 127 128 priv->regmap = syscon_get_regmap(dev->parent); 129 if (IS_ERR(priv->regmap)) 130 return PTR_ERR(priv->regmap); 131 132 ret = dev_read_u32(dev, "reg", &priv->offset); 133 if (ret < 0) 134 return ret; 135 136 device_bind(dev, &apple_reset_driver, "apple_reset", NULL, 137 dev_ofnode(dev), &child); 138 139 return 0; 140} 141 142struct power_domain_ops apple_pmgr_ops = { 143 .on = apple_pmgr_on, 144 .of_xlate = apple_pmgr_of_xlate, 145}; 146 147U_BOOT_DRIVER(apple_pmgr) = { 148 .name = "apple_pmgr", 149 .id = UCLASS_POWER_DOMAIN, 150 .of_match = apple_pmgr_ids, 151 .ops = &apple_pmgr_ops, 152 .probe = apple_pmgr_probe, 153 .priv_auto = sizeof(struct apple_pmgr_priv), 154}; 155