aboutsummaryrefslogtreecommitdiff
path: root/drivers/power/domain/apple-pmgr.c
blob: 4d06e76ff5e5ca57ba3f8d50e72de3bf8776a23c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2021 Mark Kettenis <kettenis@openbsd.org>
 */

#include <common.h>
#include <asm/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <linux/err.h>
#include <linux/bitfield.h>
#include <power-domain-uclass.h>
#include <reset-uclass.h>
#include <regmap.h>
#include <syscon.h>

#define APPLE_PMGR_RESET	BIT(31)
#define APPLE_PMGR_DEV_DISABLE	BIT(10)
#define APPLE_PMGR_WAS_CLKGATED	BIT(9)
#define APPLE_PMGR_WAS_PWRGATED BIT(8)
#define APPLE_PMGR_PS_ACTUAL	GENMASK(7, 4)
#define APPLE_PMGR_PS_TARGET	GENMASK(3, 0)

#define APPLE_PMGR_FLAGS	(APPLE_PMGR_WAS_CLKGATED | APPLE_PMGR_WAS_PWRGATED)

#define APPLE_PMGR_PS_ACTIVE	0xf
#define APPLE_PMGR_PS_PWRGATE	0x0

#define APPLE_PMGR_PS_SET_TIMEOUT_US	100

struct apple_pmgr_priv {
	struct regmap *regmap;
	u32 offset;		/* offset within regmap for this domain */
};

static int apple_reset_of_xlate(struct reset_ctl *reset_ctl,
				struct ofnode_phandle_args *args)
{
	if (args->args_count != 0)
		return -EINVAL;

	return 0;
}

static int apple_reset_request(struct reset_ctl *reset_ctl)
{
	return 0;
}

static int apple_reset_free(struct reset_ctl *reset_ctl)
{
	return 0;
}

static int apple_reset_assert(struct reset_ctl *reset_ctl)
{
	struct apple_pmgr_priv *priv = dev_get_priv(reset_ctl->dev->parent);

	regmap_update_bits(priv->regmap, priv->offset,
			   APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE,
			   APPLE_PMGR_DEV_DISABLE);
	regmap_update_bits(priv->regmap, priv->offset,
			   APPLE_PMGR_FLAGS | APPLE_PMGR_RESET,
			   APPLE_PMGR_RESET);

	return 0;
}

static int apple_reset_deassert(struct reset_ctl *reset_ctl)
{
	struct apple_pmgr_priv *priv = dev_get_priv(reset_ctl->dev->parent);

	regmap_update_bits(priv->regmap, priv->offset,
			   APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0);
	regmap_update_bits(priv->regmap, priv->offset,
			   APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, 0);

	return 0;
}

struct reset_ops apple_reset_ops = {
	.of_xlate = apple_reset_of_xlate,
	.request = apple_reset_request,
	.rfree = apple_reset_free,
	.rst_assert = apple_reset_assert,
	.rst_deassert = apple_reset_deassert,
};

static struct driver apple_reset_driver = {
	.name = "apple_reset",
	.id = UCLASS_RESET,
	.ops = &apple_reset_ops,
};

static int apple_pmgr_request(struct power_domain *power_domain)
{
	return 0;
}

static int apple_pmgr_rfree(struct power_domain *power_domain)
{
	return 0;
}

static int apple_pmgr_ps_set(struct power_domain *power_domain, u32 pstate)
{
	struct apple_pmgr_priv *priv = dev_get_priv(power_domain->dev);
	uint reg;

	regmap_update_bits(priv->regmap, priv->offset, APPLE_PMGR_PS_TARGET,
			   FIELD_PREP(APPLE_PMGR_PS_TARGET, pstate));

	return regmap_read_poll_timeout(
		priv->regmap, priv->offset, reg,
		(FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == pstate), 1,
		APPLE_PMGR_PS_SET_TIMEOUT_US);
}

static int apple_pmgr_on(struct power_domain *power_domain)
{
	return apple_pmgr_ps_set(power_domain, APPLE_PMGR_PS_ACTIVE);
}

static int apple_pmgr_off(struct power_domain *power_domain)
{
	return 0;
}

static int apple_pmgr_of_xlate(struct power_domain *power_domain,
			       struct ofnode_phandle_args *args)
{
	if (args->args_count != 0) {
		debug("Invalid args_count: %d\n", args->args_count);
		return -EINVAL;
	}

	return 0;
}

static const struct udevice_id apple_pmgr_ids[] = {
	{ .compatible = "apple,pmgr-pwrstate" },
	{ /* sentinel */ }
};

static int apple_pmgr_probe(struct udevice *dev)
{
	struct apple_pmgr_priv *priv = dev_get_priv(dev);
	struct udevice *child;
	int ret;

	ret = dev_power_domain_on(dev);
	if (ret)
		return ret;

	priv->regmap = syscon_get_regmap(dev->parent);
	if (IS_ERR(priv->regmap))
		return PTR_ERR(priv->regmap);

	ret = dev_read_u32(dev, "reg", &priv->offset);
	if (ret < 0)
		return ret;

	device_bind(dev, &apple_reset_driver, "apple_reset", NULL,
		    dev_ofnode(dev), &child);

	return 0;
}

struct power_domain_ops apple_pmgr_ops = {
	.request = apple_pmgr_request,
	.rfree = apple_pmgr_rfree,
	.on = apple_pmgr_on,
	.off = apple_pmgr_off,
	.of_xlate = apple_pmgr_of_xlate,
};

U_BOOT_DRIVER(apple_pmgr) = {
	.name = "apple_pmgr",
	.id = UCLASS_POWER_DOMAIN,
	.of_match = apple_pmgr_ids,
	.ops = &apple_pmgr_ops,
	.probe = apple_pmgr_probe,
	.priv_auto = sizeof(struct apple_pmgr_priv),
};