mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 03:44:45 +01:00
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> Link: https://patch.msgid.link/20251214-b4-atcphy-v3-1-ba82b20e9459@kernel.org Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
81791c45c8
commit
a722de305e
4 changed files with 149 additions and 0 deletions
|
|
@ -38,6 +38,10 @@ config APPLE_SART
|
|||
|
||||
Say 'y' here if you have an Apple SoC.
|
||||
|
||||
config APPLE_TUNABLE
|
||||
tristate
|
||||
depends on ARCH_APPLE || COMPILE_TEST
|
||||
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -8,3 +8,6 @@ apple-rtkit-y = rtkit.o rtkit-crashlog.o
|
|||
|
||||
obj-$(CONFIG_APPLE_SART) += apple-sart.o
|
||||
apple-sart-y = sart.o
|
||||
|
||||
obj-$(CONFIG_APPLE_TUNABLE) += apple-tunable.o
|
||||
apple-tunable-y = tunable.o
|
||||
|
|
|
|||
80
drivers/soc/apple/tunable.c
Normal file
80
drivers/soc/apple/tunable.c
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||
/*
|
||||
* Apple Silicon hardware tunable support
|
||||
*
|
||||
* Each tunable is a list with each entry containing a offset into the MMIO
|
||||
* region, a mask of bits to be cleared and a set of bits to be set. These
|
||||
* tunables are passed along by the previous boot stages and vary from device
|
||||
* to device such that they cannot be hardcoded in the individual drivers.
|
||||
*
|
||||
* Copyright (C) The Asahi Linux Contributors
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/soc/apple/tunable.h>
|
||||
|
||||
struct apple_tunable *devm_apple_tunable_parse(struct device *dev,
|
||||
struct device_node *np,
|
||||
const char *name,
|
||||
struct resource *res)
|
||||
{
|
||||
struct apple_tunable *tunable;
|
||||
struct property *prop;
|
||||
const __be32 *p;
|
||||
size_t sz;
|
||||
int i;
|
||||
|
||||
if (resource_size(res) < 4)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
prop = of_find_property(np, name, NULL);
|
||||
if (!prop)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
if (prop->length % (3 * sizeof(u32)))
|
||||
return ERR_PTR(-EINVAL);
|
||||
sz = prop->length / (3 * sizeof(u32));
|
||||
|
||||
tunable = devm_kzalloc(dev, struct_size(tunable, values, sz), GFP_KERNEL);
|
||||
if (!tunable)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
tunable->sz = sz;
|
||||
|
||||
for (i = 0, p = NULL; i < tunable->sz; ++i) {
|
||||
p = of_prop_next_u32(prop, p, &tunable->values[i].offset);
|
||||
p = of_prop_next_u32(prop, p, &tunable->values[i].mask);
|
||||
p = of_prop_next_u32(prop, p, &tunable->values[i].value);
|
||||
|
||||
/* Sanity checks to catch bugs in our bootloader */
|
||||
if (tunable->values[i].offset % 4)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (tunable->values[i].offset > (resource_size(res) - 4))
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return tunable;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_apple_tunable_parse);
|
||||
|
||||
void apple_tunable_apply(void __iomem *regs, struct apple_tunable *tunable)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < tunable->sz; ++i) {
|
||||
u32 val, old_val;
|
||||
|
||||
old_val = readl(regs + tunable->values[i].offset);
|
||||
val = old_val & ~tunable->values[i].mask;
|
||||
val |= tunable->values[i].value;
|
||||
if (val != old_val)
|
||||
writel(val, regs + tunable->values[i].offset);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(apple_tunable_apply);
|
||||
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
MODULE_AUTHOR("Sven Peter <sven@kernel.org>");
|
||||
MODULE_DESCRIPTION("Apple Silicon hardware tunable support");
|
||||
62
include/linux/soc/apple/tunable.h
Normal file
62
include/linux/soc/apple/tunable.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
|
||||
/*
|
||||
* Apple Silicon hardware tunable support
|
||||
*
|
||||
* Each tunable is a list with each entry containing a offset into the MMIO
|
||||
* region, a mask of bits to be cleared and a set of bits to be set. These
|
||||
* tunables are passed along by the previous boot stages and vary from device
|
||||
* to device such that they cannot be hardcoded in the individual drivers.
|
||||
*
|
||||
* Copyright (C) The Asahi Linux Contributors
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_SOC_APPLE_TUNABLE_H_
|
||||
#define _LINUX_SOC_APPLE_TUNABLE_H_
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* Struct to store an Apple Silicon hardware tunable.
|
||||
*
|
||||
* Each tunable is a list with each entry containing a offset into the MMIO
|
||||
* region, a mask of bits to be cleared and a set of bits to be set. These
|
||||
* tunables are passed along by the previous boot stages and vary from device
|
||||
* to device such that they cannot be hardcoded in the individual drivers.
|
||||
*
|
||||
* @param sz Number of [offset, mask, value] tuples stored in values.
|
||||
* @param values [offset, mask, value] array.
|
||||
*/
|
||||
struct apple_tunable {
|
||||
size_t sz;
|
||||
struct {
|
||||
u32 offset;
|
||||
u32 mask;
|
||||
u32 value;
|
||||
} values[] __counted_by(sz);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse an array of hardware tunables from the device tree.
|
||||
*
|
||||
* @dev: Device node used for devm_kzalloc internally.
|
||||
* @np: Device node which contains the tunable array.
|
||||
* @name: Name of the device tree property which contains the tunables.
|
||||
* @res: Resource to which the tunables will be applied, used for bound checking
|
||||
*
|
||||
* @return: devres allocated struct on success or PTR_ERR on failure.
|
||||
*/
|
||||
struct apple_tunable *devm_apple_tunable_parse(struct device *dev,
|
||||
struct device_node *np,
|
||||
const char *name,
|
||||
struct resource *res);
|
||||
|
||||
/**
|
||||
* Apply a previously loaded hardware tunable.
|
||||
*
|
||||
* @param regs: MMIO to which the tunable will be applied.
|
||||
* @param tunable: Pointer to the tunable.
|
||||
*/
|
||||
void apple_tunable_apply(void __iomem *regs, struct apple_tunable *tunable);
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue