Skip to content

Commit ae59b60

Browse files
svenpeter42jannau
authored andcommitted
soc: apple: Add hardware tunable support
Various hardware, like the Type-C PHY or the Thunderbolt/USB4 NHI, present on Apple SoCs need machine-specific tunables passed from our bootloader m1n1 to the device tree. Add generic helpers so that we don't have to duplicate this across multiple drivers. Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Reviewed-by: Neal Gompa <neal@gompa.dev> Reviewed-by: Janne Grunau <j@jannau.net> Signed-off-by: Sven Peter <sven@kernel.org> Bogus ordering in Kconfig/Makefile to avoid merge conflicts with RUST_APPLE_RTKIT and AOP/SEP from bits/190-rust and bits/250-aop. This is the only workable solution which avoids conflicts with bits/090-spi-hid as well. Signed-off-by: Janne Grunau <j@jannau.net>
1 parent 45c85ee commit ae59b60

4 files changed

Lines changed: 149 additions & 0 deletions

File tree

drivers/soc/apple/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ config APPLE_PMGR_MISC
2424
controls for SoC devices. This driver manages miscellaneous
2525
power controls.
2626

27+
config APPLE_TUNABLE
28+
tristate
29+
depends on ARCH_APPLE || COMPILE_TEST
30+
2731
config APPLE_RTKIT
2832
tristate "Apple RTKit co-processor IPC protocol"
2933
depends on APPLE_MAILBOX

drivers/soc/apple/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ apple-mailbox-y = mailbox.o
55

66
obj-$(CONFIG_APPLE_PMGR_MISC) += apple-pmgr-misc.o
77

8+
obj-$(CONFIG_APPLE_TUNABLE) += apple-tunable.o
9+
apple-tunable-y = tunable.o
10+
811
obj-$(CONFIG_APPLE_RTKIT) += apple-rtkit.o
912
apple-rtkit-y = rtkit.o rtkit-crashlog.o
1013

drivers/soc/apple/tunable.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// SPDX-License-Identifier: GPL-2.0-only OR MIT
2+
/*
3+
* Apple Silicon hardware tunable support
4+
*
5+
* Each tunable is a list with each entry containing a offset into the MMIO
6+
* region, a mask of bits to be cleared and a set of bits to be set. These
7+
* tunables are passed along by the previous boot stages and vary from device
8+
* to device such that they cannot be hardcoded in the individual drivers.
9+
*
10+
* Copyright (C) The Asahi Linux Contributors
11+
*/
12+
13+
#include <linux/io.h>
14+
#include <linux/module.h>
15+
#include <linux/of.h>
16+
#include <linux/overflow.h>
17+
#include <linux/soc/apple/tunable.h>
18+
19+
struct apple_tunable *devm_apple_tunable_parse(struct device *dev,
20+
struct device_node *np,
21+
const char *name,
22+
struct resource *res)
23+
{
24+
struct apple_tunable *tunable;
25+
struct property *prop;
26+
const __be32 *p;
27+
size_t sz;
28+
int i;
29+
30+
if (resource_size(res) < 4)
31+
return ERR_PTR(-EINVAL);
32+
33+
prop = of_find_property(np, name, NULL);
34+
if (!prop)
35+
return ERR_PTR(-ENOENT);
36+
37+
if (prop->length % (3 * sizeof(u32)))
38+
return ERR_PTR(-EINVAL);
39+
sz = prop->length / (3 * sizeof(u32));
40+
41+
tunable = devm_kzalloc(dev, struct_size(tunable, values, sz), GFP_KERNEL);
42+
if (!tunable)
43+
return ERR_PTR(-ENOMEM);
44+
tunable->sz = sz;
45+
46+
for (i = 0, p = NULL; i < tunable->sz; ++i) {
47+
p = of_prop_next_u32(prop, p, &tunable->values[i].offset);
48+
p = of_prop_next_u32(prop, p, &tunable->values[i].mask);
49+
p = of_prop_next_u32(prop, p, &tunable->values[i].value);
50+
51+
/* Sanity checks to catch bugs in our bootloader */
52+
if (tunable->values[i].offset % 4)
53+
return ERR_PTR(-EINVAL);
54+
if (tunable->values[i].offset > (resource_size(res) - 4))
55+
return ERR_PTR(-EINVAL);
56+
}
57+
58+
return tunable;
59+
}
60+
EXPORT_SYMBOL(devm_apple_tunable_parse);
61+
62+
void apple_tunable_apply(void __iomem *regs, struct apple_tunable *tunable)
63+
{
64+
size_t i;
65+
66+
for (i = 0; i < tunable->sz; ++i) {
67+
u32 val, old_val;
68+
69+
old_val = readl(regs + tunable->values[i].offset);
70+
val = old_val & ~tunable->values[i].mask;
71+
val |= tunable->values[i].value;
72+
if (val != old_val)
73+
writel(val, regs + tunable->values[i].offset);
74+
}
75+
}
76+
EXPORT_SYMBOL(apple_tunable_apply);
77+
78+
MODULE_LICENSE("Dual MIT/GPL");
79+
MODULE_AUTHOR("Sven Peter <sven@kernel.org>");
80+
MODULE_DESCRIPTION("Apple Silicon hardware tunable support");

include/linux/soc/apple/tunable.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
2+
/*
3+
* Apple Silicon hardware tunable support
4+
*
5+
* Each tunable is a list with each entry containing a offset into the MMIO
6+
* region, a mask of bits to be cleared and a set of bits to be set. These
7+
* tunables are passed along by the previous boot stages and vary from device
8+
* to device such that they cannot be hardcoded in the individual drivers.
9+
*
10+
* Copyright (C) The Asahi Linux Contributors
11+
*/
12+
13+
#ifndef _LINUX_SOC_APPLE_TUNABLE_H_
14+
#define _LINUX_SOC_APPLE_TUNABLE_H_
15+
16+
#include <linux/device.h>
17+
#include <linux/types.h>
18+
19+
/**
20+
* Struct to store an Apple Silicon hardware tunable.
21+
*
22+
* Each tunable is a list with each entry containing a offset into the MMIO
23+
* region, a mask of bits to be cleared and a set of bits to be set. These
24+
* tunables are passed along by the previous boot stages and vary from device
25+
* to device such that they cannot be hardcoded in the individual drivers.
26+
*
27+
* @param sz Number of [offset, mask, value] tuples stored in values.
28+
* @param values [offset, mask, value] array.
29+
*/
30+
struct apple_tunable {
31+
size_t sz;
32+
struct {
33+
u32 offset;
34+
u32 mask;
35+
u32 value;
36+
} values[] __counted_by(sz);
37+
};
38+
39+
/**
40+
* Parse an array of hardware tunables from the device tree.
41+
*
42+
* @dev: Device node used for devm_kzalloc internally.
43+
* @np: Device node which contains the tunable array.
44+
* @name: Name of the device tree property which contains the tunables.
45+
* @res: Resource to which the tunables will be applied, used for bound checking
46+
*
47+
* @return: devres allocated struct on success or PTR_ERR on failure.
48+
*/
49+
struct apple_tunable *devm_apple_tunable_parse(struct device *dev,
50+
struct device_node *np,
51+
const char *name,
52+
struct resource *res);
53+
54+
/**
55+
* Apply a previously loaded hardware tunable.
56+
*
57+
* @param regs: MMIO to which the tunable will be applied.
58+
* @param tunable: Pointer to the tunable.
59+
*/
60+
void apple_tunable_apply(void __iomem *regs, struct apple_tunable *tunable);
61+
62+
#endif

0 commit comments

Comments
 (0)