xref: /linux/drivers/soc/apple/apple-pmgr-misc.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1*fef9350cSHector Martin // SPDX-License-Identifier: GPL-2.0-only OR MIT
2*fef9350cSHector Martin /*
3*fef9350cSHector Martin  * Apple SoC PMGR device power state driver
4*fef9350cSHector Martin  *
5*fef9350cSHector Martin  * Copyright The Asahi Linux Contributors
6*fef9350cSHector Martin  */
7*fef9350cSHector Martin 
8*fef9350cSHector Martin #include <linux/bitfield.h>
9*fef9350cSHector Martin #include <linux/bitops.h>
10*fef9350cSHector Martin #include <linux/err.h>
11*fef9350cSHector Martin #include <linux/io.h>
12*fef9350cSHector Martin #include <linux/module.h>
13*fef9350cSHector Martin #include <linux/of.h>
14*fef9350cSHector Martin #include <linux/platform_device.h>
15*fef9350cSHector Martin 
16*fef9350cSHector Martin #define APPLE_CLKGEN_PSTATE 0
17*fef9350cSHector Martin #define APPLE_CLKGEN_PSTATE_DESIRED GENMASK(3, 0)
18*fef9350cSHector Martin 
19*fef9350cSHector Martin #define DCS_DEV_PSTATE_MIN_T600X 7
20*fef9350cSHector Martin #define SYS_DEV_PSTATE_SUSPEND 1
21*fef9350cSHector Martin 
22*fef9350cSHector Martin enum sys_device {
23*fef9350cSHector Martin 	DEV_FABRIC,
24*fef9350cSHector Martin 	DEV_DCS,
25*fef9350cSHector Martin 	DEV_MAX,
26*fef9350cSHector Martin };
27*fef9350cSHector Martin 
28*fef9350cSHector Martin struct apple_pmgr_sys_device {
29*fef9350cSHector Martin 	void __iomem *base;
30*fef9350cSHector Martin 	u32 active_state;
31*fef9350cSHector Martin 	u32 suspend_state;
32*fef9350cSHector Martin };
33*fef9350cSHector Martin 
34*fef9350cSHector Martin struct apple_pmgr_misc_hw {
35*fef9350cSHector Martin 	u32 dev_min_ps[DEV_MAX];
36*fef9350cSHector Martin };
37*fef9350cSHector Martin 
38*fef9350cSHector Martin struct apple_pmgr_misc {
39*fef9350cSHector Martin 	struct device *dev;
40*fef9350cSHector Martin 	struct apple_pmgr_sys_device devices[DEV_MAX];
41*fef9350cSHector Martin };
42*fef9350cSHector Martin 
43*fef9350cSHector Martin static void apple_pmgr_sys_dev_set_pstate(struct apple_pmgr_misc *misc,
44*fef9350cSHector Martin 					  enum sys_device dev, bool active)
45*fef9350cSHector Martin {
46*fef9350cSHector Martin 	u32 pstate;
47*fef9350cSHector Martin 	u32 val;
48*fef9350cSHector Martin 
49*fef9350cSHector Martin 	if (!misc->devices[dev].base)
50*fef9350cSHector Martin 		return;
51*fef9350cSHector Martin 
52*fef9350cSHector Martin 	if (active)
53*fef9350cSHector Martin 		pstate = misc->devices[dev].active_state;
54*fef9350cSHector Martin 	else
55*fef9350cSHector Martin 		pstate = misc->devices[dev].suspend_state;
56*fef9350cSHector Martin 
57*fef9350cSHector Martin 	dev_dbg(misc->dev, "set %d ps to pstate %d\n", dev, pstate);
58*fef9350cSHector Martin 
59*fef9350cSHector Martin 	val = readl_relaxed(misc->devices[dev].base + APPLE_CLKGEN_PSTATE);
60*fef9350cSHector Martin 	FIELD_MODIFY(APPLE_CLKGEN_PSTATE_DESIRED, &val, pstate);
61*fef9350cSHector Martin 	writel_relaxed(val, misc->devices[dev].base + APPLE_CLKGEN_PSTATE);
62*fef9350cSHector Martin }
63*fef9350cSHector Martin 
64*fef9350cSHector Martin static int __maybe_unused apple_pmgr_misc_suspend_noirq(struct device *dev)
65*fef9350cSHector Martin {
66*fef9350cSHector Martin 	struct apple_pmgr_misc *misc = dev_get_drvdata(dev);
67*fef9350cSHector Martin 	int i;
68*fef9350cSHector Martin 
69*fef9350cSHector Martin 	for (i = 0; i < DEV_MAX; i++)
70*fef9350cSHector Martin 		apple_pmgr_sys_dev_set_pstate(misc, i, false);
71*fef9350cSHector Martin 
72*fef9350cSHector Martin 	return 0;
73*fef9350cSHector Martin }
74*fef9350cSHector Martin 
75*fef9350cSHector Martin static int __maybe_unused apple_pmgr_misc_resume_noirq(struct device *dev)
76*fef9350cSHector Martin {
77*fef9350cSHector Martin 	struct apple_pmgr_misc *misc = dev_get_drvdata(dev);
78*fef9350cSHector Martin 	int i;
79*fef9350cSHector Martin 
80*fef9350cSHector Martin 	for (i = 0; i < DEV_MAX; i++)
81*fef9350cSHector Martin 		apple_pmgr_sys_dev_set_pstate(misc, i, true);
82*fef9350cSHector Martin 
83*fef9350cSHector Martin 	return 0;
84*fef9350cSHector Martin }
85*fef9350cSHector Martin 
86*fef9350cSHector Martin static int apple_pmgr_init_device(struct apple_pmgr_misc *misc,
87*fef9350cSHector Martin 				  const struct apple_pmgr_misc_hw *hw,
88*fef9350cSHector Martin 				  enum sys_device dev,
89*fef9350cSHector Martin 				  const char *device_name)
90*fef9350cSHector Martin {
91*fef9350cSHector Martin 	void __iomem *base;
92*fef9350cSHector Martin 	char name[32];
93*fef9350cSHector Martin 	u32 val;
94*fef9350cSHector Martin 
95*fef9350cSHector Martin 	snprintf(name, sizeof(name), "%s-ps", device_name);
96*fef9350cSHector Martin 
97*fef9350cSHector Martin 	base = devm_platform_ioremap_resource_byname(
98*fef9350cSHector Martin 		to_platform_device(misc->dev), name);
99*fef9350cSHector Martin 	if (IS_ERR(base))
100*fef9350cSHector Martin 		return PTR_ERR(base);
101*fef9350cSHector Martin 
102*fef9350cSHector Martin 	val = readl_relaxed(base + APPLE_CLKGEN_PSTATE);
103*fef9350cSHector Martin 
104*fef9350cSHector Martin 	misc->devices[dev].base = base;
105*fef9350cSHector Martin 	misc->devices[dev].active_state =
106*fef9350cSHector Martin 		FIELD_GET(APPLE_CLKGEN_PSTATE_DESIRED, val);
107*fef9350cSHector Martin 	misc->devices[dev].suspend_state = hw->dev_min_ps[dev];
108*fef9350cSHector Martin 
109*fef9350cSHector Martin 	return 0;
110*fef9350cSHector Martin }
111*fef9350cSHector Martin 
112*fef9350cSHector Martin static int apple_pmgr_misc_probe(struct platform_device *pdev)
113*fef9350cSHector Martin {
114*fef9350cSHector Martin 	struct device *dev = &pdev->dev;
115*fef9350cSHector Martin 	const struct apple_pmgr_misc_hw *hw;
116*fef9350cSHector Martin 	struct apple_pmgr_misc *misc;
117*fef9350cSHector Martin 	int ret;
118*fef9350cSHector Martin 
119*fef9350cSHector Martin 	misc = devm_kzalloc(dev, sizeof(*misc), GFP_KERNEL);
120*fef9350cSHector Martin 	if (!misc)
121*fef9350cSHector Martin 		return -ENOMEM;
122*fef9350cSHector Martin 
123*fef9350cSHector Martin 	misc->dev = dev;
124*fef9350cSHector Martin 	hw = of_device_get_match_data(dev);
125*fef9350cSHector Martin 	if (!hw)
126*fef9350cSHector Martin 		return -EINVAL;
127*fef9350cSHector Martin 
128*fef9350cSHector Martin 	ret = apple_pmgr_init_device(misc, hw, DEV_FABRIC, "fabric");
129*fef9350cSHector Martin 	if (ret)
130*fef9350cSHector Martin 		return ret;
131*fef9350cSHector Martin 
132*fef9350cSHector Martin 	ret = apple_pmgr_init_device(misc, hw, DEV_DCS, "dcs");
133*fef9350cSHector Martin 	if (ret)
134*fef9350cSHector Martin 		return ret;
135*fef9350cSHector Martin 
136*fef9350cSHector Martin 	platform_set_drvdata(pdev, misc);
137*fef9350cSHector Martin 
138*fef9350cSHector Martin 	return 0;
139*fef9350cSHector Martin }
140*fef9350cSHector Martin 
141*fef9350cSHector Martin static const struct apple_pmgr_misc_hw apple_pmgr_misc_hw_t600x = {
142*fef9350cSHector Martin 	.dev_min_ps = {
143*fef9350cSHector Martin 		[DEV_FABRIC] = SYS_DEV_PSTATE_SUSPEND,
144*fef9350cSHector Martin 		[DEV_DCS] = DCS_DEV_PSTATE_MIN_T600X,
145*fef9350cSHector Martin 	},
146*fef9350cSHector Martin };
147*fef9350cSHector Martin 
148*fef9350cSHector Martin static const struct apple_pmgr_misc_hw apple_pmgr_misc_hw_t602x = {
149*fef9350cSHector Martin 	.dev_min_ps = {
150*fef9350cSHector Martin 		[DEV_FABRIC] = SYS_DEV_PSTATE_SUSPEND,
151*fef9350cSHector Martin 		[DEV_DCS] = SYS_DEV_PSTATE_SUSPEND,
152*fef9350cSHector Martin 	},
153*fef9350cSHector Martin };
154*fef9350cSHector Martin 
155*fef9350cSHector Martin static const struct of_device_id apple_pmgr_misc_of_match[] = {
156*fef9350cSHector Martin 	{ .compatible = "apple,t6000-pmgr-misc", .data = &apple_pmgr_misc_hw_t600x },
157*fef9350cSHector Martin 	{ .compatible = "apple,t6020-pmgr-misc", .data = &apple_pmgr_misc_hw_t602x },
158*fef9350cSHector Martin 	{}
159*fef9350cSHector Martin };
160*fef9350cSHector Martin 
161*fef9350cSHector Martin MODULE_DEVICE_TABLE(of, apple_pmgr_misc_of_match);
162*fef9350cSHector Martin 
163*fef9350cSHector Martin static const struct dev_pm_ops apple_pmgr_misc_pm_ops = {
164*fef9350cSHector Martin 	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(apple_pmgr_misc_suspend_noirq,
165*fef9350cSHector Martin 				      apple_pmgr_misc_resume_noirq)
166*fef9350cSHector Martin };
167*fef9350cSHector Martin 
168*fef9350cSHector Martin static struct platform_driver apple_pmgr_misc_driver = {
169*fef9350cSHector Martin 	.probe = apple_pmgr_misc_probe,
170*fef9350cSHector Martin 	.driver = {
171*fef9350cSHector Martin 		.name = "apple-pmgr-misc",
172*fef9350cSHector Martin 		.of_match_table = apple_pmgr_misc_of_match,
173*fef9350cSHector Martin 		.pm = pm_ptr(&apple_pmgr_misc_pm_ops),
174*fef9350cSHector Martin 	},
175*fef9350cSHector Martin };
176*fef9350cSHector Martin 
177*fef9350cSHector Martin MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
178*fef9350cSHector Martin MODULE_DESCRIPTION("PMGR misc driver for Apple SoCs");
179*fef9350cSHector Martin MODULE_LICENSE("GPL");
180*fef9350cSHector Martin 
181*fef9350cSHector Martin module_platform_driver(apple_pmgr_misc_driver);
182