* [PATCH v2 5/8] thermal: khadas-mcu-fan: Add fan config from platform data Add regulator support
From: Ronald Claveau @ 2026-04-03 16:08 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260403-add-mcu-fan-khadas-vim4-v2-0-70536b22439a@aliel.fr>
Replace the hardcoded MAX_LEVEL constant and fan register
with values read from platform_data (fan_reg, max_level),
as new MCUs need different values.
Optionally acquire and enable a "fan" regulator supply
at probe time and on resume,
so boards that gate fan power through a regulator are handled.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
drivers/thermal/khadas_mcu_fan.c | 49 +++++++++++++++++++++++++++++++++++-----
1 file changed, 43 insertions(+), 6 deletions(-)
diff --git a/drivers/thermal/khadas_mcu_fan.c b/drivers/thermal/khadas_mcu_fan.c
index d35e5313bea41..24559bf65de46 100644
--- a/drivers/thermal/khadas_mcu_fan.c
+++ b/drivers/thermal/khadas_mcu_fan.c
@@ -13,13 +13,15 @@
#include <linux/regmap.h>
#include <linux/sysfs.h>
#include <linux/thermal.h>
-
-#define MAX_LEVEL 3
+#include <linux/regulator/consumer.h>
struct khadas_mcu_fan_ctx {
struct khadas_mcu *mcu;
+ unsigned int fan_reg;
unsigned int level;
+ unsigned int max_level;
struct thermal_cooling_device *cdev;
+ struct regulator *power;
};
static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx,
@@ -27,8 +29,7 @@ static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx,
{
int ret;
- ret = regmap_write(ctx->mcu->regmap, KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
- level);
+ ret = regmap_write(ctx->mcu->regmap, ctx->fan_reg, level);
if (ret)
return ret;
@@ -40,7 +41,9 @@ static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx,
static int khadas_mcu_fan_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
- *state = MAX_LEVEL;
+ struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
+
+ *state = ctx->max_level;
return 0;
}
@@ -61,7 +64,7 @@ khadas_mcu_fan_set_cur_state(struct thermal_cooling_device *cdev,
{
struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
- if (state > MAX_LEVEL)
+ if (state > ctx->max_level)
return -EINVAL;
if (state == ctx->level)
@@ -83,11 +86,32 @@ static int khadas_mcu_fan_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct khadas_mcu_fan_ctx *ctx;
int ret;
+ const struct khadas_mcu_fan_pdata *pdata = dev_get_platdata(&pdev->dev);
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
+
ctx->mcu = mcu;
+ ctx->fan_reg = pdata->fan_reg;
+ ctx->max_level = pdata->max_level;
+
+ ctx->power = devm_regulator_get_optional(dev->parent, "fan");
+ if (IS_ERR(ctx->power)) {
+ if (PTR_ERR(ctx->power) == -ENODEV)
+ ctx->power = NULL;
+ else
+ return PTR_ERR(ctx->power);
+ }
+
+ if (ctx->power) {
+ ret = regulator_enable(ctx->power);
+ if (ret) {
+ dev_err(dev, "Failed to enable fan power supply: %d\n", ret);
+ return ret;
+ }
+ }
+
platform_set_drvdata(pdev, ctx);
cdev = devm_thermal_of_cooling_device_register(dev->parent,
@@ -124,12 +148,25 @@ static int khadas_mcu_fan_suspend(struct device *dev)
ctx->level = level_save;
+ if (ctx->power) {
+ ret = regulator_disable(ctx->power);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
static int khadas_mcu_fan_resume(struct device *dev)
{
struct khadas_mcu_fan_ctx *ctx = dev_get_drvdata(dev);
+ int ret;
+
+ if (ctx->power) {
+ ret = regulator_enable(ctx->power);
+ if (ret)
+ return ret;
+ }
return khadas_mcu_fan_set_level(ctx, ctx->level);
}
--
2.49.0
^ permalink raw reply related
* [PATCH v2 0/8] Add VIM4 MCU/FAN support
From: Ronald Claveau @ 2026-04-03 16:08 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
The Khadas VIM4 board features a different MCU variant compared to
previous VIM boards.
While it shares the same I2C-based communication model,
it differs in some ways:
- A distinct register map with its own volatile/writeable register set
- A fan control with 0–100 levels instead of the 0–3 levels previously
- A fan power supply gated through a regulator
This series adds support for this new variant by:
1. Refactoring the khadas-mcu MFD driver to use per-variant data
structures (regmap config, cells, fan platform data),
and adding the khadas,vim4-mcu compatible string.
2. Extending the fan thermal driver to retrieve the fan register
and maximum level from platform_data,
and to optionally manage a power regulator for the fan supply.
3. Adding the corresponding DTS node for the VIM4, wiring the MCU to
the I2C AO_A bus and exposing it as a thermal cooling device.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
Changes in v2:
- PATCH 5: Add regulator_disable on suspend thanks to Neil's feedback.
- Link to v1: https://lore.kernel.org/r/20260402-add-mcu-fan-khadas-vim4-v1-0-2b12eb4ac7b0@aliel.fr
---
Ronald Claveau (8):
dt-bindings: mfd: khadas: Add new compatible for Khadas VIM4 MCU
dt-bindings: i2c: amlogic: Add compatible for T7 SOC
mfd: khadas-mcu: Add per-variant configuration infrastructure and VIM4 support
mfd: khadas-mcu: Add support for VIM4 MCU variant
thermal: khadas-mcu-fan: Add fan config from platform data Add regulator support
arm64: dts: amlogic: t7: Add i2c pinctrl node
arm64: dts: amlogic: t7: Add i2c controller node
arm64: dts: amlogic: t7: khadas-vim4: Add i2c MCU fan node
.../bindings/i2c/amlogic,meson6-i2c.yaml | 13 ++-
.../devicetree/bindings/mfd/khadas,mcu.yaml | 5 +
.../dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts | 13 +++
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 20 ++++
drivers/mfd/khadas-mcu.c | 106 ++++++++++++++++++---
drivers/thermal/khadas_mcu_fan.c | 49 ++++++++--
include/linux/mfd/khadas-mcu.h | 39 +++++++-
7 files changed, 222 insertions(+), 23 deletions(-)
---
base-commit: f7b64ed948718290209074a50bb0df17e5944873
change-id: 20260402-add-mcu-fan-khadas-vim4-ac1cbe553c9b
prerequisite-message-id: <20260326092645.1053261-1-jian.hu@amlogic.com>
prerequisite-patch-id: f03a086b4137158412b2d47b3de793b858de8dde
prerequisite-patch-id: 123970c9b29c2090440f2fd71c85d3c6fd8e36de
prerequisite-patch-id: 3e2e56b0926ba327b520f935df4ced5089bbe503
prerequisite-patch-id: 65a5d76ffdbc9b3aab3385bb65cb027004c30e7e
prerequisite-patch-id: 237269801826dd3ad7fb16eb4d7d6d4eab504278
prerequisite-patch-id: 57e9b08a968aedf543d3d0d56cf1ca4db20b2a16
prerequisite-change-id: 20260326-add-bcm43752-compatible-e264a4f7973a:v2
prerequisite-patch-id: cd98b74fa56af72af2553f391c400981d83cd4f4
prerequisite-patch-id: b730f5e42be1d89d193e63a0265495cdbf2c7d7b
prerequisite-change-id: 20260330-fix-invalid-property-bbe54d933f71:v2
prerequisite-patch-id: 8d675e7a239985c762843515b241f0a2f45f9c92
prerequisite-change-id: 20260331-fix-aml-t7-null-reset-2b608ebf9da4:v1
prerequisite-patch-id: 5b5de77af11747ce964404fb827d2ee2bff47ea5
prerequisite-patch-id: 1e37fc75fed1e533adee0f3e7e6ead1f8ff3c55c
prerequisite-patch-id: 65a5d76ffdbc9b3aab3385bb65cb027004c30e7e
prerequisite-patch-id: 2daf583fb5e7449a02bd217d8aca330171b598aa
prerequisite-patch-id: 237269801826dd3ad7fb16eb4d7d6d4eab504278
prerequisite-patch-id: d1ddf9b7710e91f8062de83bd7ba55afb2c4c112
prerequisite-patch-id: 57e9b08a968aedf543d3d0d56cf1ca4db20b2a16
prerequisite-patch-id: cd98b74fa56af72af2553f391c400981d83cd4f4
prerequisite-patch-id: b730f5e42be1d89d193e63a0265495cdbf2c7d7b
prerequisite-patch-id: 9debd88fa60febed9cd7208f86603b4c2d270520
prerequisite-patch-id: 314ef9ff0c4d1d15dab1dea9d92aa065f1eac3e9
Best regards,
--
Ronald Claveau <linux-kernel-dev@aliel.fr>
^ permalink raw reply
* Re: (subset) [PATCH 05/15] dt-bindings: rtc: ingenic,rtc: Use generic power-controller schema
From: Alexandre Belloni @ 2026-04-03 16:09 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Rafael J. Wysocki,
Ulf Hansson, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Saenz Julienne, Lee Jones, Liam Girdwood, Mark Brown,
Shree Ramamoorthy, Jerome Neanne, Paul Cercueil, Dmitry Osipenko,
Heiko Stuebner, Joseph Chen, Chris Zhong, Zhang Qing,
Sebastian Reichel, Andreas Kemnade, Jonathan Neuschäfer,
Lubomir Rintel, Julien Panis, Matti Vaittinen, Alexander Kurz,
Krzysztof Kozlowski, André Draszik, Peng Fan (OSS)
Cc: devicetree, linux-kernel, linux-rpi-kernel, linux-arm-kernel,
linux-rtc, linux-rockchip, linux-samsung-soc, Peng Fan
In-Reply-To: <20260316-power-controller-v1-5-92c80e5e1744@nxp.com>
On Mon, 16 Mar 2026 22:47:40 +0800, Peng Fan (OSS) wrote:
> Convert the binding to use the generic power-controller schema instead by
> referencing power-controller.yaml and removing the local
> `system-power-controller` property definition.
Applied, thanks!
[05/15] dt-bindings: rtc: ingenic,rtc: Use generic power-controller schema
https://git.kernel.org/abelloni/c/0452290110cc
Best regards,
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH bpf-next v12 1/5] bpf: Move constants blinding out of arch-specific JITs
From: Emil Tsalapatis @ 2026-04-03 16:04 UTC (permalink / raw)
To: Xu Kuohai, bpf, linux-kernel, linux-arm-kernel
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Yonghong Song, Puranjay Mohan,
Anton Protopopov, Alexis Lothoré, Shahab Vahedi,
Russell King, Tiezhu Yang, Hengqi Chen, Johan Almbladh,
Paul Burton, Hari Bathini, Christophe Leroy, Naveen N Rao,
Luke Nelson, Xi Wang, Björn Töpel, Pu Lehui,
Ilya Leoshkevich, Heiko Carstens, Vasily Gorbik, David S . Miller,
Wang YanQing
In-Reply-To: <20260403132811.753894-2-xukuohai@huaweicloud.com>
On Fri Apr 3, 2026 at 9:28 AM EDT, Xu Kuohai wrote:
> From: Xu Kuohai <xukuohai@huawei.com>
>
> During the JIT stage, constants blinding rewrites instructions but only
> rewrites the private instruction copy of the JITed subprog, leaving the
> global env->prog->insni and env->insn_aux_data untouched. This causes a
> mismatch between subprog instructions and the global state, making it
> difficult to use the global data in the JIT.
>
> To avoid this mismatch, and given that all arch-specific JITs already
> support constants blinding, move it to the generic verifier code, and
> switch to rewrite the global env->prog->insnsi with the global states
> adjusted, as other rewrites in the verifier do.
>
> This removes the constants blinding calls in each JIT, which are largely
> duplicated code across architectures.
>
> Since constants blinding is only required for JIT, and there are two
> JIT entry functions, jit_subprogs() for BPF programs with multiple
> subprogs and bpf_prog_select_runtime() for programs with no subprogs,
> move the constants blinding invocation into these two functions.
>
> In the verifier path, bpf_patch_insn_data() is used to keep global
> verifier auxiliary data in sync with patched instructions. A key
> question is whether this global auxiliary data should be restored
> on the failure path.
>
> Besides instructions, bpf_patch_insn_data() adjusts:
> - prog->aux->poke_tab
> - env->insn_array_maps
> - env->subprog_info
> - env->insn_aux_data
>
> For prog->aux->poke_tab, it is only used by JIT or only meaningful after
> JIT succeeds, so it does not need to be restored on the failure path.
>
> For env->insn_array_maps, when JIT fails, programs using insn arrays
> are rejected by bpf_insn_array_ready() due to missing JIT addresses.
> Hence, env->insn_array_maps is only meaningful for JIT and does not need
> to be restored.
>
> For subprog_info, if jit_subprogs fails and CONFIG_BPF_JIT_ALWAYS_ON
> is not enabled, kernel falls back to interpreter. In this case,
> env->subprog_info is used to determine subprogram stack depth. So it
> must be restored on failure.
>
> For env->insn_aux_data, it is freed by clean_insn_aux_data() at the
> end of bpf_check(). Before freeing, clean_insn_aux_data() loops over
> env->insn_aux_data to release jump targets recorded in it. The loop
> uses env->prog->len as the array length, but this length no longer
> matches the actual size of the adjusted env->insn_aux_data array after
> constants blinding.
>
> To address it, a simple approach is to keep insn_aux_data as adjusted
> after failure, since it will be freed shortly, and record its actual size
> for the loop in clean_insn_aux_data(). But since clean_insn_aux_data()
> uses the same index to loop over both env->prog->insni and env->insn_aux_data,
> this approach result in incorrect index for the insni array. So an
> alternative approach is adopted: clone the original env->insn_aux_data
> before blinding and restore it after failure, similar to env->prog.
>
> For classic BPF programs, constants blinding works as before since it
> is still invoked from bpf_prog_select_runtime().
>
> Reviewed-by: Anton Protopopov <a.s.protopopov@gmail.com> # v8
> Reviewed-by: Hari Bathini <hbathini@linux.ibm.com> # powerpc jit
> Reviewed-by: Pu Lehui <pulehui@huawei.com> # riscv jit
> Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
> ---
> arch/arc/net/bpf_jit_core.c | 39 ++++-----
> arch/arm/net/bpf_jit_32.c | 41 ++--------
> arch/arm64/net/bpf_jit_comp.c | 72 +++++-----------
> arch/loongarch/net/bpf_jit.c | 59 ++++----------
> arch/mips/net/bpf_jit_comp.c | 20 +----
> arch/parisc/net/bpf_jit_core.c | 73 +++++++----------
> arch/powerpc/net/bpf_jit_comp.c | 68 ++++++----------
> arch/riscv/net/bpf_jit_core.c | 61 +++++---------
> arch/s390/net/bpf_jit_comp.c | 59 +++++---------
> arch/sparc/net/bpf_jit_comp_64.c | 61 +++++---------
> arch/x86/net/bpf_jit_comp.c | 43 ++--------
> arch/x86/net/bpf_jit_comp32.c | 33 +-------
> include/linux/filter.h | 33 +++++++-
> kernel/bpf/core.c | 67 +++++++++++++--
> kernel/bpf/verifier.c | 136 +++++++++++++++++++++++++------
> 15 files changed, 390 insertions(+), 475 deletions(-)
>
> diff --git a/arch/arc/net/bpf_jit_core.c b/arch/arc/net/bpf_jit_core.c
> index 1421eeced0f5..973ceae48675 100644
> --- a/arch/arc/net/bpf_jit_core.c
> +++ b/arch/arc/net/bpf_jit_core.c
> @@ -79,7 +79,6 @@ struct arc_jit_data {
> * The JIT pertinent context that is used by different functions.
> *
> * prog: The current eBPF program being handled.
> - * orig_prog: The original eBPF program before any possible change.
> * jit: The JIT buffer and its length.
> * bpf_header: The JITed program header. "jit.buf" points inside it.
> * emit: If set, opcodes are written to memory; else, a dry-run.
> @@ -94,12 +93,10 @@ struct arc_jit_data {
> * need_extra_pass: A forecast if an "extra_pass" will occur.
> * is_extra_pass: Indicates if the current pass is an extra pass.
> * user_bpf_prog: True, if VM opcodes come from a real program.
> - * blinded: True if "constant blinding" step returned a new "prog".
> * success: Indicates if the whole JIT went OK.
> */
> struct jit_context {
> struct bpf_prog *prog;
> - struct bpf_prog *orig_prog;
> struct jit_buffer jit;
> struct bpf_binary_header *bpf_header;
> bool emit;
> @@ -114,7 +111,6 @@ struct jit_context {
> bool need_extra_pass;
> bool is_extra_pass;
> bool user_bpf_prog;
> - bool blinded;
> bool success;
> };
>
> @@ -161,13 +157,7 @@ static int jit_ctx_init(struct jit_context *ctx, struct bpf_prog *prog)
> {
> memset(ctx, 0, sizeof(*ctx));
>
> - ctx->orig_prog = prog;
> -
> - /* If constant blinding was requested but failed, scram. */
> - ctx->prog = bpf_jit_blind_constants(prog);
> - if (IS_ERR(ctx->prog))
> - return PTR_ERR(ctx->prog);
> - ctx->blinded = (ctx->prog != ctx->orig_prog);
> + ctx->prog = prog;
>
> /* If the verifier doesn't zero-extend, then we have to do it. */
> ctx->do_zext = !ctx->prog->aux->verifier_zext;
> @@ -214,14 +204,6 @@ static inline void maybe_free(struct jit_context *ctx, void **mem)
> */
> static void jit_ctx_cleanup(struct jit_context *ctx)
> {
> - if (ctx->blinded) {
> - /* if all went well, release the orig_prog. */
> - if (ctx->success)
> - bpf_jit_prog_release_other(ctx->prog, ctx->orig_prog);
> - else
> - bpf_jit_prog_release_other(ctx->orig_prog, ctx->prog);
> - }
> -
> maybe_free(ctx, (void **)&ctx->bpf2insn);
> maybe_free(ctx, (void **)&ctx->jit_data);
>
> @@ -229,12 +211,19 @@ static void jit_ctx_cleanup(struct jit_context *ctx)
> ctx->bpf2insn_valid = false;
>
> /* Freeing "bpf_header" is enough. "jit.buf" is a sub-array of it. */
> - if (!ctx->success && ctx->bpf_header) {
> - bpf_jit_binary_free(ctx->bpf_header);
> - ctx->bpf_header = NULL;
> - ctx->jit.buf = NULL;
> - ctx->jit.index = 0;
> - ctx->jit.len = 0;
> + if (!ctx->success) {
> + if (ctx->bpf_header) {
> + bpf_jit_binary_free(ctx->bpf_header);
> + ctx->bpf_header = NULL;
> + ctx->jit.buf = NULL;
> + ctx->jit.index = 0;
> + ctx->jit.len = 0;
> + }
> + if (ctx->is_extra_pass) {
> + ctx->prog->bpf_func = NULL;
> + ctx->prog->jited = 0;
> + ctx->prog->jited_len = 0;
> + }
> }
>
> ctx->emit = false;
> diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
> index deeb8f292454..e6b1bb2de627 100644
> --- a/arch/arm/net/bpf_jit_32.c
> +++ b/arch/arm/net/bpf_jit_32.c
> @@ -2144,9 +2144,7 @@ bool bpf_jit_needs_zext(void)
>
> struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> {
> - struct bpf_prog *tmp, *orig_prog = prog;
> struct bpf_binary_header *header;
> - bool tmp_blinded = false;
> struct jit_ctx ctx;
> unsigned int tmp_idx;
> unsigned int image_size;
> @@ -2156,20 +2154,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> * the interpreter.
> */
> if (!prog->jit_requested)
> - return orig_prog;
> -
> - /* If constant blinding was enabled and we failed during blinding
> - * then we must fall back to the interpreter. Otherwise, we save
> - * the new JITed code.
> - */
> - tmp = bpf_jit_blind_constants(prog);
> -
> - if (IS_ERR(tmp))
> - return orig_prog;
> - if (tmp != prog) {
> - tmp_blinded = true;
> - prog = tmp;
> - }
> + return prog;
>
> memset(&ctx, 0, sizeof(ctx));
> ctx.prog = prog;
> @@ -2179,10 +2164,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> * we must fall back to the interpreter
> */
> ctx.offsets = kcalloc(prog->len, sizeof(int), GFP_KERNEL);
> - if (ctx.offsets == NULL) {
> - prog = orig_prog;
> - goto out;
> - }
> + if (ctx.offsets == NULL)
> + return prog;
>
> /* 1) fake pass to find in the length of the JITed code,
> * to compute ctx->offsets and other context variables
> @@ -2194,10 +2177,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> * being successful in the second pass, so just fall back
> * to the interpreter.
> */
> - if (build_body(&ctx)) {
> - prog = orig_prog;
> + if (build_body(&ctx))
> goto out_off;
> - }
>
> tmp_idx = ctx.idx;
> build_prologue(&ctx);
> @@ -2213,10 +2194,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> ctx.idx += ctx.imm_count;
> if (ctx.imm_count) {
> ctx.imms = kcalloc(ctx.imm_count, sizeof(u32), GFP_KERNEL);
> - if (ctx.imms == NULL) {
> - prog = orig_prog;
> + if (ctx.imms == NULL)
> goto out_off;
> - }
> }
> #else
> /* there's nothing about the epilogue on ARMv7 */
> @@ -2238,10 +2217,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> /* Not able to allocate memory for the structure then
> * we must fall back to the interpretation
> */
> - if (header == NULL) {
> - prog = orig_prog;
> + if (header == NULL)
> goto out_imms;
> - }
>
> /* 2.) Actual pass to generate final JIT code */
> ctx.target = (u32 *) image_ptr;
> @@ -2278,16 +2255,12 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> #endif
> out_off:
> kfree(ctx.offsets);
> -out:
> - if (tmp_blinded)
> - bpf_jit_prog_release_other(prog, prog == orig_prog ?
> - tmp : orig_prog);
> +
> return prog;
>
> out_free:
> image_ptr = NULL;
> bpf_jit_binary_free(header);
> - prog = orig_prog;
> goto out_imms;
> }
>
> diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
> index adf84962d579..cd5a72fff500 100644
> --- a/arch/arm64/net/bpf_jit_comp.c
> +++ b/arch/arm64/net/bpf_jit_comp.c
> @@ -2009,14 +2009,12 @@ struct arm64_jit_data {
> struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> {
> int image_size, prog_size, extable_size, extable_align, extable_offset;
> - struct bpf_prog *tmp, *orig_prog = prog;
> struct bpf_binary_header *header;
> struct bpf_binary_header *ro_header = NULL;
> struct arm64_jit_data *jit_data;
> void __percpu *priv_stack_ptr = NULL;
> bool was_classic = bpf_prog_was_classic(prog);
> int priv_stack_alloc_sz;
> - bool tmp_blinded = false;
> bool extra_pass = false;
> struct jit_ctx ctx;
> u8 *image_ptr;
> @@ -2025,26 +2023,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> int exentry_idx;
>
> if (!prog->jit_requested)
> - return orig_prog;
> -
> - tmp = bpf_jit_blind_constants(prog);
> - /* If blinding was requested and we failed during blinding,
> - * we must fall back to the interpreter.
> - */
> - if (IS_ERR(tmp))
> - return orig_prog;
> - if (tmp != prog) {
> - tmp_blinded = true;
> - prog = tmp;
> - }
> + return prog;
>
> jit_data = prog->aux->jit_data;
> if (!jit_data) {
> jit_data = kzalloc_obj(*jit_data);
> - if (!jit_data) {
> - prog = orig_prog;
> - goto out;
> - }
> + if (!jit_data)
> + return prog;
> prog->aux->jit_data = jit_data;
> }
> priv_stack_ptr = prog->aux->priv_stack_ptr;
> @@ -2056,10 +2041,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 16) +
> 2 * PRIV_STACK_GUARD_SZ;
> priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_sz, 16, GFP_KERNEL);
> - if (!priv_stack_ptr) {
> - prog = orig_prog;
> + if (!priv_stack_ptr)
> goto out_priv_stack;
> - }
>
> priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_sz);
> prog->aux->priv_stack_ptr = priv_stack_ptr;
> @@ -2079,10 +2062,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> ctx.prog = prog;
>
> ctx.offset = kvzalloc_objs(int, prog->len + 1);
> - if (ctx.offset == NULL) {
> - prog = orig_prog;
> + if (ctx.offset == NULL)
> goto out_off;
> - }
>
> ctx.user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
> ctx.arena_vm_start = bpf_arena_get_kern_vm_start(prog->aux->arena);
> @@ -2095,15 +2076,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> * BPF line info needs ctx->offset[i] to be the offset of
> * instruction[i] in jited image, so build prologue first.
> */
> - if (build_prologue(&ctx, was_classic)) {
> - prog = orig_prog;
> + if (build_prologue(&ctx, was_classic))
> goto out_off;
> - }
>
> - if (build_body(&ctx, extra_pass)) {
> - prog = orig_prog;
> + if (build_body(&ctx, extra_pass))
> goto out_off;
> - }
>
> ctx.epilogue_offset = ctx.idx;
> build_epilogue(&ctx, was_classic);
> @@ -2121,10 +2098,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr,
> sizeof(u64), &header, &image_ptr,
> jit_fill_hole);
> - if (!ro_header) {
> - prog = orig_prog;
> + if (!ro_header)
> goto out_off;
> - }
>
> /* Pass 2: Determine jited position and result for each instruction */
>
> @@ -2152,10 +2127,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> /* Dont write body instructions to memory for now */
> ctx.write = false;
>
> - if (build_body(&ctx, extra_pass)) {
> - prog = orig_prog;
> + if (build_body(&ctx, extra_pass))
> goto out_free_hdr;
> - }
>
> ctx.epilogue_offset = ctx.idx;
> ctx.exentry_idx = exentry_idx;
> @@ -2164,19 +2137,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>
> /* Pass 3: Adjust jump offset and write final image */
> if (build_body(&ctx, extra_pass) ||
> - WARN_ON_ONCE(ctx.idx != ctx.epilogue_offset)) {
> - prog = orig_prog;
> + WARN_ON_ONCE(ctx.idx != ctx.epilogue_offset))
This thunk is slightly different now, the WARN_ON_ONCE() won't be checked
if build_body() succeeds. Do we even need it? AFAICT the only case it
wouldn't trigger if build_body() fails is if it did so at the very last
instruction. Alternatively, should we check it if build_body() succeeds
instead to retain the old behavior?
> goto out_free_hdr;
> - }
>
> build_epilogue(&ctx, was_classic);
> build_plt(&ctx);
>
> /* Extra pass to validate JITed code. */
> - if (validate_ctx(&ctx)) {
> - prog = orig_prog;
> + if (validate_ctx(&ctx))
> goto out_free_hdr;
> - }
>
> /* update the real prog size */
> prog_size = sizeof(u32) * ctx.idx;
> @@ -2193,16 +2162,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> if (extra_pass && ctx.idx > jit_data->ctx.idx) {
> pr_err_once("multi-func JIT bug %d > %d\n",
> ctx.idx, jit_data->ctx.idx);
> - prog->bpf_func = NULL;
> - prog->jited = 0;
> - prog->jited_len = 0;
> goto out_free_hdr;
> }
> if (WARN_ON(bpf_jit_binary_pack_finalize(ro_header, header))) {
> - /* ro_header has been freed */
> + /* ro_header and header has been freed */
> ro_header = NULL;
> - prog = orig_prog;
> - goto out_off;
> + header = NULL;
> + goto out_free_hdr;
> }
> /*
> * The instructions have now been copied to the ROX region from
> @@ -2245,13 +2211,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> kfree(jit_data);
> prog->aux->jit_data = NULL;
> }
> -out:
> - if (tmp_blinded)
> - bpf_jit_prog_release_other(prog, prog == orig_prog ?
> - tmp : orig_prog);
> +
> return prog;
>
> out_free_hdr:
> + if (extra_pass) {
> + prog->bpf_func = NULL;
> + prog->jited = 0;
> + prog->jited_len = 0;
> + }
> if (header) {
> bpf_arch_text_copy(&ro_header->size, &header->size,
> sizeof(header->size));
> diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
> index 9cb796e16379..fcc8c0c29fb0 100644
> --- a/arch/loongarch/net/bpf_jit.c
> +++ b/arch/loongarch/net/bpf_jit.c
> @@ -1922,43 +1922,26 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
>
> struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> {
> - bool tmp_blinded = false, extra_pass = false;
> + bool extra_pass = false;
> u8 *image_ptr, *ro_image_ptr;
> int image_size, prog_size, extable_size;
> struct jit_ctx ctx;
> struct jit_data *jit_data;
> struct bpf_binary_header *header;
> struct bpf_binary_header *ro_header;
> - struct bpf_prog *tmp, *orig_prog = prog;
>
> /*
> * If BPF JIT was not enabled then we must fall back to
> * the interpreter.
> */
> if (!prog->jit_requested)
> - return orig_prog;
> -
> - tmp = bpf_jit_blind_constants(prog);
> - /*
> - * If blinding was requested and we failed during blinding,
> - * we must fall back to the interpreter. Otherwise, we save
> - * the new JITed code.
> - */
> - if (IS_ERR(tmp))
> - return orig_prog;
> -
> - if (tmp != prog) {
> - tmp_blinded = true;
> - prog = tmp;
> - }
> + return prog;
>
> jit_data = prog->aux->jit_data;
> if (!jit_data) {
> jit_data = kzalloc_obj(*jit_data);
> - if (!jit_data) {
> - prog = orig_prog;
> - goto out;
> - }
> + if (!jit_data)
> + return prog;
> prog->aux->jit_data = jit_data;
> }
> if (jit_data->ctx.offset) {
> @@ -1978,17 +1961,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> ctx.user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
>
> ctx.offset = kvcalloc(prog->len + 1, sizeof(u32), GFP_KERNEL);
> - if (ctx.offset == NULL) {
> - prog = orig_prog;
> + if (ctx.offset == NULL)
> goto out_offset;
> - }
>
> /* 1. Initial fake pass to compute ctx->idx and set ctx->flags */
> build_prologue(&ctx);
> - if (build_body(&ctx, extra_pass)) {
> - prog = orig_prog;
> + if (build_body(&ctx, extra_pass))
> goto out_offset;
> - }
> ctx.epilogue_offset = ctx.idx;
> build_epilogue(&ctx);
>
> @@ -2004,10 +1983,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> /* Now we know the size of the structure to make */
> ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr, sizeof(u32),
> &header, &image_ptr, jit_fill_hole);
> - if (!ro_header) {
> - prog = orig_prog;
> + if (!ro_header)
> goto out_offset;
> - }
>
> /* 2. Now, the actual pass to generate final JIT code */
> /*
> @@ -2027,17 +2004,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> ctx.num_exentries = 0;
>
> build_prologue(&ctx);
> - if (build_body(&ctx, extra_pass)) {
> - prog = orig_prog;
> + if (build_body(&ctx, extra_pass))
> goto out_free;
> - }
> build_epilogue(&ctx);
>
> /* 3. Extra pass to validate JITed code */
> - if (validate_ctx(&ctx)) {
> - prog = orig_prog;
> + if (validate_ctx(&ctx))
> goto out_free;
> - }
>
> /* And we're done */
> if (bpf_jit_enable > 1)
> @@ -2050,9 +2023,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> goto out_free;
> }
> if (WARN_ON(bpf_jit_binary_pack_finalize(ro_header, header))) {
> - /* ro_header has been freed */
> + /* ro_header and header have been freed */
> ro_header = NULL;
> - prog = orig_prog;
> + header = NULL;
> goto out_free;
> }
> /*
> @@ -2084,13 +2057,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> prog->aux->jit_data = NULL;
> }
>
> -out:
> - if (tmp_blinded)
> - bpf_jit_prog_release_other(prog, prog == orig_prog ? tmp : orig_prog);
> -
> return prog;
>
> out_free:
> + if (extra_pass) {
> + prog->bpf_func = NULL;
> + prog->jited = 0;
> + prog->jited_len = 0;
> + }
> +
> if (header) {
> bpf_arch_text_copy(&ro_header->size, &header->size, sizeof(header->size));
> bpf_jit_binary_pack_free(ro_header, header);
> diff --git a/arch/mips/net/bpf_jit_comp.c b/arch/mips/net/bpf_jit_comp.c
> index e355dfca4400..d2b6c955f18e 100644
> --- a/arch/mips/net/bpf_jit_comp.c
> +++ b/arch/mips/net/bpf_jit_comp.c
> @@ -911,10 +911,8 @@ bool bpf_jit_needs_zext(void)
>
> struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> {
> - struct bpf_prog *tmp, *orig_prog = prog;
> struct bpf_binary_header *header = NULL;
> struct jit_context ctx;
> - bool tmp_blinded = false;
> unsigned int tmp_idx;
> unsigned int image_size;
> u8 *image_ptr;
> @@ -925,19 +923,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> * the interpreter.
> */
> if (!prog->jit_requested)
> - return orig_prog;
> - /*
> - * If constant blinding was enabled and we failed during blinding
> - * then we must fall back to the interpreter. Otherwise, we save
> - * the new JITed code.
> - */
> - tmp = bpf_jit_blind_constants(prog);
> - if (IS_ERR(tmp))
> - return orig_prog;
> - if (tmp != prog) {
> - tmp_blinded = true;
> - prog = tmp;
> - }
> + return prog;
>
> memset(&ctx, 0, sizeof(ctx));
> ctx.program = prog;
> @@ -1025,14 +1011,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> prog->jited_len = image_size;
>
> out:
> - if (tmp_blinded)
> - bpf_jit_prog_release_other(prog, prog == orig_prog ?
> - tmp : orig_prog);
> kfree(ctx.descriptors);
> return prog;
>
> out_err:
> - prog = orig_prog;
> if (header)
> bpf_jit_binary_free(header);
> goto out;
> diff --git a/arch/parisc/net/bpf_jit_core.c b/arch/parisc/net/bpf_jit_core.c
> index a5eb6b51e27a..35dca372b5df 100644
> --- a/arch/parisc/net/bpf_jit_core.c
> +++ b/arch/parisc/net/bpf_jit_core.c
> @@ -44,30 +44,19 @@ bool bpf_jit_needs_zext(void)
> struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> {
> unsigned int prog_size = 0, extable_size = 0;
> - bool tmp_blinded = false, extra_pass = false;
> - struct bpf_prog *tmp, *orig_prog = prog;
> + bool extra_pass = false;
> int pass = 0, prev_ninsns = 0, prologue_len, i;
> struct hppa_jit_data *jit_data;
> struct hppa_jit_context *ctx;
>
> if (!prog->jit_requested)
> - return orig_prog;
> -
> - tmp = bpf_jit_blind_constants(prog);
> - if (IS_ERR(tmp))
> - return orig_prog;
> - if (tmp != prog) {
> - tmp_blinded = true;
> - prog = tmp;
> - }
> + return prog;
>
> jit_data = prog->aux->jit_data;
> if (!jit_data) {
> jit_data = kzalloc_obj(*jit_data);
> - if (!jit_data) {
> - prog = orig_prog;
> - goto out;
> - }
> + if (!jit_data)
> + return prog;
> prog->aux->jit_data = jit_data;
> }
>
> @@ -81,10 +70,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>
> ctx->prog = prog;
> ctx->offset = kzalloc_objs(int, prog->len);
> - if (!ctx->offset) {
> - prog = orig_prog;
> - goto out_offset;
> - }
> + if (!ctx->offset)
> + goto out_err;
> for (i = 0; i < prog->len; i++) {
> prev_ninsns += 20;
> ctx->offset[i] = prev_ninsns;
> @@ -93,10 +80,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> for (i = 0; i < NR_JIT_ITERATIONS; i++) {
> pass++;
> ctx->ninsns = 0;
> - if (build_body(ctx, extra_pass, ctx->offset)) {
> - prog = orig_prog;
> - goto out_offset;
> - }
> + if (build_body(ctx, extra_pass, ctx->offset))
> + goto out_err;
> ctx->body_len = ctx->ninsns;
> bpf_jit_build_prologue(ctx);
> ctx->prologue_len = ctx->ninsns - ctx->body_len;
> @@ -116,10 +101,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> &jit_data->image,
> sizeof(long),
> bpf_fill_ill_insns);
> - if (!jit_data->header) {
> - prog = orig_prog;
> - goto out_offset;
> - }
> + if (!jit_data->header)
> + goto out_err;
>
> ctx->insns = (u32 *)jit_data->image;
> /*
> @@ -134,8 +117,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> pr_err("bpf-jit: image did not converge in <%d passes!\n", i);
> if (jit_data->header)
> bpf_jit_binary_free(jit_data->header);
> - prog = orig_prog;
> - goto out_offset;
> + goto out_err;
> }
>
> if (extable_size)
> @@ -148,8 +130,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> bpf_jit_build_prologue(ctx);
> if (build_body(ctx, extra_pass, NULL)) {
> bpf_jit_binary_free(jit_data->header);
> - prog = orig_prog;
> - goto out_offset;
> + goto out_err;
> }
> bpf_jit_build_epilogue(ctx);
>
> @@ -160,20 +141,19 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> { extern int machine_restart(char *); machine_restart(""); }
> }
>
> + if (!prog->is_func || extra_pass) {
> + if (bpf_jit_binary_lock_ro(jit_data->header)) {
> + bpf_jit_binary_free(jit_data->header);
> + goto out_err;
> + }
> + bpf_flush_icache(jit_data->header, ctx->insns + ctx->ninsns);
> + }
> +
> prog->bpf_func = (void *)ctx->insns;
> prog->jited = 1;
> prog->jited_len = prog_size;
>
> - bpf_flush_icache(jit_data->header, ctx->insns + ctx->ninsns);
> -
> if (!prog->is_func || extra_pass) {
> - if (bpf_jit_binary_lock_ro(jit_data->header)) {
> - bpf_jit_binary_free(jit_data->header);
> - prog->bpf_func = NULL;
> - prog->jited = 0;
> - prog->jited_len = 0;
> - goto out_offset;
> - }
> prologue_len = ctx->epilogue_offset - ctx->body_len;
> for (i = 0; i < prog->len; i++)
> ctx->offset[i] += prologue_len;
> @@ -183,14 +163,19 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> kfree(jit_data);
> prog->aux->jit_data = NULL;
> }
> -out:
> +
> if (HPPA_JIT_REBOOT)
> { extern int machine_restart(char *); machine_restart(""); }
>
> - if (tmp_blinded)
> - bpf_jit_prog_release_other(prog, prog == orig_prog ?
> - tmp : orig_prog);
> return prog;
> +
> +out_err:
> + if (extra_pass) {
> + prog->bpf_func = NULL;
> + prog->jited = 0;
> + prog->jited_len = 0;
> + }
> + goto out_offset;
> }
>
> u64 hppa_div64(u64 div, u64 divisor)
> diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
> index a62a9a92b7b5..711028bebea3 100644
> --- a/arch/powerpc/net/bpf_jit_comp.c
> +++ b/arch/powerpc/net/bpf_jit_comp.c
> @@ -142,9 +142,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> int flen;
> struct bpf_binary_header *fhdr = NULL;
> struct bpf_binary_header *hdr = NULL;
> - struct bpf_prog *org_fp = fp;
> - struct bpf_prog *tmp_fp;
> - bool bpf_blinded = false;
> bool extra_pass = false;
> u8 *fimage = NULL;
> u32 *fcode_base;
> @@ -152,24 +149,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> u32 fixup_len;
>
> if (!fp->jit_requested)
> - return org_fp;
> -
> - tmp_fp = bpf_jit_blind_constants(org_fp);
> - if (IS_ERR(tmp_fp))
> - return org_fp;
> -
> - if (tmp_fp != org_fp) {
> - bpf_blinded = true;
> - fp = tmp_fp;
> - }
> + return fp;
>
> jit_data = fp->aux->jit_data;
> if (!jit_data) {
> jit_data = kzalloc_obj(*jit_data);
> - if (!jit_data) {
> - fp = org_fp;
> - goto out;
> - }
> + if (!jit_data)
> + return fp;
> fp->aux->jit_data = jit_data;
> }
>
> @@ -194,10 +180,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> }
>
> addrs = kcalloc(flen + 1, sizeof(*addrs), GFP_KERNEL);
> - if (addrs == NULL) {
> - fp = org_fp;
> - goto out_addrs;
> - }
> + if (addrs == NULL)
> + goto out_err;
>
> memset(&cgctx, 0, sizeof(struct codegen_context));
> bpf_jit_init_reg_mapping(&cgctx);
> @@ -211,11 +195,9 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> cgctx.exception_cb = fp->aux->exception_cb;
>
> /* Scouting faux-generate pass 0 */
> - if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false)) {
> + if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false))
> /* We hit something illegal or unsupported. */
> - fp = org_fp;
> - goto out_addrs;
> - }
> + goto out_err;
>
> /*
> * If we have seen a tail call, we need a second pass.
> @@ -226,10 +208,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> */
> if (cgctx.seen & SEEN_TAILCALL || !is_offset_in_branch_range((long)cgctx.idx * 4)) {
> cgctx.idx = 0;
> - if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false)) {
> - fp = org_fp;
> - goto out_addrs;
> - }
> + if (bpf_jit_build_body(fp, NULL, NULL, &cgctx, addrs, 0, false))
> + goto out_err;
> }
>
> bpf_jit_realloc_regs(&cgctx);
> @@ -250,10 +230,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>
> fhdr = bpf_jit_binary_pack_alloc(alloclen, &fimage, 4, &hdr, &image,
> bpf_jit_fill_ill_insns);
> - if (!fhdr) {
> - fp = org_fp;
> - goto out_addrs;
> - }
> + if (!fhdr)
> + goto out_err;
>
> if (extable_len)
> fp->aux->extable = (void *)fimage + FUNCTION_DESCR_SIZE + proglen + fixup_len;
> @@ -272,8 +250,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> extra_pass)) {
> bpf_arch_text_copy(&fhdr->size, &hdr->size, sizeof(hdr->size));
> bpf_jit_binary_pack_free(fhdr, hdr);
> - fp = org_fp;
> - goto out_addrs;
> + goto out_err;
> }
> bpf_jit_build_epilogue(code_base, &cgctx);
>
> @@ -295,15 +272,16 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> ((u64 *)image)[1] = local_paca->kernel_toc;
> #endif
>
> + if (!fp->is_func || extra_pass) {
> + if (bpf_jit_binary_pack_finalize(fhdr, hdr))
> + goto out_err;
> + }
> +
> fp->bpf_func = (void *)fimage;
> fp->jited = 1;
> fp->jited_len = cgctx.idx * 4 + FUNCTION_DESCR_SIZE;
>
> if (!fp->is_func || extra_pass) {
> - if (bpf_jit_binary_pack_finalize(fhdr, hdr)) {
> - fp = org_fp;
> - goto out_addrs;
> - }
> bpf_prog_fill_jited_linfo(fp, addrs);
> out_addrs:
> kfree(addrs);
> @@ -318,11 +296,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> jit_data->hdr = hdr;
> }
>
> -out:
> - if (bpf_blinded)
> - bpf_jit_prog_release_other(fp, fp == org_fp ? tmp_fp : org_fp);
> -
> return fp;
> +
> +out_err:
> + if (extra_pass) {
> + fp->bpf_func = NULL;
> + fp->jited = 0;
> + fp->jited_len = 0;
> + }
> + goto out_addrs;
> }
>
> /*
> diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c
> index b3581e926436..527baa50dc68 100644
> --- a/arch/riscv/net/bpf_jit_core.c
> +++ b/arch/riscv/net/bpf_jit_core.c
> @@ -44,29 +44,19 @@ bool bpf_jit_needs_zext(void)
> struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> {
> unsigned int prog_size = 0, extable_size = 0;
> - bool tmp_blinded = false, extra_pass = false;
> - struct bpf_prog *tmp, *orig_prog = prog;
> + bool extra_pass = false;
> int pass = 0, prev_ninsns = 0, i;
> struct rv_jit_data *jit_data;
> struct rv_jit_context *ctx;
>
> if (!prog->jit_requested)
> - return orig_prog;
> -
> - tmp = bpf_jit_blind_constants(prog);
> - if (IS_ERR(tmp))
> - return orig_prog;
> - if (tmp != prog) {
> - tmp_blinded = true;
> - prog = tmp;
> - }
> + return prog;
>
> jit_data = prog->aux->jit_data;
> if (!jit_data) {
> jit_data = kzalloc_obj(*jit_data);
> if (!jit_data) {
> - prog = orig_prog;
> - goto out;
> + return prog;
> }
> prog->aux->jit_data = jit_data;
> }
> @@ -83,15 +73,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> ctx->user_vm_start = bpf_arena_get_user_vm_start(prog->aux->arena);
> ctx->prog = prog;
> ctx->offset = kzalloc_objs(int, prog->len);
> - if (!ctx->offset) {
> - prog = orig_prog;
> + if (!ctx->offset)
> goto out_offset;
> - }
>
> - if (build_body(ctx, extra_pass, NULL)) {
> - prog = orig_prog;
> + if (build_body(ctx, extra_pass, NULL))
> goto out_offset;
> - }
>
> for (i = 0; i < prog->len; i++) {
> prev_ninsns += 32;
> @@ -105,10 +91,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> bpf_jit_build_prologue(ctx, bpf_is_subprog(prog));
> ctx->prologue_len = ctx->ninsns;
>
> - if (build_body(ctx, extra_pass, ctx->offset)) {
> - prog = orig_prog;
> + if (build_body(ctx, extra_pass, ctx->offset))
> goto out_offset;
> - }
>
> ctx->epilogue_offset = ctx->ninsns;
> bpf_jit_build_epilogue(ctx);
> @@ -126,10 +110,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> &jit_data->ro_image, sizeof(u32),
> &jit_data->header, &jit_data->image,
> bpf_fill_ill_insns);
> - if (!jit_data->ro_header) {
> - prog = orig_prog;
> + if (!jit_data->ro_header)
> goto out_offset;
> - }
>
> /*
> * Use the image(RW) for writing the JITed instructions. But also save
> @@ -150,7 +132,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>
> if (i == NR_JIT_ITERATIONS) {
> pr_err("bpf-jit: image did not converge in <%d passes!\n", i);
> - prog = orig_prog;
> goto out_free_hdr;
> }
>
> @@ -163,26 +144,27 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> ctx->nexentries = 0;
>
> bpf_jit_build_prologue(ctx, bpf_is_subprog(prog));
> - if (build_body(ctx, extra_pass, NULL)) {
> - prog = orig_prog;
> + if (build_body(ctx, extra_pass, NULL))
> goto out_free_hdr;
> - }
> bpf_jit_build_epilogue(ctx);
>
> if (bpf_jit_enable > 1)
> bpf_jit_dump(prog->len, prog_size, pass, ctx->insns);
>
> - prog->bpf_func = (void *)ctx->ro_insns + cfi_get_offset();
> - prog->jited = 1;
> - prog->jited_len = prog_size - cfi_get_offset();
> -
> if (!prog->is_func || extra_pass) {
> if (WARN_ON(bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header))) {
> /* ro_header has been freed */
> jit_data->ro_header = NULL;
> - prog = orig_prog;
> - goto out_offset;
> + jit_data->header = NULL;
> + goto out_free_hdr;
> }
> + }
> +
> + prog->bpf_func = (void *)ctx->ro_insns + cfi_get_offset();
> + prog->jited = 1;
> + prog->jited_len = prog_size - cfi_get_offset();
> +
> + if (!prog->is_func || extra_pass) {
> /*
> * The instructions have now been copied to the ROX region from
> * where they will execute.
> @@ -198,14 +180,15 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> kfree(jit_data);
> prog->aux->jit_data = NULL;
> }
> -out:
>
> - if (tmp_blinded)
> - bpf_jit_prog_release_other(prog, prog == orig_prog ?
> - tmp : orig_prog);
> return prog;
>
> out_free_hdr:
> + if (extra_pass) {
> + prog->bpf_func = NULL;
> + prog->jited = 0;
> + prog->jited_len = 0;
> + }
> if (jit_data->header) {
> bpf_arch_text_copy(&jit_data->ro_header->size, &jit_data->header->size,
> sizeof(jit_data->header->size));
> diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
> index d08d159b6319..2dfc279b1be2 100644
> --- a/arch/s390/net/bpf_jit_comp.c
> +++ b/arch/s390/net/bpf_jit_comp.c
> @@ -2314,36 +2314,20 @@ static struct bpf_binary_header *bpf_jit_alloc(struct bpf_jit *jit,
> */
> struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> {
> - struct bpf_prog *tmp, *orig_fp = fp;
> struct bpf_binary_header *header;
> struct s390_jit_data *jit_data;
> - bool tmp_blinded = false;
> bool extra_pass = false;
> struct bpf_jit jit;
> int pass;
>
> if (!fp->jit_requested)
> - return orig_fp;
> -
> - tmp = bpf_jit_blind_constants(fp);
> - /*
> - * If blinding was requested and we failed during blinding,
> - * we must fall back to the interpreter.
> - */
> - if (IS_ERR(tmp))
> - return orig_fp;
> - if (tmp != fp) {
> - tmp_blinded = true;
> - fp = tmp;
> - }
> + return fp;
>
> jit_data = fp->aux->jit_data;
> if (!jit_data) {
> jit_data = kzalloc_obj(*jit_data);
> - if (!jit_data) {
> - fp = orig_fp;
> - goto out;
> - }
> + if (!jit_data)
> + return fp;
> fp->aux->jit_data = jit_data;
> }
> if (jit_data->ctx.addrs) {
> @@ -2356,34 +2340,27 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
>
> memset(&jit, 0, sizeof(jit));
> jit.addrs = kvcalloc(fp->len + 1, sizeof(*jit.addrs), GFP_KERNEL);
> - if (jit.addrs == NULL) {
> - fp = orig_fp;
> - goto free_addrs;
> - }
> + if (jit.addrs == NULL)
> + goto out_err;
> /*
> * Three initial passes:
> * - 1/2: Determine clobbered registers
> * - 3: Calculate program size and addrs array
> */
> for (pass = 1; pass <= 3; pass++) {
> - if (bpf_jit_prog(&jit, fp, extra_pass)) {
> - fp = orig_fp;
> - goto free_addrs;
> - }
> + if (bpf_jit_prog(&jit, fp, extra_pass))
> + goto out_err;
> }
> /*
> * Final pass: Allocate and generate program
> */
> header = bpf_jit_alloc(&jit, fp);
> - if (!header) {
> - fp = orig_fp;
> - goto free_addrs;
> - }
> + if (!header)
> + goto out_err;
> skip_init_ctx:
> if (bpf_jit_prog(&jit, fp, extra_pass)) {
> bpf_jit_binary_free(header);
> - fp = orig_fp;
> - goto free_addrs;
> + goto out_err;
> }
> if (bpf_jit_enable > 1) {
> bpf_jit_dump(fp->len, jit.size, pass, jit.prg_buf);
> @@ -2392,8 +2369,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> if (!fp->is_func || extra_pass) {
> if (bpf_jit_binary_lock_ro(header)) {
> bpf_jit_binary_free(header);
> - fp = orig_fp;
> - goto free_addrs;
> + goto out_err;
> }
> } else {
> jit_data->header = header;
> @@ -2411,11 +2387,16 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)
> kfree(jit_data);
> fp->aux->jit_data = NULL;
> }
> -out:
> - if (tmp_blinded)
> - bpf_jit_prog_release_other(fp, fp == orig_fp ?
> - tmp : orig_fp);
> +
> return fp;
> +
> +out_err:
> + if (extra_pass) {
> + fp->bpf_func = NULL;
> + fp->jited = 0;
> + fp->jited_len = 0;
> + }
> + goto free_addrs;
> }
>
> bool bpf_jit_supports_kfunc_call(void)
> diff --git a/arch/sparc/net/bpf_jit_comp_64.c b/arch/sparc/net/bpf_jit_comp_64.c
> index b23d1c645ae5..e83e29137566 100644
> --- a/arch/sparc/net/bpf_jit_comp_64.c
> +++ b/arch/sparc/net/bpf_jit_comp_64.c
> @@ -1479,37 +1479,22 @@ struct sparc64_jit_data {
>
> struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> {
> - struct bpf_prog *tmp, *orig_prog = prog;
> struct sparc64_jit_data *jit_data;
> struct bpf_binary_header *header;
> u32 prev_image_size, image_size;
> - bool tmp_blinded = false;
> bool extra_pass = false;
> struct jit_ctx ctx;
> u8 *image_ptr;
> int pass, i;
>
> if (!prog->jit_requested)
> - return orig_prog;
> -
> - tmp = bpf_jit_blind_constants(prog);
> - /* If blinding was requested and we failed during blinding,
> - * we must fall back to the interpreter.
> - */
> - if (IS_ERR(tmp))
> - return orig_prog;
> - if (tmp != prog) {
> - tmp_blinded = true;
> - prog = tmp;
> - }
> + return prog;
>
> jit_data = prog->aux->jit_data;
> if (!jit_data) {
> jit_data = kzalloc_obj(*jit_data);
> - if (!jit_data) {
> - prog = orig_prog;
> - goto out;
> - }
> + if (!jit_data)
> + return prog;
> prog->aux->jit_data = jit_data;
> }
> if (jit_data->ctx.offset) {
> @@ -1527,10 +1512,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> ctx.prog = prog;
>
> ctx.offset = kmalloc_array(prog->len, sizeof(unsigned int), GFP_KERNEL);
> - if (ctx.offset == NULL) {
> - prog = orig_prog;
> - goto out_off;
> - }
> + if (ctx.offset == NULL)
> + goto out_err;
>
> /* Longest sequence emitted is for bswap32, 12 instructions. Pre-cook
> * the offset array so that we converge faster.
> @@ -1543,10 +1526,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> ctx.idx = 0;
>
> build_prologue(&ctx);
> - if (build_body(&ctx)) {
> - prog = orig_prog;
> - goto out_off;
> - }
> + if (build_body(&ctx))
> + goto out_err;
> build_epilogue(&ctx);
>
> if (bpf_jit_enable > 1)
> @@ -1569,10 +1550,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> image_size = sizeof(u32) * ctx.idx;
> header = bpf_jit_binary_alloc(image_size, &image_ptr,
> sizeof(u32), jit_fill_hole);
> - if (header == NULL) {
> - prog = orig_prog;
> - goto out_off;
> - }
> + if (header == NULL)
> + goto out_err;
>
> ctx.image = (u32 *)image_ptr;
> skip_init_ctx:
> @@ -1582,8 +1561,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
>
> if (build_body(&ctx)) {
> bpf_jit_binary_free(header);
> - prog = orig_prog;
> - goto out_off;
> + goto out_err;
> }
>
> build_epilogue(&ctx);
> @@ -1592,8 +1570,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> pr_err("bpf_jit: Failed to converge, prev_size=%u size=%d\n",
> prev_image_size, ctx.idx * 4);
> bpf_jit_binary_free(header);
> - prog = orig_prog;
> - goto out_off;
> + goto out_err;
> }
>
> if (bpf_jit_enable > 1)
> @@ -1604,8 +1581,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> if (!prog->is_func || extra_pass) {
> if (bpf_jit_binary_lock_ro(header)) {
> bpf_jit_binary_free(header);
> - prog = orig_prog;
> - goto out_off;
> + goto out_err;
> }
> } else {
> jit_data->ctx = ctx;
> @@ -1624,9 +1600,14 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> kfree(jit_data);
> prog->aux->jit_data = NULL;
> }
> -out:
> - if (tmp_blinded)
> - bpf_jit_prog_release_other(prog, prog == orig_prog ?
> - tmp : orig_prog);
> +
> return prog;
> +
> +out_err:
> + if (extra_pass) {
> + prog->bpf_func = NULL;
> + prog->jited = 0;
> + prog->jited_len = 0;
> + }
> + goto out_off;
> }
> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> index e9b78040d703..77d00a8dec87 100644
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
> @@ -3717,13 +3717,11 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> {
> struct bpf_binary_header *rw_header = NULL;
> struct bpf_binary_header *header = NULL;
> - struct bpf_prog *tmp, *orig_prog = prog;
> void __percpu *priv_stack_ptr = NULL;
> struct x64_jit_data *jit_data;
> int priv_stack_alloc_sz;
> int proglen, oldproglen = 0;
> struct jit_context ctx = {};
> - bool tmp_blinded = false;
> bool extra_pass = false;
> bool padding = false;
> u8 *rw_image = NULL;
> @@ -3733,27 +3731,13 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> int i;
>
> if (!prog->jit_requested)
> - return orig_prog;
> -
> - tmp = bpf_jit_blind_constants(prog);
> - /*
> - * If blinding was requested and we failed during blinding,
> - * we must fall back to the interpreter.
> - */
> - if (IS_ERR(tmp))
> - return orig_prog;
> - if (tmp != prog) {
> - tmp_blinded = true;
> - prog = tmp;
> - }
> + return prog;
>
> jit_data = prog->aux->jit_data;
> if (!jit_data) {
> jit_data = kzalloc_obj(*jit_data);
> - if (!jit_data) {
> - prog = orig_prog;
> - goto out;
> - }
> + if (!jit_data)
> + return prog;
> prog->aux->jit_data = jit_data;
> }
> priv_stack_ptr = prog->aux->priv_stack_ptr;
> @@ -3765,10 +3749,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> priv_stack_alloc_sz = round_up(prog->aux->stack_depth, 8) +
> 2 * PRIV_STACK_GUARD_SZ;
> priv_stack_ptr = __alloc_percpu_gfp(priv_stack_alloc_sz, 8, GFP_KERNEL);
> - if (!priv_stack_ptr) {
> - prog = orig_prog;
> + if (!priv_stack_ptr)
> goto out_priv_stack;
> - }
>
> priv_stack_init_guard(priv_stack_ptr, priv_stack_alloc_sz);
> prog->aux->priv_stack_ptr = priv_stack_ptr;
> @@ -3786,10 +3768,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> goto skip_init_addrs;
> }
> addrs = kvmalloc_objs(*addrs, prog->len + 1);
> - if (!addrs) {
> - prog = orig_prog;
> + if (!addrs)
> goto out_addrs;
> - }
>
> /*
> * Before first pass, make a rough estimation of addrs[]
> @@ -3820,8 +3800,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> sizeof(rw_header->size));
> bpf_jit_binary_pack_free(header, rw_header);
> }
> - /* Fall back to interpreter mode */
> - prog = orig_prog;
> if (extra_pass) {
> prog->bpf_func = NULL;
> prog->jited = 0;
> @@ -3852,10 +3830,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size,
> &image, align, &rw_header, &rw_image,
> jit_fill_hole);
> - if (!header) {
> - prog = orig_prog;
> + if (!header)
> goto out_addrs;
> - }
> prog->aux->extable = (void *) image + roundup(proglen, align);
> }
> oldproglen = proglen;
> @@ -3908,8 +3884,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> prog->bpf_func = (void *)image + cfi_get_offset();
> prog->jited = 1;
> prog->jited_len = proglen - cfi_get_offset();
> - } else {
> - prog = orig_prog;
> }
>
> if (!image || !prog->is_func || extra_pass) {
> @@ -3925,10 +3899,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> kfree(jit_data);
> prog->aux->jit_data = NULL;
> }
> -out:
> - if (tmp_blinded)
> - bpf_jit_prog_release_other(prog, prog == orig_prog ?
> - tmp : orig_prog);
> +
> return prog;
> }
>
> diff --git a/arch/x86/net/bpf_jit_comp32.c b/arch/x86/net/bpf_jit_comp32.c
> index dda423025c3d..5f259577614a 100644
> --- a/arch/x86/net/bpf_jit_comp32.c
> +++ b/arch/x86/net/bpf_jit_comp32.c
> @@ -2521,35 +2521,19 @@ bool bpf_jit_needs_zext(void)
> struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> {
> struct bpf_binary_header *header = NULL;
> - struct bpf_prog *tmp, *orig_prog = prog;
> int proglen, oldproglen = 0;
> struct jit_context ctx = {};
> - bool tmp_blinded = false;
> u8 *image = NULL;
> int *addrs;
> int pass;
> int i;
>
> if (!prog->jit_requested)
> - return orig_prog;
> -
> - tmp = bpf_jit_blind_constants(prog);
> - /*
> - * If blinding was requested and we failed during blinding,
> - * we must fall back to the interpreter.
> - */
> - if (IS_ERR(tmp))
> - return orig_prog;
> - if (tmp != prog) {
> - tmp_blinded = true;
> - prog = tmp;
> - }
> + return prog;
>
> addrs = kmalloc_objs(*addrs, prog->len);
> - if (!addrs) {
> - prog = orig_prog;
> - goto out;
> - }
> + if (!addrs)
> + return prog;
>
> /*
> * Before first pass, make a rough estimation of addrs[]
> @@ -2574,7 +2558,6 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> image = NULL;
> if (header)
> bpf_jit_binary_free(header);
> - prog = orig_prog;
> goto out_addrs;
> }
> if (image) {
> @@ -2588,10 +2571,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> if (proglen == oldproglen) {
> header = bpf_jit_binary_alloc(proglen, &image,
> 1, jit_fill_hole);
> - if (!header) {
> - prog = orig_prog;
> + if (!header)
> goto out_addrs;
> - }
> }
> oldproglen = proglen;
> cond_resched();
> @@ -2604,16 +2585,10 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
> prog->bpf_func = (void *)image;
> prog->jited = 1;
> prog->jited_len = proglen;
> - } else {
> - prog = orig_prog;
> }
>
> out_addrs:
> kfree(addrs);
> -out:
> - if (tmp_blinded)
> - bpf_jit_prog_release_other(prog, prog == orig_prog ?
> - tmp : orig_prog);
> return prog;
> }
>
> diff --git a/include/linux/filter.h b/include/linux/filter.h
> index e40d4071a345..d396e55c9a1d 100644
> --- a/include/linux/filter.h
> +++ b/include/linux/filter.h
> @@ -1183,6 +1183,18 @@ static inline bool bpf_dump_raw_ok(const struct cred *cred)
>
> struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
> const struct bpf_insn *patch, u32 len);
> +
> +#ifdef CONFIG_BPF_SYSCALL
> +struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
> + const struct bpf_insn *patch, u32 len);
> +#else
> +static inline struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
> + const struct bpf_insn *patch, u32 len)
> +{
> + return ERR_PTR(-ENOTSUPP);
> +}
> +#endif /* CONFIG_BPF_SYSCALL */
> +
> int bpf_remove_insns(struct bpf_prog *prog, u32 off, u32 cnt);
>
> static inline bool xdp_return_frame_no_direct(void)
> @@ -1309,9 +1321,14 @@ int bpf_jit_get_func_addr(const struct bpf_prog *prog,
>
> const char *bpf_jit_get_prog_name(struct bpf_prog *prog);
>
> -struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *fp);
> +struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bpf_prog *prog);
> void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other);
>
> +static inline bool bpf_prog_need_blind(const struct bpf_prog *prog)
> +{
> + return prog->blinding_requested && !prog->blinded;
> +}
> +
> static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen,
> u32 pass, void *image)
> {
> @@ -1450,6 +1467,20 @@ static inline void bpf_prog_kallsyms_del(struct bpf_prog *fp)
> {
> }
>
> +static inline bool bpf_prog_need_blind(const struct bpf_prog *prog)
> +{
> + return false;
> +}
> +
> +static inline
> +struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bpf_prog *prog)
> +{
> + return prog;
> +}
> +
> +static inline void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other)
> +{
> +}
> #endif /* CONFIG_BPF_JIT */
>
> void bpf_prog_kallsyms_del_all(struct bpf_prog *fp);
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index 1af5fb3f21d9..cc61fe57b98d 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -1506,7 +1506,10 @@ static void adjust_insn_arrays(struct bpf_prog *prog, u32 off, u32 len)
> #endif
> }
>
> -struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
> +/* Now this function is used only to blind the main prog and must be invoked only when
> + * bpf_prog_need_blind() returns true.
> + */
> +struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bpf_prog *prog)
> {
> struct bpf_insn insn_buff[16], aux[2];
> struct bpf_prog *clone, *tmp;
> @@ -1514,13 +1517,17 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
> struct bpf_insn *insn;
> int i, rewritten;
>
> - if (!prog->blinding_requested || prog->blinded)
> - return prog;
> + if (env)
> + prog = env->prog;
>
> clone = bpf_prog_clone_create(prog, GFP_USER);
> if (!clone)
> return ERR_PTR(-ENOMEM);
>
> + /* make sure bpf_patch_insn_data() patches the correct prog */
> + if (env)
> + env->prog = clone;
> +
> insn_cnt = clone->len;
> insn = clone->insnsi;
>
> @@ -1548,21 +1555,34 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
> if (!rewritten)
> continue;
>
> - tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
> - if (IS_ERR(tmp)) {
> + if (env)
> + tmp = bpf_patch_insn_data(env, i, insn_buff, rewritten);
> + else
> + tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
> +
> + if (IS_ERR_OR_NULL(tmp)) {
> + if (env)
> + /* restore the original prog */
> + env->prog = prog;
> /* Patching may have repointed aux->prog during
> * realloc from the original one, so we need to
> * fix it up here on error.
> */
> bpf_jit_prog_release_other(prog, clone);
> - return tmp;
> + return IS_ERR(tmp) ? tmp : ERR_PTR(-ENOMEM);
> }
>
> clone = tmp;
> insn_delta = rewritten - 1;
>
> - /* Instructions arrays must be updated using absolute xlated offsets */
> - adjust_insn_arrays(clone, prog->aux->subprog_start + i, rewritten);
> + if (env)
> + env->prog = clone;
> + else
> + /* Instructions arrays must be updated using absolute xlated offsets.
> + * The arrays have already been adjusted by bpf_patch_insn_data() when
> + * env is not NULL.
> + */
> + adjust_insn_arrays(clone, i, rewritten);
>
> /* Walk new program and skip insns we just inserted. */
> insn = clone->insnsi + i + insn_delta;
> @@ -2531,6 +2551,35 @@ static bool bpf_prog_select_interpreter(struct bpf_prog *fp)
> return select_interpreter;
> }
>
> +static struct bpf_prog *bpf_prog_jit_compile(struct bpf_prog *prog)
> +{
> +#ifdef CONFIG_BPF_JIT
> + bool blinded = false;
> + struct bpf_prog *orig_prog = prog;
> +
> + if (bpf_prog_need_blind(orig_prog)) {
> + prog = bpf_jit_blind_constants(NULL, orig_prog);
> + /* If blinding was requested and we failed during blinding, we must fall
> + * back to the interpreter.
> + */
> + if (IS_ERR(prog))
> + return orig_prog;
> + blinded = true;
> + }
> +
> + prog = bpf_int_jit_compile(prog);
> + if (blinded) {
> + if (!prog->jited) {
> + bpf_jit_prog_release_other(orig_prog, prog);
> + prog = orig_prog;
> + } else {
> + bpf_jit_prog_release_other(prog, orig_prog);
> + }
> + }
> +#endif
> + return prog;
> +}
> +
> /**
> * bpf_prog_select_runtime - select exec runtime for BPF program
> * @fp: bpf_prog populated with BPF program
> @@ -2570,7 +2619,7 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
> if (*err)
> return fp;
>
> - fp = bpf_int_jit_compile(fp);
> + fp = bpf_prog_jit_compile(fp);
> bpf_prog_jit_attempt_done(fp);
> if (!fp->jited && jit_needed) {
> *err = -ENOTSUPP;
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index a431b7d50e1b..66cef3744fde 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -22215,8 +22215,8 @@ static void adjust_poke_descs(struct bpf_prog *prog, u32 off, u32 len)
> }
> }
>
> -static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
> - const struct bpf_insn *patch, u32 len)
> +struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
> + const struct bpf_insn *patch, u32 len)
> {
> struct bpf_prog *new_prog;
> struct bpf_insn_aux_data *new_data = NULL;
> @@ -22983,7 +22983,41 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
> return 0;
> }
>
> -static int jit_subprogs(struct bpf_verifier_env *env)
> +static u32 *dup_subprog_starts(struct bpf_verifier_env *env)
> +{
> + u32 *starts = NULL;
> +
> + starts = kvmalloc_objs(u32, env->subprog_cnt, GFP_KERNEL_ACCOUNT);
> + if (!starts)
> + return NULL;
> + for (int i = 0; i < env->subprog_cnt; i++)
> + starts[i] = env->subprog_info[i].start;
> + return starts;
> +}
> +
> +static void restore_subprog_starts(struct bpf_verifier_env *env, u32 *orig_starts)
> +{
> + for (int i = 0; i < env->subprog_cnt; i++)
> + env->subprog_info[i].start = orig_starts[i];
> +}
> +
> +static struct bpf_insn_aux_data *dup_insn_aux_data(struct bpf_verifier_env *env)
> +{
> + size_t size;
> +
> + size = array_size(sizeof(struct bpf_insn_aux_data), env->prog->len);
> + return kvmemdup(env->insn_aux_data, size, GFP_KERNEL_ACCOUNT);
> +}
> +
> +static void restore_insn_aux_data(struct bpf_verifier_env *env,
> + struct bpf_insn_aux_data *orig_insn_aux)
> +{
> + /* the expanded elements are zero-filled, so no special handling is required */
> + vfree(env->insn_aux_data);
> + env->insn_aux_data = orig_insn_aux;
> +}
> +
> +static int __jit_subprogs(struct bpf_verifier_env *env)
> {
> struct bpf_prog *prog = env->prog, **func, *tmp;
> int i, j, subprog_start, subprog_end = 0, len, subprog;
> @@ -22991,10 +23025,6 @@ static int jit_subprogs(struct bpf_verifier_env *env)
> struct bpf_insn *insn;
> void *old_bpf_func;
> int err, num_exentries;
> - int old_len, subprog_start_adjustment = 0;
> -
> - if (env->subprog_cnt <= 1)
> - return 0;
>
> for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
> if (!bpf_pseudo_func(insn) && !bpf_pseudo_call(insn))
> @@ -23063,10 +23093,11 @@ static int jit_subprogs(struct bpf_verifier_env *env)
> goto out_free;
> func[i]->is_func = 1;
> func[i]->sleepable = prog->sleepable;
> + func[i]->blinded = prog->blinded;
> func[i]->aux->func_idx = i;
> /* Below members will be freed only at prog->aux */
> func[i]->aux->btf = prog->aux->btf;
> - func[i]->aux->subprog_start = subprog_start + subprog_start_adjustment;
> + func[i]->aux->subprog_start = subprog_start;
> func[i]->aux->func_info = prog->aux->func_info;
> func[i]->aux->func_info_cnt = prog->aux->func_info_cnt;
> func[i]->aux->poke_tab = prog->aux->poke_tab;
> @@ -23122,15 +23153,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
> func[i]->aux->might_sleep = env->subprog_info[i].might_sleep;
> if (!i)
> func[i]->aux->exception_boundary = env->seen_exception;
> -
> - /*
> - * To properly pass the absolute subprog start to jit
> - * all instruction adjustments should be accumulated
> - */
> - old_len = func[i]->len;
> func[i] = bpf_int_jit_compile(func[i]);
> - subprog_start_adjustment += func[i]->len - old_len;
> -
> if (!func[i]->jited) {
> err = -ENOTSUPP;
> goto out_free;
> @@ -23256,16 +23279,83 @@ static int jit_subprogs(struct bpf_verifier_env *env)
> }
> kfree(func);
> out_undo_insn:
> + bpf_prog_jit_attempt_done(prog);
> + return err;
> +}
> +
> +static int jit_subprogs(struct bpf_verifier_env *env)
> +{
> + int err, i;
> + bool blinded = false;
> + struct bpf_insn *insn;
> + struct bpf_prog *prog, *orig_prog;
> + struct bpf_insn_aux_data *orig_insn_aux;
> + u32 *orig_subprog_starts;
> +
> + if (env->subprog_cnt <= 1)
> + return 0;
> +
> + prog = orig_prog = env->prog;
> + if (bpf_prog_need_blind(orig_prog)) {
> + orig_insn_aux = dup_insn_aux_data(env);
> + if (!orig_insn_aux) {
> + err = -ENOMEM;
> + goto out_cleanup;
> + }
> + orig_subprog_starts = dup_subprog_starts(env);
> + if (!orig_subprog_starts) {
> + err = -ENOMEM;
> + goto out_free_aux;
> + }
> + prog = bpf_jit_blind_constants(env, NULL);
> + if (IS_ERR(prog)) {
> + err = -ENOMEM;
> + prog = orig_prog;
> + goto out_restore;
> + }
> + blinded = true;
> + }
> +
> + err = __jit_subprogs(env);
> + if (blinded) {
> + if (err) {
> + bpf_jit_prog_release_other(orig_prog, prog);
> + /* roll back to the clean original prog */
> + prog = env->prog = orig_prog;
> + goto out_restore;
> + } else {
> + bpf_jit_prog_release_other(prog, orig_prog);
> + kvfree(orig_subprog_starts);
> + kvfree(orig_insn_aux);
> + }
> + } else if (err) {
> + /* We will fall back to interpreter mode when err is not -EFAULT, before
> + * that, insn->off and insn->imm should be restored to their original values
> + * since they were modified by __jit_subprogs.
> + */
> + if (err != -EFAULT) {
> + for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
> + if (!bpf_pseudo_call(insn))
> + continue;
> + insn->off = 0;
> + insn->imm = env->insn_aux_data[i].call_imm;
> + }
> + }
> + goto out_cleanup;
> + }
Nit: The if/else branching and fallthroughs are not immediately clear
here. You could remove some of it if you did:
if (blinded) {
if (err) {
...
goto out_restore;
}
bpf_jit_prog_release_other();
...
return 0;
}
/* Else !blinded */
if (!err)
return 0;
/* Else err != 0*/
if (err == -EFAULT)
...
> +
> + return 0;
> +
> +out_restore:
> + restore_subprog_starts(env, orig_subprog_starts);
> + restore_insn_aux_data(env, orig_insn_aux);
> + kvfree(orig_subprog_starts);
> +out_free_aux:
> + kvfree(orig_insn_aux);
> +out_cleanup:
> /* cleanup main prog to be interpreted */
> prog->jit_requested = 0;
> prog->blinding_requested = 0;
> - for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
> - if (!bpf_pseudo_call(insn))
> - continue;
> - insn->off = 0;
> - insn->imm = env->insn_aux_data[i].call_imm;
> - }
> - bpf_prog_jit_attempt_done(prog);
> return err;
> }
>
^ permalink raw reply
* Re: [GIT PULL] ARM: dts: updates for ti/omap for v7.1
From: Kevin Hilman @ 2026-04-03 16:01 UTC (permalink / raw)
To: Arnd Bergmann, soc; +Cc: Linux-OMAP, linux-arm-kernel
In-Reply-To: <83d0c8d8-fcde-4407-bb09-c2ae0e0e142d@app.fastmail.com>
"Arnd Bergmann" <arnd@arndb.de> writes:
> On Wed, Apr 1, 2026, at 23:29, Kevin Hilman wrote:
>>
>> ----------------------------------------------------------------
>> ARM: dts: updates for ti/omap for v7.1
>>
>
> Hi Kevin,
>
> I applied this one, but I noticed two problems:
>
> There is no long form changelog text, please add
> more information about what is in the branch in
> the future. I've added a short paragraph while
> applying.
Sorry about that, and thanks for fixing it up.
>> +-
>> arch/arm/boot/dts/ti/omap/omap4-samsung-espresso-common.dtsi | 744
>> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> arch/arm/boot/dts/ti/omap/omap4-samsung-espresso10.dts | 101
>> +++++++++++++++++++++
>> arch/arm/boot/dts/ti/omap/omap4-samsung-espresso7.dts | 70
>> +++++++++++++++
>> arch/arm/boot/dts/ti/omap/omap5-l4.dtsi | 2
>
> Something went wrong with the overly long lines here.
Hmm, not sure what happened there.
Thanks,
Kevin
^ permalink raw reply
* Re: [PATCH net] net: airoha: Fix memory leak in airoha_qdma_rx_process()
From: Simon Horman @ 2026-04-03 15:59 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260402-airoha_qdma_rx_process-mem-leak-fix-v1-1-b5706f402d3c@kernel.org>
On Thu, Apr 02, 2026 at 02:57:10PM +0200, Lorenzo Bianconi wrote:
> If an error occurs on the subsequents buffers belonging to the
> non-linear part of the skb (e.g. due to an error in the payload length
> reported by the NIC or if we consumed all the available fragments for
> the skb), the page_pool fragment will not be linked to the skb so it will
> not return to the pool in the airoha_qdma_rx_process() error path. Fix the
> memory leak partially reverting commit 'd6d2b0e1538d ("net: airoha: Fix
> page recycling in airoha_qdma_rx_process()")' and always running
> page_pool_put_full_page routine in the airoha_qdma_rx_process() error
> path.
>
> Fixes: d6d2b0e1538d ("net: airoha: Fix page recycling in airoha_qdma_rx_process()")
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply
* Re: [PATCH v20 06/10] power: reset: Add psci-reboot-mode driver
From: Lorenzo Pieralisi @ 2026-04-03 15:50 UTC (permalink / raw)
To: Shivendra Pratap
Cc: Arnd Bergmann, Bjorn Andersson, Sebastian Reichel, Rob Herring,
Souvik Chakravarty, Krzysztof Kozlowski, Andy Yan,
Matthias Brugger, Mark Rutland, Conor Dooley, Konrad Dybcio,
John Stultz, Moritz Fischer, Bartosz Golaszewski, Sudeep Holla,
Florian Fainelli, Krzysztof Kozlowski, Dmitry Baryshkov,
Mukesh Ojha, Andre Draszik, Kathiravan Thirumoorthy, linux-pm,
linux-kernel, linux-arm-kernel, linux-arm-msm, devicetree,
Srinivas Kandagatla
In-Reply-To: <da6f4566-a719-409b-80a9-40ca89e3e721@oss.qualcomm.com>
On Fri, Apr 03, 2026 at 12:05:27AM +0530, Shivendra Pratap wrote:
>
>
> On 01-04-2026 20:07, Lorenzo Pieralisi wrote:
> > On Tue, Mar 31, 2026 at 11:30:09PM +0530, Shivendra Pratap wrote:
> > >
> > >
> > > On 27-03-2026 19:25, Lorenzo Pieralisi wrote:
> > > > On Wed, Mar 04, 2026 at 11:33:06PM +0530, Shivendra Pratap wrote:
> > > > > PSCI supports different types of resets like COLD reset, ARCH WARM
>
> [snip..]
>
> > > > > + * Predefined reboot-modes are defined as per the values
> > > > > + * of enum reboot_mode defined in the kernel: reboot.c.
> > > > > + */
> > > > > +static struct mode_info psci_resets[] = {
> > > > > + { .mode = "warm", .magic = REBOOT_WARM},
> > > > > + { .mode = "soft", .magic = REBOOT_SOFT},
> > > > > + { .mode = "cold", .magic = REBOOT_COLD},
> >
> > These strings match the command userspace issue right ? I think that we
> > should make them match the corresponding PSCI reset types, the list above
> > maps command to reboot_mode values and those can belong to any reboot
> > mode driver to be honest they don't make much sense in a PSCI reboot
> > mode driver only.
> >
> > It is a question for everyone here: would it make sense to make these
> > predefined resets a set of strings, eg:
> >
> > psci-system-reset
> > psci-system-reset2-arch-warm-reset
> >
> > and then vendor resets:
> >
> > psci-system-reset2-vendor-reset
>
> Can you share bit more details on this? We are already defining the string
> from userspace in the struct - eg: ".mode = "warm".
"warm","soft","cold" are not strictly speaking PSCI concepts and mean nothing
well defined to user space and even if they did, they would not belong in
the PSCI reboot mode driver but in generic code.
Spelling out what a reset is might help instead, again, this is just my
opinion, I don't know how the semantics of resets have been handled thus
far.
If userspace issues a LINUX_REBOOT_CMD_RESTART2 with arg, say,
"psci-system-reset2-arch-warm-reset" it is pretty clear what it wants
to do in PSCI.
Again, it is a suggestion, comments welcome.
> yes we can move away from enum reboot_mode and use custom psci defines one -
> Ack.
>
> >
>
> [snip ..]
>
> > > > > +
> > > > > +/*
> > > > > + * arg1 is reset_type(Low 32 bit of magic).
> > > > > + * arg2 is cookie(High 32 bit of magic).
> > > > > + * If reset_type is 0, cookie will be used to decide the reset command.
> > > > > + */
> > > > > +static int psci_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
> > > > > +{
> > > > > + u32 reset_type = REBOOT_MODE_ARG1(magic);
> > > > > + u32 cookie = REBOOT_MODE_ARG2(magic);
> > > > > +
> > > > > + if (reset_type == 0) {
> > > > > + if (cookie == REBOOT_WARM || cookie == REBOOT_SOFT)
> > > > > + psci_set_reset_cmd(true, 0, 0);
> > > > > + else
> > > > > + psci_set_reset_cmd(false, 0, 0);
> > > > > + } else {
> > > > > + psci_set_reset_cmd(true, reset_type, cookie);
> > > > > + }
> > > >
> > > > I don't think that psci_set_reset_cmd() has the right interface (and this
> > > > nested if is too complicated for my taste). All we need to pass is reset-type
> > > > and cookie (and if the reset is one of the predefined ones, reset-type is 0
> > > > and cookie is the REBOOT_* cookie).
> > > >
> > > > Then the PSCI firmware driver will take the action according to what
> > > > resets are available.
> > > >
> > > > How does it sound ?
> > >
> > > So we mean these checks will move to the psci driver? Sorry for re-iterating
> > > the question.
> >
> > Given what I say above, I believe that something we can do is mapping the magic
> > to an enum like:
> >
> > PSCI_SYSTEM_RESET
> > PSCI_SYSTEM_RESET2_ARCH_SYSTEM_WARM_RESET
> > PSCI_SYSTEM_RESET2_VENDOR_RESET
> >
> > and can add a probe function into PSCI driver similar to psci_has_osi_support() but
> > to probe for SYSTEM_RESET2 and initialize the predefined strings accordingly,
> > depending on its presence.
>
> Not able to get it cleanly.
>
> 1. Will move away from reboot_mode enum for pre-defined modes and define new
> enum defining these modes- fine.
> 2. get SYSTEM_RESET2 is supported from psci exported function -- fine, but
> how we use it here now, as we do not want to send the reset_cmd from
> psci_set_reset_cmd now?
You do keep psci_set_reset_cmd() but all it is used for is setting a struct
shared with the PSCI driver where you initialize the enum above, possibly
with a cookie if it is a vendor reset.
> 3. For pre-defined modes, warm/soft or cold - reset_type and cookie, both
> are zero, sys_reset2 or sys_reset2 decides the ARCH reset vs cold reset.
> 4. For vendor-rest , we use sys_reset2 with reset_type and cookie.
Yes.
> All above is done in reboot_notifier call at psci-reboot-mode.
> --
>
> Now in the final restart_notifier->psci_sys_reset --
>
> If panic is in progress, we do not use any of the cmd based reset params and
> go with the legacy reset. So we need to preserve the values that were set
> from psci-reboot-mode.
>
> Did not understand the proposed suggestion in above usecase. Need more input
> on this.
I explained above. The reboot mode driver sets the command to carry out
depending on the string coming from user space and whether PSCI supports
SYSTEM_RESET2 or not.
> --
>
> One other option is to have a restart_notifier in psci-reboot-mode, with
> lesser priority than psci_sys_rest and then handle all the case including
> panic and sys_reset2.
No.
Thanks,
Lorenzo
^ permalink raw reply
* Re: [PATCH v6 09/10] clk: realtek: Add RTD1625-ISO clock controller driver
From: Brian Masney @ 2026-04-03 15:29 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-10-eleanor.lin@realtek.com>
Hi Yu-Chun,
On Thu, Apr 02, 2026 at 03:39:56PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add support for the ISO (Isolation) domain clock controller on the Realtek
> RTD1625 SoC. This controller manages clocks in the always-on power domain,
> ensuring essential services remain functional even when the main system
> power is gated.
>
> Since the reset controller shares the same register space with the ISO
> clock controller, it is instantiated as an auxiliary device by the core
> clock driver. This patch also includes the corresponding auxiliary reset
> driver to handle the ISO domain resets.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> - Move struct rtk_reset_desc arrays from the clock driver to the dedicated reset driver.
> - Implement and register a dedicated reset auxiliary driver.
> ---
> drivers/clk/realtek/Makefile | 1 +
> drivers/clk/realtek/clk-rtd1625-iso.c | 144 ++++++++++++++++++++++
> drivers/reset/realtek/Makefile | 2 +-
> drivers/reset/realtek/reset-rtd1625-iso.c | 96 +++++++++++++++
> 4 files changed, 242 insertions(+), 1 deletion(-)
> create mode 100644 drivers/clk/realtek/clk-rtd1625-iso.c
> create mode 100644 drivers/reset/realtek/reset-rtd1625-iso.c
>
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index c992f97dfbc7..1680435e1e0f 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -10,3 +10,4 @@ clk-rtk-y += freq_table.o
>
> clk-rtk-$(CONFIG_RTK_CLK_PLL_MMC) += clk-pll-mmc.o
> obj-$(CONFIG_COMMON_CLK_RTD1625) += clk-rtd1625-crt.o
> +obj-$(CONFIG_COMMON_CLK_RTD1625) += clk-rtd1625-iso.o
> diff --git a/drivers/clk/realtek/clk-rtd1625-iso.c b/drivers/clk/realtek/clk-rtd1625-iso.c
> new file mode 100644
> index 000000000000..027a131363f9
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-rtd1625-iso.c
> @@ -0,0 +1,144 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2024 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <dt-bindings/clock/realtek,rtd1625-clk.h>
> +#include <linux/array_size.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include "clk-regmap-gate.h"
> +
> +#define RTD1625_ISO_CLK_MAX 19
> +#define RTD1625_ISO_RSTN_MAX 29
> +#define RTD1625_ISO_S_CLK_MAX 5
> +#define RTD1625_ISO_S_RSTN_MAX 5
> +
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_p4, 0, 0x4, 0, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_p3, 0, 0x4, 1, 0);
> +static CLK_REGMAP_GATE(clk_en_misc_cec0, "clk_en_misc", 0, 0x4, 2, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbusrx_sys, 0, 0x4, 3, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbustx_sys, 0, 0x4, 4, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbus_sys, 0, 0x4, 5, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbus_osc, 0, 0x4, 6, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_i2c0, 0, 0x4, 9, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_i2c1, 0, 0x4, 10, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_etn_250m, 0, 0x4, 11, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_etn_sys, 0, 0x4, 12, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_drd, 0, 0x4, 13, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_host, 0, 0x4, 14, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_u3_host, 0, 0x4, 15, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb, 0, 0x4, 16, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_vtc, 0, 0x4, 17, 0);
> +static CLK_REGMAP_GATE(clk_en_misc_vfd, "clk_en_misc", 0, 0x4, 18, 0);
> +
> +static struct clk_regmap *rtd1625_clk_regmap_list[] = {
static const? Same for some others below as well.
> + &clk_en_usb_p4.clkr,
> + &clk_en_usb_p3.clkr,
> + &clk_en_misc_cec0.clkr,
> + &clk_en_cbusrx_sys.clkr,
> + &clk_en_cbustx_sys.clkr,
> + &clk_en_cbus_sys.clkr,
> + &clk_en_cbus_osc.clkr,
> + &clk_en_i2c0.clkr,
> + &clk_en_i2c1.clkr,
> + &clk_en_etn_250m.clkr,
> + &clk_en_etn_sys.clkr,
> + &clk_en_usb_drd.clkr,
> + &clk_en_usb_host.clkr,
> + &clk_en_usb_u3_host.clkr,
> + &clk_en_usb.clkr,
> + &clk_en_vtc.clkr,
> + &clk_en_misc_vfd.clkr,
> +};
> +
> +static struct clk_hw_onecell_data rtd1625_iso_clk_data = {
> + .num = RTD1625_ISO_CLK_MAX,
> + .hws = {
> + [RTD1625_ISO_CLK_EN_USB_P4] = &__clk_regmap_gate_hw(&clk_en_usb_p4),
> + [RTD1625_ISO_CLK_EN_USB_P3] = &__clk_regmap_gate_hw(&clk_en_usb_p3),
> + [RTD1625_ISO_CLK_EN_MISC_CEC0] = &__clk_regmap_gate_hw(&clk_en_misc_cec0),
> + [RTD1625_ISO_CLK_EN_CBUSRX_SYS] = &__clk_regmap_gate_hw(&clk_en_cbusrx_sys),
> + [RTD1625_ISO_CLK_EN_CBUSTX_SYS] = &__clk_regmap_gate_hw(&clk_en_cbustx_sys),
> + [RTD1625_ISO_CLK_EN_CBUS_SYS] = &__clk_regmap_gate_hw(&clk_en_cbus_sys),
> + [RTD1625_ISO_CLK_EN_CBUS_OSC] = &__clk_regmap_gate_hw(&clk_en_cbus_osc),
> + [RTD1625_ISO_CLK_EN_I2C0] = &__clk_regmap_gate_hw(&clk_en_i2c0),
> + [RTD1625_ISO_CLK_EN_I2C1] = &__clk_regmap_gate_hw(&clk_en_i2c1),
> + [RTD1625_ISO_CLK_EN_ETN_250M] = &__clk_regmap_gate_hw(&clk_en_etn_250m),
> + [RTD1625_ISO_CLK_EN_ETN_SYS] = &__clk_regmap_gate_hw(&clk_en_etn_sys),
> + [RTD1625_ISO_CLK_EN_USB_DRD] = &__clk_regmap_gate_hw(&clk_en_usb_drd),
> + [RTD1625_ISO_CLK_EN_USB_HOST] = &__clk_regmap_gate_hw(&clk_en_usb_host),
> + [RTD1625_ISO_CLK_EN_USB_U3_HOST] = &__clk_regmap_gate_hw(&clk_en_usb_u3_host),
> + [RTD1625_ISO_CLK_EN_USB] = &__clk_regmap_gate_hw(&clk_en_usb),
> + [RTD1625_ISO_CLK_EN_VTC] = &__clk_regmap_gate_hw(&clk_en_vtc),
> + [RTD1625_ISO_CLK_EN_MISC_VFD] = &__clk_regmap_gate_hw(&clk_en_misc_vfd),
> + [RTD1625_ISO_CLK_MAX] = NULL,
> + },
> +};
> +
> +static const struct rtk_clk_desc rtd1625_iso_desc = {
> + .clk_data = &rtd1625_iso_clk_data,
> + .clks = rtd1625_clk_regmap_list,
> + .num_clks = ARRAY_SIZE(rtd1625_clk_regmap_list),
> +};
> +
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_irda, 0, 0x4, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ur10, 0, 0x4, 8, 1);
> +
> +static struct clk_regmap *rtd1625_iso_s_clk_regmap_list[] = {
> + &clk_en_irda.clkr,
> + &clk_en_ur10.clkr,
> +};
> +
> +static struct clk_hw_onecell_data rtd1625_iso_s_clk_data = {
> + .num = RTD1625_ISO_S_CLK_MAX,
> + .hws = {
> + [RTD1625_ISO_S_CLK_EN_IRDA] = &__clk_regmap_gate_hw(&clk_en_irda),
> + [RTD1625_ISO_S_CLK_EN_UR10] = &__clk_regmap_gate_hw(&clk_en_ur10),
> + [RTD1625_ISO_S_CLK_MAX] = NULL,
> + },
> +};
> +
> +static const struct rtk_clk_desc rtd1625_iso_s_desc = {
> + .clk_data = &rtd1625_iso_s_clk_data,
> + .clks = rtd1625_iso_s_clk_regmap_list,
> + .num_clks = ARRAY_SIZE(rtd1625_iso_s_clk_regmap_list),
> +};
> +
> +static int rtd1625_iso_probe(struct platform_device *pdev)
> +{
> + const struct rtk_clk_desc *desc;
> +
> + desc = of_device_get_match_data(&pdev->dev);
> + if (!desc)
> + return -EINVAL;
> + return rtk_clk_probe(pdev, desc, "iso_rst");
Add newline before return.
> +}
> +
> +static const struct of_device_id rtd1625_iso_match[] = {
> + {.compatible = "realtek,rtd1625-iso-clk", .data = &rtd1625_iso_desc},
> + {.compatible = "realtek,rtd1625-iso-s-clk", .data = &rtd1625_iso_s_desc},
> + { /* sentinel */ }
> +};
> +
> +static struct platform_driver rtd1625_iso_driver = {
> + .probe = rtd1625_iso_probe,
> + .driver = {
> + .name = "rtk-rtd1625-iso-clk",
> + .of_match_table = rtd1625_iso_match,
> + },
> +};
> +
> +static int __init rtd1625_iso_init(void)
> +{
> + return platform_driver_register(&rtd1625_iso_driver);
> +}
> +subsys_initcall(rtd1625_iso_init);
> +
> +MODULE_DESCRIPTION("Realtek RTD1625 ISO Controller Driver");
> +MODULE_AUTHOR("Cheng-Yu Lee <cylee12@realtek.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_CLK");
> diff --git a/drivers/reset/realtek/Makefile b/drivers/reset/realtek/Makefile
> index 8ca1fa939f10..26b3ddc75ada 100644
> --- a/drivers/reset/realtek/Makefile
> +++ b/drivers/reset/realtek/Makefile
> @@ -1,2 +1,2 @@
> # SPDX-License-Identifier: GPL-2.0-only
> -obj-$(CONFIG_RESET_RTK_COMMON) += common.o reset-rtd1625-crt.o
> +obj-$(CONFIG_RESET_RTK_COMMON) += common.o reset-rtd1625-crt.o reset-rtd1625-iso.o
Some comment as the previous patch. CONFIG_RESET_RTK_COMMON is expected
to be common, right? If so, a SoC-specific driver shouldn't be listed
here.
> diff --git a/drivers/reset/realtek/reset-rtd1625-iso.c b/drivers/reset/realtek/reset-rtd1625-iso.c
> new file mode 100644
> index 000000000000..f2a0478382ae
> --- /dev/null
> +++ b/drivers/reset/realtek/reset-rtd1625-iso.c
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026 Realtek Semiconductor Corporation
> + */
> +
> +#include <dt-bindings/reset/realtek,rtd1625.h>
> +#include <linux/auxiliary_bus.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/of.h>
> +#include <linux/slab.h>
> +#include "common.h"
> +
> +#define RTD1625_ISO_RSTN_MAX 29
> +#define RTD1625_ISO_S_RSTN_MAX 5
> +
> +static struct rtk_reset_desc rtd1625_iso_reset_descs[] = {
static const?
> + [RTD1625_ISO_RSTN_VFD] = { .ofs = 0x88, .bit = 0 },
> + [RTD1625_ISO_RSTN_CEC0] = { .ofs = 0x88, .bit = 2 },
> + [RTD1625_ISO_RSTN_CEC1] = { .ofs = 0x88, .bit = 3 },
> + [RTD1625_ISO_RSTN_CBUSTX] = { .ofs = 0x88, .bit = 5 },
> + [RTD1625_ISO_RSTN_CBUSRX] = { .ofs = 0x88, .bit = 6 },
> + [RTD1625_ISO_RSTN_USB3_PHY2_XTAL_POW] = { .ofs = 0x88, .bit = 7 },
> + [RTD1625_ISO_RSTN_UR0] = { .ofs = 0x88, .bit = 8 },
> + [RTD1625_ISO_RSTN_GMAC] = { .ofs = 0x88, .bit = 9 },
> + [RTD1625_ISO_RSTN_GPHY] = { .ofs = 0x88, .bit = 10 },
> + [RTD1625_ISO_RSTN_I2C_0] = { .ofs = 0x88, .bit = 11 },
> + [RTD1625_ISO_RSTN_I2C_1] = { .ofs = 0x88, .bit = 12 },
> + [RTD1625_ISO_RSTN_CBUS] = { .ofs = 0x88, .bit = 13 },
> + [RTD1625_ISO_RSTN_USB_DRD] = { .ofs = 0x88, .bit = 14 },
> + [RTD1625_ISO_RSTN_USB_HOST] = { .ofs = 0x88, .bit = 15 },
> + [RTD1625_ISO_RSTN_USB_PHY_0] = { .ofs = 0x88, .bit = 16 },
> + [RTD1625_ISO_RSTN_USB_PHY_1] = { .ofs = 0x88, .bit = 17 },
> + [RTD1625_ISO_RSTN_USB_PHY_2] = { .ofs = 0x88, .bit = 18 },
> + [RTD1625_ISO_RSTN_USB] = { .ofs = 0x88, .bit = 19 },
> + [RTD1625_ISO_RSTN_TYPE_C] = { .ofs = 0x88, .bit = 20 },
> + [RTD1625_ISO_RSTN_USB_U3_HOST] = { .ofs = 0x88, .bit = 21 },
> + [RTD1625_ISO_RSTN_USB3_PHY0_POW] = { .ofs = 0x88, .bit = 22 },
> + [RTD1625_ISO_RSTN_USB3_P0_MDIO] = { .ofs = 0x88, .bit = 23 },
> + [RTD1625_ISO_RSTN_USB3_PHY1_POW] = { .ofs = 0x88, .bit = 24 },
> + [RTD1625_ISO_RSTN_USB3_P1_MDIO] = { .ofs = 0x88, .bit = 25 },
> + [RTD1625_ISO_RSTN_VTC] = { .ofs = 0x88, .bit = 26 },
> + [RTD1625_ISO_RSTN_USB3_PHY2_POW] = { .ofs = 0x88, .bit = 27 },
> + [RTD1625_ISO_RSTN_USB3_P2_MDIO] = { .ofs = 0x88, .bit = 28 },
> + [RTD1625_ISO_RSTN_USB_PHY_3] = { .ofs = 0x88, .bit = 29 },
> + [RTD1625_ISO_RSTN_USB_PHY_4] = { .ofs = 0x88, .bit = 30 },
> +};
> +
> +static struct rtk_reset_desc rtd1625_iso_s_reset_descs[] = {
> + [RTD1625_ISO_S_RSTN_ISOM_MIS] = { .ofs = 0x310, .bit = 0, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_GPIOM] = { .ofs = 0x310, .bit = 2, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_TIMER7] = { .ofs = 0x310, .bit = 4, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_IRDA] = { .ofs = 0x310, .bit = 6, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_UR10] = { .ofs = 0x310, .bit = 8, .write_en = 1 },
> +};
> +
> +static int rtd1625_iso_reset_probe(struct auxiliary_device *adev,
> + const struct auxiliary_device_id *id)
> +{
> + struct device *dev = &adev->dev;
> + struct device *parent = dev->parent;
> + struct rtk_reset_data *data;
> +
> + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + if (of_device_is_compatible(parent->of_node, "realtek,rtd1625-iso-s-clk")) {
> + data->descs = rtd1625_iso_s_reset_descs;
> + data->rcdev.nr_resets = RTD1625_ISO_S_RSTN_MAX;
> + } else {
> + data->descs = rtd1625_iso_reset_descs;
> + data->rcdev.nr_resets = RTD1625_ISO_RSTN_MAX;
> + }
> + return rtk_reset_controller_add(dev, data);
Newline before return.
> +}
> +
> +static const struct auxiliary_device_id rtd1625_iso_reset_ids[] = {
> + {
> + .name = "clk_rtk.iso_rst",
> + },
I would combine the { .name } all on one line.
Brian
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(auxiliary, rtd1625_iso_reset_ids);
> +
> +static struct auxiliary_driver rtd1625_iso_driver = {
> + .probe = rtd1625_iso_reset_probe,
> + .id_table = rtd1625_iso_reset_ids,
> + .driver = {
> + .name = "rtd1625-iso-reset",
> + },
> +};
> +module_auxiliary_driver(rtd1625_iso_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_RESET");
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH v6 08/10] clk: realtek: Add RTD1625-CRT clock controller driver
From: Brian Masney @ 2026-04-03 15:24 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-9-eleanor.lin@realtek.com>
Hi Yu-Chun,
On Thu, Apr 02, 2026 at 03:39:55PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add support for the CRT (Clock, Reset, and Test) domain clock controller
> on the Realtek RTD1625 SoC. This driver provides essential clock sources
> (including PLLs), gating, and multiplexing functionalities for the
> platform's peripherals.
>
> Since the reset controller shares the same register space with the CRT
> clock controller, it is instantiated as an auxiliary device by the core
> clock driver. This patch also includes the corresponding auxiliary reset
> driver to handle the CRT domain resets.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> - Move struct rtk_reset_desc array from the clock driver to the dedicated reset driver.
> - Implement and register a dedicated reset auxiliary driver.
> ---
> drivers/clk/realtek/Kconfig | 13 +
> drivers/clk/realtek/Makefile | 1 +
> drivers/clk/realtek/clk-rtd1625-crt.c | 779 ++++++++++++++++++++++
> drivers/reset/realtek/Kconfig | 2 +
> drivers/reset/realtek/Makefile | 2 +-
> drivers/reset/realtek/reset-rtd1625-crt.c | 186 ++++++
> 6 files changed, 982 insertions(+), 1 deletion(-)
> create mode 100644 drivers/clk/realtek/clk-rtd1625-crt.c
> create mode 100644 drivers/reset/realtek/reset-rtd1625-crt.c
>
> diff --git a/drivers/clk/realtek/Kconfig b/drivers/clk/realtek/Kconfig
> index b31a31e57b3a..6a213cfd66bc 100644
> --- a/drivers/clk/realtek/Kconfig
> +++ b/drivers/clk/realtek/Kconfig
> @@ -28,4 +28,17 @@ config RTK_CLK_COMMON
> config RTK_CLK_PLL_MMC
> bool
>
> +config COMMON_CLK_RTD1625
> + tristate "RTD1625 Clock Controller"
> + select RTK_CLK_COMMON
> + select RTK_CLK_PLL_MMC
> + help
> + Support for the clock controller on Realtek RTD1625 SoCs.
> +
> + This driver provides clock sources, gating, multiplexing, and
> + reset control for peripherals on the RTD1625 platform.
> +
> + Say Y here if your system is based on the RTD1625 and you need
> + its peripheral devices to function.
> +
> endif
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index fd7d777902c8..c992f97dfbc7 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -9,3 +9,4 @@ clk-rtk-y += clk-regmap-mux.o
> clk-rtk-y += freq_table.o
>
> clk-rtk-$(CONFIG_RTK_CLK_PLL_MMC) += clk-pll-mmc.o
> +obj-$(CONFIG_COMMON_CLK_RTD1625) += clk-rtd1625-crt.o
> diff --git a/drivers/clk/realtek/clk-rtd1625-crt.c b/drivers/clk/realtek/clk-rtd1625-crt.c
> new file mode 100644
> index 000000000000..fcb8b08722c8
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-rtd1625-crt.c
> @@ -0,0 +1,779 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <dt-bindings/clock/realtek,rtd1625-clk.h>
> +#include <linux/array_size.h>
> +#include <linux/bits.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include "clk-pll.h"
> +#include "clk-regmap-gate.h"
> +#include "clk-regmap-mux.h"
> +
> +#define RTD1625_CRT_CLK_MAX 172
> +#define RTD1625_CRT_RSTN_MAX 123
> +
> +#define RTD1625_REG_PLL_ACPU1 0x10c
> +#define RTD1625_REG_PLL_ACPU2 0x110
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU0 0x5c0
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU1 0x5c4
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU2 0x5c8
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU_DBG2 0x5dc
> +
> +#define RTD1625_REG_PLL_VE1_1 0x114
> +#define RTD1625_REG_PLL_VE1_2 0x118
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_0 0x580
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_1 0x584
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_2 0x588
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_DBG2 0x59c
> +
> +#define RTD1625_REG_PLL_GPU1 0x1c0
> +#define RTD1625_REG_PLL_GPU2 0x1c4
> +#define RTD1625_REG_PLL_SSC_DIG_GPU0 0x5a0
> +#define RTD1625_REG_PLL_SSC_DIG_GPU1 0x5a4
> +#define RTD1625_REG_PLL_SSC_DIG_GPU2 0x5a8
> +#define RTD1625_REG_PLL_SSC_DIG_GPU_DBG2 0x5bc
> +
> +#define RTD1625_REG_PLL_NPU1 0x1c8
> +#define RTD1625_REG_PLL_NPU2 0x1cc
> +#define RTD1625_REG_PLL_SSC_DIG_NPU0 0x800
> +#define RTD1625_REG_PLL_SSC_DIG_NPU1 0x804
> +#define RTD1625_REG_PLL_SSC_DIG_NPU2 0x808
> +#define RTD1625_REG_PLL_SSC_DIG_NPU_DBG2 0x81c
> +
> +#define RTD1625_REG_PLL_VE2_1 0x1d0
> +#define RTD1625_REG_PLL_VE2_2 0x1d4
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_0 0x5e0
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_1 0x5e4
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_2 0x5e8
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_DBG2 0x5fc
> +
> +#define RTD1625_REG_PLL_HIFI1 0x1d8
> +#define RTD1625_REG_PLL_HIFI2 0x1dc
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI0 0x6e0
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI1 0x6e4
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI2 0x6e8
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI_DBG2 0x6fc
> +
> +#define RTD1625_REG_PLL_BUS1 0x524
> +
> +#define RTD1625_REG_PLL_SSC_DIG_DDSA1 0x564
> +
> +#define RTD1625_REG_PLL_SSC_DIG_DCSB1 0x544
> +
> +static const char * const clk_gpu_parents[] = {"pll_gpu", "clk_sys"};
> +static CLK_REGMAP_MUX(clk_gpu, clk_gpu_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x28, 12, 0x1);
> +static const char * const clk_ve_parents[] = {"pll_vo", "clk_sysh", "pll_ve1", "pll_ve2"};
> +static CLK_REGMAP_MUX(clk_ve1, clk_ve_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x4c, 0, 0x3);
> +static CLK_REGMAP_MUX(clk_ve2, clk_ve_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x4c, 3, 0x3);
> +static CLK_REGMAP_MUX(clk_ve4, clk_ve_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x4c, 6, 0x3);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_misc, CLK_IS_CRITICAL, 0x50, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_pcie0, 0, 0x50, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_gspi, 0, 0x50, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_iso_misc, 0, 0x50, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sds, 0, 0x50, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hdmi, 0, 0x50, 14, 1);
> +static CLK_REGMAP_GATE(clk_en_gpu, "clk_gpu", CLK_SET_RATE_PARENT, 0x50, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_ve1, "clk_ve1", CLK_SET_RATE_PARENT, 0x50, 20, 1);
> +static CLK_REGMAP_GATE(clk_en_ve2, "clk_ve2", CLK_SET_RATE_PARENT, 0x50, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_se, 0, 0x50, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_md, 0, 0x54, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tp, CLK_IS_CRITICAL, 0x54, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_rcic, 0, 0x54, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_nf, 0, 0x54, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_emmc, 0, 0x54, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sd, 0, 0x54, 14, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sdio_ip, 0, 0x54, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mipi_csi, 0, 0x54, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_emmc_ip, "pll_emmc", CLK_SET_RATE_PARENT, 0x54, 20, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sdio, 0, 0x54, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sd_ip, 0, 0x54, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tpb, 0, 0x54, 28, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_sc1, "clk_en_misc", 0, 0x54, 30, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_3, "clk_en_misc", 0, 0x58, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_jpeg, 0, 0x58, 4, 1);
> +static CLK_REGMAP_GATE(clk_en_acpu, "pll_acpu", CLK_SET_RATE_PARENT,
> + 0x58, 6, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_sc0, "clk_en_misc", 0, 0x58, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hdmirx, 0, 0x58, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hse, CLK_IS_CRITICAL, 0x58, 28, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_fan, 0, 0x5c, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sata_wrap_sys, 0, 0x5c, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sata_wrap_sysh, 0, 0x5c, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sata_mac_sysh, 0, 0x5c, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_r2rdsc, 0, 0x5c, 14, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_pcie1, 0, 0x5c, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_4, "clk_en_misc", 0, 0x5c, 20, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_5, "clk_en_misc", 0, 0x5c, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tsio, 0, 0x5c, 24, 1);
> +static CLK_REGMAP_GATE(clk_en_ve4, "clk_ve4", CLK_SET_RATE_PARENT,
> + 0x5c, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_edp, 0, 0x5c, 28, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tsio_trx, 0, 0x5c, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_pcie2, 0, 0x8c, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_earc, 0, 0x8c, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lite, 0, 0x8c, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mipi_dsi, 0, 0x8c, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_npupp, 0, 0x8c, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_npu, 0, 0x8c, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu0, 0, 0x8c, 14, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu1, 0, 0x8c, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_nsram, 0, 0x8c, 18, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hdmitop, 0, 0x8c, 20, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu_iso_npu, 0, 0x8c, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_keyladder, 0, 0x8c, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ifcp_klm, 0, 0x8c, 28, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ifcp, 0, 0x8c, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_genpw, 0, 0xb0, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_chip, 0, 0xb0, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_ip, 0, 0xb0, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdlm2m, 0, 0xb0, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_xtal, 0, 0xb0, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_test_mux, 0, 0xb0, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_dla, 0, 0xb0, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tpcw, 0, 0xb0, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_gpu_ts_src, 0, 0xb0, 18, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_vi, 0, 0xb0, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lvds1, 0, 0xb0, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lvds2, 0, 0xb0, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu, 0, 0xb0, 28, 1);
> +static CLK_REGMAP_GATE(clk_en_ur1, "clk_en_ur_top", 0, 0x884, 0, 1);
> +static CLK_REGMAP_GATE(clk_en_ur2, "clk_en_ur_top", 0, 0x884, 2, 1);
> +static CLK_REGMAP_GATE(clk_en_ur3, "clk_en_ur_top", 0, 0x884, 4, 1);
> +static CLK_REGMAP_GATE(clk_en_ur4, "clk_en_ur_top", 0, 0x884, 6, 1);
> +static CLK_REGMAP_GATE(clk_en_ur5, "clk_en_ur_top", 0, 0x884, 8, 1);
> +static CLK_REGMAP_GATE(clk_en_ur6, "clk_en_ur_top", 0, 0x884, 10, 1);
> +static CLK_REGMAP_GATE(clk_en_ur7, "clk_en_ur_top", 0, 0x884, 12, 1);
> +static CLK_REGMAP_GATE(clk_en_ur8, "clk_en_ur_top", 0, 0x884, 14, 1);
> +static CLK_REGMAP_GATE(clk_en_ur9, "clk_en_ur_top", 0, 0x884, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ur_top, CLK_IS_CRITICAL, 0x884, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_7, "clk_en_misc", 0, 0x884, 28, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_6, "clk_en_misc", 0, 0x884, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_spi0, 0, 0x894, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_spi1, 0, 0x894, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_spi2, 0, 0x894, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lsadc0, 0, 0x894, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lsadc1, 0, 0x894, 18, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_isomis_dma, 0, 0x894, 20, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_dptx, 0, 0x894, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_npu_mipi_csi, 0, 0x894, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_edptx, 0, 0x894, 28, 1);
> +
> +#define FREQ_NF_MASK 0x7ffff
> +#define FREQ_NF(_r, _nf) {.rate = _r, .val = (_nf),}
> +
> +static const struct freq_table acpu_tbl[] = {
> + FREQ_NF(513000000, 0x11000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table ve_tbl[] = {
> + FREQ_NF(553500000, 0x12800),
> + FREQ_NF(661500000, 0x16800),
> + FREQ_NF(688500000, 0x17800),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table bus_tbl[] = {
> + FREQ_NF(513000000, 0x11000),
> + FREQ_NF(540000000, 0x12000),
> + FREQ_NF(553500000, 0x12800),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table ddsa_tbl[] = {
> + FREQ_NF(432000000, 0xe000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table gpu_tbl[] = {
> + FREQ_NF(405000000, 0xd000),
> + FREQ_NF(540000000, 0x12000),
> + FREQ_NF(661500000, 0x16800),
> + FREQ_NF(729000000, 0x19000),
> + FREQ_NF(810000000, 0x1c000),
> + FREQ_NF(850500000, 0x1d800),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table hifi_tbl[] = {
> + FREQ_NF(756000000, 0x1a000),
> + FREQ_NF(810000000, 0x1c000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table npu_tbl[] = {
> + FREQ_NF(661500000, 0x16800),
> + FREQ_NF(729000000, 0x19000),
> + FREQ_NF(810000000, 0x1c000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_power_on[] = {
> + {RTD1625_REG_PLL_ACPU2, 0x5},
> + {RTD1625_REG_PLL_ACPU2, 0x7},
> + {RTD1625_REG_PLL_ACPU1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_ACPU2, 0x1e1f8e},
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x5, 200},
> + {RTD1625_REG_PLL_ACPU2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_power_off[] = {
> + {RTD1625_REG_PLL_ACPU2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x5},
> +};
> +
> +static struct clk_pll pll_acpu = {
static const?
> + .clkr.hw.init = CLK_HW_INIT("pll_acpu", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_acpu_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_acpu_seq_power_on),
> + .seq_power_off = pll_acpu_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_acpu_seq_power_off),
> + .seq_pre_set_freq = pll_acpu_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_acpu_seq_pre_set_freq),
> + .seq_post_set_freq = pll_acpu_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_acpu_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_ACPU1,
> + .freq_tbl = acpu_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_ACPU_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_ACPU2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_power_on[] = {
> + {RTD1625_REG_PLL_VE1_2, 0x5},
> + {RTD1625_REG_PLL_VE1_2, 0x7},
> + {RTD1625_REG_PLL_VE1_1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x5, 200},
> + {RTD1625_REG_PLL_VE1_2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_power_off[] = {
> + {RTD1625_REG_PLL_VE1_2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x5},
> +};
> +
> +static struct clk_pll pll_ve1 = {
Same here about static const, plus some others below?
> + .clkr.hw.init = CLK_HW_INIT("pll_ve1", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_ve1_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_ve1_seq_power_on),
> + .seq_power_off = pll_ve1_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_ve1_seq_power_off),
> + .seq_pre_set_freq = pll_ve1_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_ve1_seq_pre_set_freq),
> + .seq_post_set_freq = pll_ve1_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_ve1_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_VE1_1,
> + .freq_tbl = ve_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_VE1_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_VE1_2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static struct clk_pll pll_ddsa = {
> + .clkr.hw.init = CLK_HW_INIT("pll_ddsa", "osc27m", &rtk_clk_pll_ro_ops,
> + CLK_GET_RATE_NOCACHE),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_DDSA1,
> + .freq_tbl = ddsa_tbl,
> + .freq_mask = FREQ_NF_MASK,
> +};
> +
> +static struct clk_pll pll_bus = {
> + .clkr.hw.init = CLK_HW_INIT("pll_bus", "osc27m", &rtk_clk_pll_ro_ops, CLK_GET_RATE_NOCACHE),
> + .freq_reg = RTD1625_REG_PLL_BUS1,
> + .freq_tbl = bus_tbl,
> + .freq_mask = FREQ_NF_MASK,
> +};
> +
> +static CLK_FIXED_FACTOR(clk_sys, "clk_sys", "pll_bus", 2, 1, 0);
> +
> +static struct clk_pll pll_dcsb = {
> + .clkr.hw.init = CLK_HW_INIT("pll_dcsb", "osc27m", &rtk_clk_pll_ro_ops,
> + CLK_GET_RATE_NOCACHE),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_DCSB1,
> + .freq_tbl = bus_tbl,
> + .freq_mask = FREQ_NF_MASK,
> +};
> +
> +static CLK_FIXED_FACTOR(clk_sysh, "clk_sysh", "pll_dcsb", 1, 1, 0);
> +
> +static const struct reg_sequence pll_gpu_seq_power_on[] = {
> + {RTD1625_REG_PLL_GPU2, 0x5},
> + {RTD1625_REG_PLL_GPU2, 0x7},
> + {RTD1625_REG_PLL_GPU1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x5, 200},
> + {RTD1625_REG_PLL_GPU2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_gpu_seq_power_off[] = {
> + {RTD1625_REG_PLL_GPU2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_gpu_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_gpu_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x5},
> +};
> +
> +static struct clk_pll pll_gpu = {
> + .clkr.hw.init = CLK_HW_INIT("pll_gpu", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_gpu_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_gpu_seq_power_on),
> + .seq_power_off = pll_gpu_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_gpu_seq_power_off),
> + .seq_pre_set_freq = pll_gpu_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_gpu_seq_pre_set_freq),
> + .seq_post_set_freq = pll_gpu_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_gpu_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_GPU1,
> + .freq_tbl = gpu_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_GPU_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_GPU2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static const struct reg_sequence pll_npu_seq_power_on[] = {
> + {RTD1625_REG_PLL_NPU2, 0x5},
> + {RTD1625_REG_PLL_NPU2, 0x7},
> + {RTD1625_REG_PLL_NPU1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x5, 200},
> + {RTD1625_REG_PLL_NPU2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_npu_seq_power_off[] = {
> + {RTD1625_REG_PLL_NPU2, 0x4},
> + {RTD1625_REG_PLL_NPU1, 0x54010},
> +};
> +
> +static const struct reg_sequence pll_npu_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_npu_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x5},
> +};
> +
> +static struct clk_pll pll_npu = {
> + .clkr.hw.init = CLK_HW_INIT("pll_npu", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_npu_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_npu_seq_power_on),
> + .seq_power_off = pll_npu_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_npu_seq_power_off),
> + .seq_pre_set_freq = pll_npu_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_npu_seq_pre_set_freq),
> + .seq_post_set_freq = pll_npu_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_npu_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_NPU1,
> + .freq_tbl = npu_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_NPU_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_NPU2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static CLK_FIXED_FACTOR(clk_npu, "clk_npu", "pll_npu", 1, 1, CLK_SET_RATE_PARENT);
> +static CLK_FIXED_FACTOR(clk_npu_mipi_csi, "clk_npu_mipi_csi", "pll_npu", 1, 1,
> + CLK_SET_RATE_PARENT);
> +
> +static const struct reg_sequence pll_ve2_seq_power_on[] = {
> + {RTD1625_REG_PLL_VE2_2, 0x5},
> + {RTD1625_REG_PLL_VE2_2, 0x7},
> + {RTD1625_REG_PLL_VE2_1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x5, 200},
> + {RTD1625_REG_PLL_VE2_2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_ve2_seq_power_off[] = {
> + {RTD1625_REG_PLL_VE2_2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve2_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve2_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x5},
> +};
> +
> +static struct clk_pll pll_ve2 = {
> + .clkr.hw.init = CLK_HW_INIT("pll_ve2", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_ve2_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_ve2_seq_power_on),
> + .seq_power_off = pll_ve2_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_ve2_seq_power_off),
> + .seq_pre_set_freq = pll_ve2_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_ve2_seq_pre_set_freq),
> + .seq_post_set_freq = pll_ve2_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_ve2_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_VE2_1,
> + .freq_tbl = ve_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_VE2_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_VE2_2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_power_on[] = {
> + {RTD1625_REG_PLL_HIFI2, 0x5},
> + {RTD1625_REG_PLL_HIFI2, 0x7},
> + {RTD1625_REG_PLL_HIFI1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x5, 200},
> + {RTD1625_REG_PLL_HIFI2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_power_off[] = {
> + {RTD1625_REG_PLL_HIFI2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x5},
> +};
> +
> +static struct clk_pll pll_hifi = {
> + .clkr.hw.init = CLK_HW_INIT("pll_hifi", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_hifi_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_hifi_seq_power_on),
> + .seq_power_off = pll_hifi_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_hifi_seq_power_off),
> + .seq_pre_set_freq = pll_hifi_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_hifi_seq_pre_set_freq),
> + .seq_post_set_freq = pll_hifi_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_hifi_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_HIFI1,
> + .freq_tbl = hifi_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_HIFI_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_HIFI2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static CLK_FIXED_FACTOR(pll_emmc_ref, "pll_emmc_ref", "osc27m", 1, 1, 0);
> +
> +static struct clk_pll_mmc pll_emmc = {
> + .pll_ofs = 0x1f0,
> + .ssc_dig_ofs = 0x6b0,
> + .clkr.hw.init = CLK_HW_INIT("pll_emmc", "pll_emmc_ref", &rtk_clk_pll_mmc_ops, 0),
> + .phase0_hw.init = CLK_HW_INIT("pll_emmc_vp0", "pll_emmc", &rtk_clk_pll_mmc_phase_ops, 0),
> + .phase1_hw.init = CLK_HW_INIT("pll_emmc_vp1", "pll_emmc", &rtk_clk_pll_mmc_phase_ops, 0),
> +};
> +
> +static struct clk_regmap *rtd1625_crt_regmap_clks[] = {
> + &clk_en_misc.clkr,
> + &clk_en_pcie0.clkr,
> + &clk_en_gspi.clkr,
> + &clk_en_iso_misc.clkr,
> + &clk_en_sds.clkr,
> + &clk_en_hdmi.clkr,
> + &clk_en_gpu.clkr,
> + &clk_en_ve1.clkr,
> + &clk_en_ve2.clkr,
> + &clk_en_se.clkr,
> + &clk_en_md.clkr,
> + &clk_en_tp.clkr,
> + &clk_en_rcic.clkr,
> + &clk_en_nf.clkr,
> + &clk_en_emmc.clkr,
> + &clk_en_sd.clkr,
> + &clk_en_sdio_ip.clkr,
> + &clk_en_mipi_csi.clkr,
> + &clk_en_emmc_ip.clkr,
> + &clk_en_sdio.clkr,
> + &clk_en_sd_ip.clkr,
> + &clk_en_tpb.clkr,
> + &clk_en_misc_sc1.clkr,
> + &clk_en_misc_i2c_3.clkr,
> + &clk_en_jpeg.clkr,
> + &clk_en_acpu.clkr,
> + &clk_en_misc_sc0.clkr,
> + &clk_en_hdmirx.clkr,
> + &clk_en_hse.clkr,
> + &clk_en_fan.clkr,
> + &clk_en_sata_wrap_sys.clkr,
> + &clk_en_sata_wrap_sysh.clkr,
> + &clk_en_sata_mac_sysh.clkr,
> + &clk_en_r2rdsc.clkr,
> + &clk_en_pcie1.clkr,
> + &clk_en_misc_i2c_4.clkr,
> + &clk_en_misc_i2c_5.clkr,
> + &clk_en_tsio.clkr,
> + &clk_en_ve4.clkr,
> + &clk_en_edp.clkr,
> + &clk_en_tsio_trx.clkr,
> + &clk_en_pcie2.clkr,
> + &clk_en_earc.clkr,
> + &clk_en_lite.clkr,
> + &clk_en_mipi_dsi.clkr,
> + &clk_en_npupp.clkr,
> + &clk_en_npu.clkr,
> + &clk_en_aucpu0.clkr,
> + &clk_en_aucpu1.clkr,
> + &clk_en_nsram.clkr,
> + &clk_en_hdmitop.clkr,
> + &clk_en_aucpu_iso_npu.clkr,
> + &clk_en_keyladder.clkr,
> + &clk_en_ifcp_klm.clkr,
> + &clk_en_ifcp.clkr,
> + &clk_en_mdl_genpw.clkr,
> + &clk_en_mdl_chip.clkr,
> + &clk_en_mdl_ip.clkr,
> + &clk_en_mdlm2m.clkr,
> + &clk_en_mdl_xtal.clkr,
> + &clk_en_test_mux.clkr,
> + &clk_en_dla.clkr,
> + &clk_en_tpcw.clkr,
> + &clk_en_gpu_ts_src.clkr,
> + &clk_en_vi.clkr,
> + &clk_en_lvds1.clkr,
> + &clk_en_lvds2.clkr,
> + &clk_en_aucpu.clkr,
> + &clk_en_ur1.clkr,
> + &clk_en_ur2.clkr,
> + &clk_en_ur3.clkr,
> + &clk_en_ur4.clkr,
> + &clk_en_ur5.clkr,
> + &clk_en_ur6.clkr,
> + &clk_en_ur7.clkr,
> + &clk_en_ur8.clkr,
> + &clk_en_ur9.clkr,
> + &clk_en_ur_top.clkr,
> + &clk_en_misc_i2c_7.clkr,
> + &clk_en_misc_i2c_6.clkr,
> + &clk_en_spi0.clkr,
> + &clk_en_spi1.clkr,
> + &clk_en_spi2.clkr,
> + &clk_en_lsadc0.clkr,
> + &clk_en_lsadc1.clkr,
> + &clk_en_isomis_dma.clkr,
> + &clk_en_dptx.clkr,
> + &clk_en_npu_mipi_csi.clkr,
> + &clk_en_edptx.clkr,
> + &clk_gpu.clkr,
> + &clk_ve1.clkr,
> + &clk_ve2.clkr,
> + &clk_ve4.clkr,
> + &pll_ve1.clkr,
> + &pll_ddsa.clkr,
> + &pll_bus.clkr,
> + &pll_dcsb.clkr,
> + &pll_gpu.clkr,
> + &pll_npu.clkr,
> + &pll_ve2.clkr,
> + &pll_hifi.clkr,
> + &pll_emmc.clkr,
> + &pll_acpu.clkr,
> +};
> +
> +static struct clk_hw_onecell_data rtd1625_crt_hw_data = {
> + .num = RTD1625_CRT_CLK_MAX,
> + .hws = {
> + [RTD1625_CRT_CLK_EN_MISC] = &__clk_regmap_gate_hw(&clk_en_misc),
> + [RTD1625_CRT_CLK_EN_PCIE0] = &__clk_regmap_gate_hw(&clk_en_pcie0),
> + [RTD1625_CRT_CLK_EN_GSPI] = &__clk_regmap_gate_hw(&clk_en_gspi),
> + [RTD1625_CRT_CLK_EN_ISO_MISC] = &__clk_regmap_gate_hw(&clk_en_iso_misc),
> + [RTD1625_CRT_CLK_EN_SDS] = &__clk_regmap_gate_hw(&clk_en_sds),
> + [RTD1625_CRT_CLK_EN_HDMI] = &__clk_regmap_gate_hw(&clk_en_hdmi),
> + [RTD1625_CRT_CLK_EN_GPU] = &__clk_regmap_gate_hw(&clk_en_gpu),
> + [RTD1625_CRT_CLK_EN_VE1] = &__clk_regmap_gate_hw(&clk_en_ve1),
> + [RTD1625_CRT_CLK_EN_VE2] = &__clk_regmap_gate_hw(&clk_en_ve2),
> + [RTD1625_CRT_CLK_EN_MD] = &__clk_regmap_gate_hw(&clk_en_md),
> + [RTD1625_CRT_CLK_EN_TP] = &__clk_regmap_gate_hw(&clk_en_tp),
> + [RTD1625_CRT_CLK_EN_RCIC] = &__clk_regmap_gate_hw(&clk_en_rcic),
> + [RTD1625_CRT_CLK_EN_NF] = &__clk_regmap_gate_hw(&clk_en_nf),
> + [RTD1625_CRT_CLK_EN_EMMC] = &__clk_regmap_gate_hw(&clk_en_emmc),
> + [RTD1625_CRT_CLK_EN_SD] = &__clk_regmap_gate_hw(&clk_en_sd),
> + [RTD1625_CRT_CLK_EN_SDIO_IP] = &__clk_regmap_gate_hw(&clk_en_sdio_ip),
> + [RTD1625_CRT_CLK_EN_MIPI_CSI] = &__clk_regmap_gate_hw(&clk_en_mipi_csi),
> + [RTD1625_CRT_CLK_EN_EMMC_IP] = &__clk_regmap_gate_hw(&clk_en_emmc_ip),
> + [RTD1625_CRT_CLK_EN_SDIO] = &__clk_regmap_gate_hw(&clk_en_sdio),
> + [RTD1625_CRT_CLK_EN_SD_IP] = &__clk_regmap_gate_hw(&clk_en_sd_ip),
> + [RTD1625_CRT_CLK_EN_TPB] = &__clk_regmap_gate_hw(&clk_en_tpb),
> + [RTD1625_CRT_CLK_EN_MISC_SC1] = &__clk_regmap_gate_hw(&clk_en_misc_sc1),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_3] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_3),
> + [RTD1625_CRT_CLK_EN_ACPU] = &__clk_regmap_gate_hw(&clk_en_acpu),
> + [RTD1625_CRT_CLK_EN_JPEG] = &__clk_regmap_gate_hw(&clk_en_jpeg),
> + [RTD1625_CRT_CLK_EN_MISC_SC0] = &__clk_regmap_gate_hw(&clk_en_misc_sc0),
> + [RTD1625_CRT_CLK_EN_HDMIRX] = &__clk_regmap_gate_hw(&clk_en_hdmirx),
> + [RTD1625_CRT_CLK_EN_HSE] = &__clk_regmap_gate_hw(&clk_en_hse),
> + [RTD1625_CRT_CLK_EN_FAN] = &__clk_regmap_gate_hw(&clk_en_fan),
> + [RTD1625_CRT_CLK_EN_SATA_WRAP_SYS] = &__clk_regmap_gate_hw(&clk_en_sata_wrap_sys),
> + [RTD1625_CRT_CLK_EN_SATA_WRAP_SYSH] = &__clk_regmap_gate_hw(&clk_en_sata_wrap_sysh),
> + [RTD1625_CRT_CLK_EN_SATA_MAC_SYSH] = &__clk_regmap_gate_hw(&clk_en_sata_mac_sysh),
> + [RTD1625_CRT_CLK_EN_R2RDSC] = &__clk_regmap_gate_hw(&clk_en_r2rdsc),
> + [RTD1625_CRT_CLK_EN_PCIE1] = &__clk_regmap_gate_hw(&clk_en_pcie1),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_4] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_4),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_5] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_5),
> + [RTD1625_CRT_CLK_EN_TSIO] = &__clk_regmap_gate_hw(&clk_en_tsio),
> + [RTD1625_CRT_CLK_EN_VE4] = &__clk_regmap_gate_hw(&clk_en_ve4),
> + [RTD1625_CRT_CLK_EN_EDP] = &__clk_regmap_gate_hw(&clk_en_edp),
> + [RTD1625_CRT_CLK_EN_TSIO_TRX] = &__clk_regmap_gate_hw(&clk_en_tsio_trx),
> + [RTD1625_CRT_CLK_EN_PCIE2] = &__clk_regmap_gate_hw(&clk_en_pcie2),
> + [RTD1625_CRT_CLK_EN_EARC] = &__clk_regmap_gate_hw(&clk_en_earc),
> + [RTD1625_CRT_CLK_EN_LITE] = &__clk_regmap_gate_hw(&clk_en_lite),
> + [RTD1625_CRT_CLK_EN_MIPI_DSI] = &__clk_regmap_gate_hw(&clk_en_mipi_dsi),
> + [RTD1625_CRT_CLK_EN_NPUPP] = &__clk_regmap_gate_hw(&clk_en_npupp),
> + [RTD1625_CRT_CLK_EN_NPU] = &__clk_regmap_gate_hw(&clk_en_npu),
> + [RTD1625_CRT_CLK_EN_AUCPU0] = &__clk_regmap_gate_hw(&clk_en_aucpu0),
> + [RTD1625_CRT_CLK_EN_AUCPU1] = &__clk_regmap_gate_hw(&clk_en_aucpu1),
> + [RTD1625_CRT_CLK_EN_NSRAM] = &__clk_regmap_gate_hw(&clk_en_nsram),
> + [RTD1625_CRT_CLK_EN_HDMITOP] = &__clk_regmap_gate_hw(&clk_en_hdmitop),
> + [RTD1625_CRT_CLK_EN_AUCPU_ISO_NPU] = &__clk_regmap_gate_hw(&clk_en_aucpu_iso_npu),
> + [RTD1625_CRT_CLK_EN_KEYLADDER] = &__clk_regmap_gate_hw(&clk_en_keyladder),
> + [RTD1625_CRT_CLK_EN_IFCP_KLM] = &__clk_regmap_gate_hw(&clk_en_ifcp_klm),
> + [RTD1625_CRT_CLK_EN_IFCP] = &__clk_regmap_gate_hw(&clk_en_ifcp),
> + [RTD1625_CRT_CLK_EN_MDL_GENPW] = &__clk_regmap_gate_hw(&clk_en_mdl_genpw),
> + [RTD1625_CRT_CLK_EN_MDL_CHIP] = &__clk_regmap_gate_hw(&clk_en_mdl_chip),
> + [RTD1625_CRT_CLK_EN_MDL_IP] = &__clk_regmap_gate_hw(&clk_en_mdl_ip),
> + [RTD1625_CRT_CLK_EN_MDLM2M] = &__clk_regmap_gate_hw(&clk_en_mdlm2m),
> + [RTD1625_CRT_CLK_EN_MDL_XTAL] = &__clk_regmap_gate_hw(&clk_en_mdl_xtal),
> + [RTD1625_CRT_CLK_EN_TEST_MUX] = &__clk_regmap_gate_hw(&clk_en_test_mux),
> + [RTD1625_CRT_CLK_EN_DLA] = &__clk_regmap_gate_hw(&clk_en_dla),
> + [RTD1625_CRT_CLK_EN_TPCW] = &__clk_regmap_gate_hw(&clk_en_tpcw),
> + [RTD1625_CRT_CLK_EN_GPU_TS_SRC] = &__clk_regmap_gate_hw(&clk_en_gpu_ts_src),
> + [RTD1625_CRT_CLK_EN_VI] = &__clk_regmap_gate_hw(&clk_en_vi),
> + [RTD1625_CRT_CLK_EN_LVDS1] = &__clk_regmap_gate_hw(&clk_en_lvds1),
> + [RTD1625_CRT_CLK_EN_LVDS2] = &__clk_regmap_gate_hw(&clk_en_lvds2),
> + [RTD1625_CRT_CLK_EN_AUCPU] = &__clk_regmap_gate_hw(&clk_en_aucpu),
> + [RTD1625_CRT_CLK_EN_UR1] = &__clk_regmap_gate_hw(&clk_en_ur1),
> + [RTD1625_CRT_CLK_EN_UR2] = &__clk_regmap_gate_hw(&clk_en_ur2),
> + [RTD1625_CRT_CLK_EN_UR3] = &__clk_regmap_gate_hw(&clk_en_ur3),
> + [RTD1625_CRT_CLK_EN_UR4] = &__clk_regmap_gate_hw(&clk_en_ur4),
> + [RTD1625_CRT_CLK_EN_UR5] = &__clk_regmap_gate_hw(&clk_en_ur5),
> + [RTD1625_CRT_CLK_EN_UR6] = &__clk_regmap_gate_hw(&clk_en_ur6),
> + [RTD1625_CRT_CLK_EN_UR7] = &__clk_regmap_gate_hw(&clk_en_ur7),
> + [RTD1625_CRT_CLK_EN_UR8] = &__clk_regmap_gate_hw(&clk_en_ur8),
> + [RTD1625_CRT_CLK_EN_UR9] = &__clk_regmap_gate_hw(&clk_en_ur9),
> + [RTD1625_CRT_CLK_EN_UR_TOP] = &__clk_regmap_gate_hw(&clk_en_ur_top),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_7] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_7),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_6] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_6),
> + [RTD1625_CRT_CLK_EN_SPI0] = &__clk_regmap_gate_hw(&clk_en_spi0),
> + [RTD1625_CRT_CLK_EN_SPI1] = &__clk_regmap_gate_hw(&clk_en_spi1),
> + [RTD1625_CRT_CLK_EN_SPI2] = &__clk_regmap_gate_hw(&clk_en_spi2),
> + [RTD1625_CRT_CLK_EN_LSADC0] = &__clk_regmap_gate_hw(&clk_en_lsadc0),
> + [RTD1625_CRT_CLK_EN_LSADC1] = &__clk_regmap_gate_hw(&clk_en_lsadc1),
> + [RTD1625_CRT_CLK_EN_ISOMIS_DMA] = &__clk_regmap_gate_hw(&clk_en_isomis_dma),
> + [RTD1625_CRT_CLK_EN_DPTX] = &__clk_regmap_gate_hw(&clk_en_dptx),
> + [RTD1625_CRT_CLK_EN_NPU_MIPI_CSI] = &__clk_regmap_gate_hw(&clk_en_npu_mipi_csi),
> + [RTD1625_CRT_CLK_EN_EDPTX] = &__clk_regmap_gate_hw(&clk_en_edptx),
> + [RTD1625_CRT_CLK_GPU] = &__clk_regmap_mux_hw(&clk_gpu),
> + [RTD1625_CRT_CLK_VE1] = &__clk_regmap_mux_hw(&clk_ve1),
> + [RTD1625_CRT_CLK_VE2] = &__clk_regmap_mux_hw(&clk_ve2),
> + [RTD1625_CRT_CLK_VE4] = &__clk_regmap_mux_hw(&clk_ve4),
> + [RTD1625_CRT_PLL_VE1] = &__clk_pll_hw(&pll_ve1),
> + [RTD1625_CRT_PLL_DDSA] = &__clk_pll_hw(&pll_ddsa),
> + [RTD1625_CRT_PLL_BUS] = &__clk_pll_hw(&pll_bus),
> + [RTD1625_CRT_CLK_SYS] = &clk_sys.hw,
> + [RTD1625_CRT_PLL_DCSB] = &__clk_pll_hw(&pll_dcsb),
> + [RTD1625_CRT_CLK_SYSH] = &clk_sysh.hw,
> + [RTD1625_CRT_PLL_GPU] = &__clk_pll_hw(&pll_gpu),
> + [RTD1625_CRT_PLL_NPU] = &__clk_pll_hw(&pll_npu),
> + [RTD1625_CRT_PLL_VE2] = &__clk_pll_hw(&pll_ve2),
> + [RTD1625_CRT_PLL_HIFI] = &__clk_pll_hw(&pll_hifi),
> + [RTD1625_CRT_PLL_EMMC_REF] = &pll_emmc_ref.hw,
> + [RTD1625_CRT_PLL_EMMC] = &__clk_pll_mmc_hw(&pll_emmc),
> + [RTD1625_CRT_PLL_EMMC_VP0] = &pll_emmc.phase0_hw,
> + [RTD1625_CRT_PLL_EMMC_VP1] = &pll_emmc.phase1_hw,
> + [RTD1625_CRT_PLL_ACPU] = &__clk_pll_hw(&pll_acpu),
> + [RTD1625_CRT_CLK_NPU] = &clk_npu.hw,
> + [RTD1625_CRT_CLK_NPU_MIPI_CSI] = &clk_npu_mipi_csi.hw,
> +
> + [RTD1625_CRT_CLK_MAX] = NULL,
> + },
> +};
> +
> +static const struct rtk_clk_desc rtd1625_crt_desc = {
> + .clk_data = &rtd1625_crt_hw_data,
> + .clks = rtd1625_crt_regmap_clks,
> + .num_clks = ARRAY_SIZE(rtd1625_crt_regmap_clks),
> +};
> +
> +static int rtd1625_crt_probe(struct platform_device *pdev)
> +{
> + const struct rtk_clk_desc *desc;
> +
> + desc = of_device_get_match_data(&pdev->dev);
> + if (!desc)
> + return -EINVAL;
> +
> + return rtk_clk_probe(pdev, desc, "crt_rst");
> +}
> +
> +static const struct of_device_id rtd1625_crt_match[] = {
> + {.compatible = "realtek,rtd1625-crt-clk", .data = &rtd1625_crt_desc,},
> + {/* sentinel */}
Add a space around the comment like so:
{ /* sentinel */ }
> +};
> +
> +static struct platform_driver rtd1625_crt_driver = {
> + .probe = rtd1625_crt_probe,
> + .driver = {
> + .name = "rtk-rtd1625-crt-clk",
> + .of_match_table = rtd1625_crt_match,
> + },
> +};
> +
> +static int __init rtd1625_crt_init(void)
> +{
> + return platform_driver_register(&rtd1625_crt_driver);
> +}
> +subsys_initcall(rtd1625_crt_init);
> +
> +MODULE_DESCRIPTION("Reatek RTD1625 CRT Controller Driver");
s/Reatek/Realtex/
> +MODULE_AUTHOR("Cheng-Yu Lee <cylee12@realtek.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_CLK");
> diff --git a/drivers/reset/realtek/Kconfig b/drivers/reset/realtek/Kconfig
> index 99a14d355803..a44c7834191c 100644
> --- a/drivers/reset/realtek/Kconfig
> +++ b/drivers/reset/realtek/Kconfig
> @@ -1,3 +1,5 @@
> # SPDX-License-Identifier: GPL-2.0-only
> config RESET_RTK_COMMON
> bool
> + select AUXILIARY_BUS
> + default COMMON_CLK_RTD1625
> diff --git a/drivers/reset/realtek/Makefile b/drivers/reset/realtek/Makefile
> index b59a3f7f2453..8ca1fa939f10 100644
> --- a/drivers/reset/realtek/Makefile
> +++ b/drivers/reset/realtek/Makefile
> @@ -1,2 +1,2 @@
> # SPDX-License-Identifier: GPL-2.0-only
> -obj-$(CONFIG_RESET_RTK_COMMON) += common.o
> +obj-$(CONFIG_RESET_RTK_COMMON) += common.o reset-rtd1625-crt.o
CONFIG_RESET_RTK_COMMON is supposed to be common, right? If so, the
SoC-specific driver shouldn't be included here.
> diff --git a/drivers/reset/realtek/reset-rtd1625-crt.c b/drivers/reset/realtek/reset-rtd1625-crt.c
> new file mode 100644
> index 000000000000..ebb15bb68885
> --- /dev/null
> +++ b/drivers/reset/realtek/reset-rtd1625-crt.c
> @@ -0,0 +1,186 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026 Realtek Semiconductor Corporation
> + */
> +
> +#include <dt-bindings/reset/realtek,rtd1625.h>
> +#include <linux/auxiliary_bus.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include "common.h"
> +
> +#define RTD1625_CRT_RSTN_MAX 123
> +
> +static struct rtk_reset_desc rtd1625_crt_reset_descs[] = {
> + /* Bank 0: offset 0x0 */
> + [RTD1625_CRT_RSTN_MISC] = { .ofs = 0x0, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DIP] = { .ofs = 0x0, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_GSPI] = { .ofs = 0x0, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDS] = { .ofs = 0x0, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDS_REG] = { .ofs = 0x0, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDS_PHY] = { .ofs = 0x0, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_GPU2D] = { .ofs = 0x0, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DC_PHY] = { .ofs = 0x0, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DCPHY_CRT] = { .ofs = 0x0, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LSADC] = { .ofs = 0x0, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SE] = { .ofs = 0x0, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DLA] = { .ofs = 0x0, .bit = 30, .write_en = 1 },
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Can this cause undefined behavior during reset mask computation?
Several reset array entries set .bit = 30 and .write_en = 1. In
rtk_reset_assert() and rtk_reset_deassert(), if the bitmask is computed as
0x3 << desc->bit, 0x3 is a signed 32-bit integer literal. Left-shifting it by
30 results in 0xC0000000, which exceeds the maximum positive value for a
signed 32-bit integer.
Modifying the sign bit via left-shift on a signed type invokes undefined
behavior in C. Would an unsigned literal (e.g., 0x3U << desc->bit) be needed
to safely construct the mask?
> + /* Bank 1: offset 0x4 */
> + [RTD1625_CRT_RSTN_JPEG] = { .ofs = 0x4, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SD] = { .ofs = 0x4, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDIO] = { .ofs = 0x4, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCR_CNT] = { .ofs = 0x4, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_STITCH] = { .ofs = 0x4, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_PHY] = { .ofs = 0x4, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0] = { .ofs = 0x4, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_CORE] = { .ofs = 0x4, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_POWER] = { .ofs = 0x4, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_NONSTICH] = { .ofs = 0x4, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_PHY_MDIO] = { .ofs = 0x4, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_SGMII_MDIO] = { .ofs = 0x4, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VO2] = { .ofs = 0x4, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MISC_SC0] = { .ofs = 0x4, .bit = 30, .write_en = 1 },
> + /* Bank 2: offset 0x8 */
> + [RTD1625_CRT_RSTN_MD] = { .ofs = 0x8, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LVDS1] = { .ofs = 0x8, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LVDS2] = { .ofs = 0x8, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MISC_SC1] = { .ofs = 0x8, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_3] = { .ofs = 0x8, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_FAN] = { .ofs = 0x8, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_TVE] = { .ofs = 0x8, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AIO] = { .ofs = 0x8, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VO] = { .ofs = 0x8, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MIPI_CSI] = { .ofs = 0x8, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMIRX] = { .ofs = 0x8, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMIRX_WRAP] = { .ofs = 0x8, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMI] = { .ofs = 0x8, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DISP] = { .ofs = 0x8, .bit = 30, .write_en = 1 },
> + /* Bank 3: offset 0xc */
> + [RTD1625_CRT_RSTN_SATA_PHY_POW1] = { .ofs = 0xc, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_PHY_POW0] = { .ofs = 0xc, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MDIO1] = { .ofs = 0xc, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MDIO0] = { .ofs = 0xc, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_WRAP] = { .ofs = 0xc, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MAC_P1] = { .ofs = 0xc, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MAC_P0] = { .ofs = 0xc, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MAC_COM] = { .ofs = 0xc, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_STITCH] = { .ofs = 0xc, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_PHY] = { .ofs = 0xc, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1] = { .ofs = 0xc, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_CORE] = { .ofs = 0xc, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_POWER] = { .ofs = 0xc, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_NONSTICH] = { .ofs = 0xc, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_PHY_MDIO] = { .ofs = 0xc, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMITOP] = { .ofs = 0xc, .bit = 30, .write_en = 1 },
> + /* Bank 4: offset 0x68 */
> + [RTD1625_CRT_RSTN_I2C_4] = { .ofs = 0x68, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_5] = { .ofs = 0x68, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_TSIO] = { .ofs = 0x68, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VI] = { .ofs = 0x68, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_EDP] = { .ofs = 0x68, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1_MMU] = { .ofs = 0x68, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1_MMU_FUNC] = { .ofs = 0x68, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HSE_MMU] = { .ofs = 0x68, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HSE_MMU_FUNC] = { .ofs = 0x68, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDLM2M] = { .ofs = 0x68, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_ISO_GSPI] = { .ofs = 0x68, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SOFT_NPU] = { .ofs = 0x68, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SPI2EMMC] = { .ofs = 0x68, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_EARC] = { .ofs = 0x68, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1] = { .ofs = 0x68, .bit = 30, .write_en = 1 },
> + /* Bank 5: offset 0x90 */
> + [RTD1625_CRT_RSTN_PCIE2_STITCH] = { .ofs = 0x90, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_PHY] = { .ofs = 0x90, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2] = { .ofs = 0x90, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_CORE] = { .ofs = 0x90, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_POWER] = { .ofs = 0x90, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_NONSTICH] = { .ofs = 0x90, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_PHY_MDIO] = { .ofs = 0x90, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DCPHY_UMCTL2] = { .ofs = 0x90, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MIPI_DSI] = { .ofs = 0x90, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HIFM] = { .ofs = 0x90, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_NSRAM] = { .ofs = 0x90, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AUCPU0_REG] = { .ofs = 0x90, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDL_GENPW] = { .ofs = 0x90, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDL_CHIP] = { .ofs = 0x90, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDL_IP] = { .ofs = 0x90, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_TEST_MUX] = { .ofs = 0x90, .bit = 30, .write_en = 1 },
> + /* Bank 6: offset 0xb8 */
> + [RTD1625_CRT_RSTN_ISO_BIST] = { .ofs = 0xb8, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MAIN_BIST] = { .ofs = 0xb8, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MAIN2_BIST] = { .ofs = 0xb8, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1_BIST] = { .ofs = 0xb8, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE2_BIST] = { .ofs = 0xb8, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DCPHY_BIST] = { .ofs = 0xb8, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_GPU_BIST] = { .ofs = 0xb8, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DISP_BIST] = { .ofs = 0xb8, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_NPU_BIST] = { .ofs = 0xb8, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_CAS_BIST] = { .ofs = 0xb8, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE4_BIST] = { .ofs = 0xb8, .bit = 20, .write_en = 1 },
> + /* Bank 7: offset 0x454 (DUMMY0, no write_en) */
> + [RTD1625_CRT_RSTN_EMMC] = { .ofs = 0x454, .bit = 0 },
> + /* Bank 8: offset 0x458 (DUMMY1, no write_en) */
> + [RTD1625_CRT_RSTN_GPU] = { .ofs = 0x458, .bit = 0 },
> + /* Bank 9: offset 0x464 (DUMMY4, no write_en) */
> + [RTD1625_CRT_RSTN_VE2] = { .ofs = 0x464, .bit = 0 },
> + /* Bank 10: offset 0x880 */
> + [RTD1625_CRT_RSTN_UR1] = { .ofs = 0x880, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR2] = { .ofs = 0x880, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR3] = { .ofs = 0x880, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR4] = { .ofs = 0x880, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR5] = { .ofs = 0x880, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR6] = { .ofs = 0x880, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR7] = { .ofs = 0x880, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR8] = { .ofs = 0x880, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR9] = { .ofs = 0x880, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR_TOP] = { .ofs = 0x880, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_7] = { .ofs = 0x880, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_6] = { .ofs = 0x880, .bit = 30, .write_en = 1 },
> + /* Bank 11: offset 0x890 */
> + [RTD1625_CRT_RSTN_SPI0] = { .ofs = 0x890, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SPI1] = { .ofs = 0x890, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SPI2] = { .ofs = 0x890, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LSADC0] = { .ofs = 0x890, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LSADC1] = { .ofs = 0x890, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_ISOMIS_DMA] = { .ofs = 0x890, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AUDIO_ADC] = { .ofs = 0x890, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DPTX] = { .ofs = 0x890, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AUCPU1_REG] = { .ofs = 0x890, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_EDPTX] = { .ofs = 0x890, .bit = 28, .write_en = 1 },
> +};
> +
> +static int rtd1625_crt_reset_probe(struct auxiliary_device *adev,
> + const struct auxiliary_device_id *id)
> +{
> + struct device *dev = &adev->dev;
> + struct rtk_reset_data *data;
> +
> + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + data->descs = rtd1625_crt_reset_descs;
> + data->rcdev.nr_resets = RTD1625_CRT_RSTN_MAX;
> + return rtk_reset_controller_add(dev, data);
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Will the reset controller driver unconditionally fail to probe with -ENODEV
due to an incompatible regmap acquisition method?
The rtk_reset_controller_add() helper attempts to retrieve the shared regmap
from the parent clock device using dev_get_regmap(parent, NULL). However, the
parent clock driver (rtk_clk_probe()) acquires its regmap via
device_node_to_regmap().
This syscon helper creates the regmap but does not associate it with the
parent struct device via devres. Because the regmap is absent from the
parent's devres list, dev_get_regmap() will always return NULL, causing the
reset driver probe to fail unconditionally and leaving dependent peripherals
without reset control.
Brian
> +}
> +
> +static const struct auxiliary_device_id rtd1625_crt_reset_ids[] = {
> + {
> + .name = "clk_rtk.crt_rst",
> + },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(auxiliary, rtd1625_crt_reset_ids);
> +
> +static struct auxiliary_driver rtd1625_crt_driver = {
> + .probe = rtd1625_crt_reset_probe,
> + .id_table = rtd1625_crt_reset_ids,
> + .driver = {
> + .name = "rtd1625-crt-reset",
> + },
> +};
> +module_auxiliary_driver(rtd1625_crt_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_RESET");
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH v3 2/2] mailbox: Make mbox_send_message() return error code when tx fails
From: Joonwon Kang @ 2026-04-03 15:19 UTC (permalink / raw)
To: jassisinghbrar
Cc: angelogioacchino.delregno, jonathanh, joonwonkang,
linux-arm-kernel, linux-kernel, linux-mediatek, linux-tegra,
matthias.bgg, stable, thierry.reding, akpm
In-Reply-To: <CABb+yY3hYcJ82QGor3w5KKHUGz9Pc1k64Jdf-94E4Yvv0DTeyQ@mail.gmail.com>
> On Thu, Apr 2, 2026 at 12:07 PM Joonwon Kang <joonwonkang@google.com> wrote:
> >
> > When the mailbox controller failed transmitting message, the error code
> > was only passed to the client's tx done handler and not to
> > mbox_send_message(). For this reason, the function could return a false
> > success. This commit resolves the issue by introducing the tx status and
> > checking it before mbox_send_message() returns.
> >
> Can you please share the scenario when this becomes necessary? This
> can potentially change the ground underneath some clients, so we have
> to be sure this is really useful.
I would say the problem here is generic enough to apply to all the cases where
the send result needs to be checked. Since the return value of the send API is
not the real send result, any users who believe that this blocking send API
will return the real send result could fall for that. For example, users may
think the send was successful even though it was not actually. I believe it is
uncommon that users have to register a callback solely to get the send result
even though they are using the blocking send API already. Also, I guess there
is no special reason why only the mailbox send API should work this way among
other typical blocking send APIs. For these reasons, this patch makes the send
API return the real send result. This way, users will not need to register the
redundant callback and I think the return value will align with their common
expectation.
Regarding the change in the ground for some clients, could you help to clarify
a bit more on what change, you expect, would surprise the clients?
Thanks,
Joonwon Kang
>
> Thanks
> Jassi
>
>
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Joonwon Kang <joonwonkang@google.com>
> > ---
> > drivers/mailbox/mailbox.c | 20 +++++++++++++++-----
> > include/linux/mailbox_controller.h | 2 ++
> > 2 files changed, 17 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
> > index d63386468982..ea9aec9dc947 100644
> > --- a/drivers/mailbox/mailbox.c
> > +++ b/drivers/mailbox/mailbox.c
> > @@ -21,7 +21,10 @@
> > static LIST_HEAD(mbox_cons);
> > static DEFINE_MUTEX(con_mutex);
> >
> > -static int add_to_rbuf(struct mbox_chan *chan, void *mssg, struct completion *tx_complete)
> > +static int add_to_rbuf(struct mbox_chan *chan,
> > + void *mssg,
> > + struct completion *tx_complete,
> > + int *tx_status)
> > {
> > int idx;
> >
> > @@ -34,6 +37,7 @@ static int add_to_rbuf(struct mbox_chan *chan, void *mssg, struct completion *tx
> > idx = chan->msg_free;
> > chan->msg_data[idx].data = mssg;
> > chan->msg_data[idx].tx_complete = tx_complete;
> > + chan->msg_data[idx].tx_status = tx_status;
> > chan->msg_count++;
> >
> > if (idx == MBOX_TX_QUEUE_LEN - 1)
> > @@ -91,12 +95,13 @@ static void msg_submit(struct mbox_chan *chan)
> >
> > static void tx_tick(struct mbox_chan *chan, int r, int idx)
> > {
> > - struct mbox_message mssg = {MBOX_NO_MSG, NULL};
> > + struct mbox_message mssg = {MBOX_NO_MSG, NULL, NULL};
> >
> > scoped_guard(spinlock_irqsave, &chan->lock) {
> > if (idx >= 0 && idx != chan->active_req) {
> > chan->msg_data[idx].data = MBOX_NO_MSG;
> > chan->msg_data[idx].tx_complete = NULL;
> > + chan->msg_data[idx].tx_status = NULL;
> > return;
> > }
> >
> > @@ -116,8 +121,10 @@ static void tx_tick(struct mbox_chan *chan, int r, int idx)
> > if (chan->cl->tx_done)
> > chan->cl->tx_done(chan->cl, mssg.data, r);
> >
> > - if (r != -ETIME && chan->cl->tx_block)
> > + if (r != -ETIME && chan->cl->tx_block) {
> > + *mssg.tx_status = r;
> > complete(mssg.tx_complete);
> > + }
> > }
> >
> > static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
> > @@ -286,15 +293,16 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
> > int t;
> > int idx;
> > struct completion tx_complete;
> > + int tx_status = 0;
> >
> > if (!chan || !chan->cl || mssg == MBOX_NO_MSG)
> > return -EINVAL;
> >
> > if (chan->cl->tx_block) {
> > init_completion(&tx_complete);
> > - t = add_to_rbuf(chan, mssg, &tx_complete);
> > + t = add_to_rbuf(chan, mssg, &tx_complete, &tx_status);
> > } else {
> > - t = add_to_rbuf(chan, mssg, NULL);
> > + t = add_to_rbuf(chan, mssg, NULL, NULL);
> > }
> >
> > if (t < 0) {
> > @@ -318,6 +326,8 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
> > idx = t;
> > t = -ETIME;
> > tx_tick(chan, t, idx);
> > + } else if (tx_status < 0) {
> > + t = tx_status;
> > }
> > }
> >
> > diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
> > index 912499ad08ed..890da97bcb50 100644
> > --- a/include/linux/mailbox_controller.h
> > +++ b/include/linux/mailbox_controller.h
> > @@ -117,10 +117,12 @@ struct mbox_controller {
> > * struct mbox_message - Internal representation of a mailbox message
> > * @data: Data packet
> > * @tx_complete: Pointer to the transmission completion
> > + * @tx_status: Pointer to the transmission status
> > */
> > struct mbox_message {
> > void *data;
> > struct completion *tx_complete;
> > + int *tx_status;
> > };
> >
> > /**
> > --
> > 2.53.0.1185.g05d4b7b318-goog
> >
^ permalink raw reply
* Re: [PATCH v6 07/10] clk: realtek: Add support for MMC-tuned PLL clocks
From: Brian Masney @ 2026-04-03 15:10 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-8-eleanor.lin@realtek.com>
Hi Yu-Chun,
I should have finished going through Sashiko while manually reviewing
your patches.
On Thu, Apr 02, 2026 at 03:39:54PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add clk_pll_mmc_ops for enable/disable, prepare, rate control, and status
> operations on MMC PLL clocks.
>
> Also add clk_pll_mmc_phase_ops to support phase get/set operations.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Jyan Chou <jyanchou@realtek.com>
> Signed-off-by: Jyan Chou <jyanchou@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> +static int clk_pll_mmc_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val = PLL_MMC_SSC_DIV_N_VAL;
> + int ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_FLAG_INITAL_EMMC_MASK, 0x0 << PLL_FLAG_INITAL_EMMC_SHIFT);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_n(clkm, val);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_ext_f(clkm, 1517);
> + if (ret)
> + return ret;
> +
> + switch (val) {
> + case 31 ... 46:
> + ret |= set_pi_ibselh(clkm, 3);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 2);
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Is it intended to use bitwise OR to accumulate these return values? Because
these hardware operations return standard negative error codes on failure,
performing a bitwise OR on multiple negative integers will merge their bit
patterns and create a corrupted error code.
> + break;
> +
> + case 20 ... 30:
> + ret |= set_pi_ibselh(clkm, 2);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 10 ... 19:
> + ret |= set_pi_ibselh(clkm, 1);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 5 ... 9:
> + ret |= set_pi_ibselh(clkm, 0);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 0);
> + break;
> + }
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC3_OFFSET,
> + PLL_NCODE_SSC_EMMC_MASK,
> + 27 << PLL_NCODE_SSC_EMMC_SHIFT);
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Are the mask and shift values mismatched here? PLL_FLAG_INITAL_EMMC_MASK is
defined as BIT(1) (0x02), but PLL_FLAG_INITAL_EMMC_SHIFT is 8.
When regmap_update_bits() applies the 0x02 mask to a value shifted by 8,
won't it evaluate to 0 and fail to set the intended initialization flag?
Brian
^ permalink raw reply
* Re: [PATCH v6 07/10] clk: realtek: Add support for MMC-tuned PLL clocks
From: Brian Masney @ 2026-04-03 15:07 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-8-eleanor.lin@realtek.com>
Hi Yu-Chun and Cheng-Yu,
On Thu, Apr 02, 2026 at 03:39:54PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add clk_pll_mmc_ops for enable/disable, prepare, rate control, and status
> operations on MMC PLL clocks.
>
> Also add clk_pll_mmc_phase_ops to support phase get/set operations.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Jyan Chou <jyanchou@realtek.com>
> Signed-off-by: Jyan Chou <jyanchou@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> - Move to_clk_pll_mmc() from clk-pll.h to clk-pll-mmc.c to limit its scope.
> - Change offset type from int to unsigned int.
> ---
> MAINTAINERS | 8 +
> drivers/clk/realtek/Kconfig | 3 +
> drivers/clk/realtek/Makefile | 2 +
> drivers/clk/realtek/clk-pll-mmc.c | 410 ++++++++++++++++++++++++++++++
> drivers/clk/realtek/clk-pll.h | 13 +
> 5 files changed, 436 insertions(+)
> create mode 100644 drivers/clk/realtek/clk-pll-mmc.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8318156a02b5..4b28af4b26b5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22245,6 +22245,14 @@ F: drivers/reset/realtek/*
> F: include/dt-bindings/clock/realtek*
> F: include/dt-bindings/reset/realtek*
>
> +REALTEK SOC PLL CLOCK FOR MMC SUPPORT
> +M: Cheng-Yu Lee <cylee12@realtek.com>
> +M: Jyan Chou <jyanchou@realtek.com>
> +M: Yu-Chun Lin <eleanor.lin@realtek.com>
> +L: linux-clk@vger.kernel.org
> +S: Supported
> +F: drivers/clk/realtek/clk-pll-mmc.c
> +
> REALTEK SPI-NAND
> M: Chris Packham <chris.packham@alliedtelesis.co.nz>
> S: Maintained
> diff --git a/drivers/clk/realtek/Kconfig b/drivers/clk/realtek/Kconfig
> index bc47d3f1c452..b31a31e57b3a 100644
> --- a/drivers/clk/realtek/Kconfig
> +++ b/drivers/clk/realtek/Kconfig
> @@ -25,4 +25,7 @@ config RTK_CLK_COMMON
> multiple Realtek clock implementations, and include integration
> with reset controllers where required.
>
> +config RTK_CLK_PLL_MMC
> + bool
> +
> endif
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index f90dc57fcfdb..fd7d777902c8 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -7,3 +7,5 @@ clk-rtk-y += clk-pll.o
> clk-rtk-y += clk-regmap-gate.o
> clk-rtk-y += clk-regmap-mux.o
> clk-rtk-y += freq_table.o
> +
> +clk-rtk-$(CONFIG_RTK_CLK_PLL_MMC) += clk-pll-mmc.o
> diff --git a/drivers/clk/realtek/clk-pll-mmc.c b/drivers/clk/realtek/clk-pll-mmc.c
> new file mode 100644
> index 000000000000..d28c7027d3f0
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-pll-mmc.c
> @@ -0,0 +1,410 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2021 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include "clk-pll.h"
> +
> +#define PLL_EMMC1_OFFSET 0x0
> +#define PLL_EMMC2_OFFSET 0x4
> +#define PLL_EMMC3_OFFSET 0x8
> +#define PLL_EMMC4_OFFSET 0xc
> +#define PLL_SSC_DIG_EMMC1_OFFSET 0x0
> +#define PLL_SSC_DIG_EMMC3_OFFSET 0xc
> +#define PLL_SSC_DIG_EMMC4_OFFSET 0x10
> +
> +#define PLL_MMC_SSC_DIV_N_VAL 0x1b
> +
> +#define PLL_PHRT0_MASK BIT(1)
> +#define PLL_PHSEL_MASK GENMASK(4, 0)
> +#define PLL_SSCPLL_RS_MASK GENMASK(12, 10)
> +#define PLL_SSCPLL_ICP_MASK GENMASK(9, 5)
> +#define PLL_SSC_DIV_EXT_F_MASK GENMASK(25, 13)
> +#define PLL_PI_IBSELH_MASK GENMASK(28, 27)
> +#define PLL_SSC_DIV_N_MASK GENMASK(23, 16)
> +#define PLL_NCODE_SSC_EMMC_MASK GENMASK(20, 13)
> +#define PLL_FCODE_SSC_EMMC_MASK GENMASK(12, 0)
> +#define PLL_GRAN_EST_EM_MC_MASK GENMASK(20, 0)
> +#define PLL_EN_SSC_EMMC_MASK BIT(0)
> +#define PLL_FLAG_INITAL_EMMC_MASK BIT(1)
> +
> +#define PLL_PHRT0_SHIFT 1
> +#define PLL_SSCPLL_RS_SHIFT 10
> +#define PLL_SSCPLL_ICP_SHIFT 5
> +#define PLL_SSC_DIV_EXT_F_SHIFT 13
> +#define PLL_PI_IBSELH_SHIFT 27
> +#define PLL_SSC_DIV_N_SHIFT 16
> +#define PLL_NCODE_SSC_EMMC_SHIFT 13
> +#define PLL_FLAG_INITAL_EMMC_SHIFT 8
> +
> +#define CYCLE_DEGREES 360
> +#define PHASE_STEPS 32
> +#define PHASE_SCALE_FACTOR 1125
> +
> +static inline struct clk_pll_mmc *to_clk_pll_mmc(struct clk_hw *hw)
> +{
> + struct clk_regmap *clkr = to_clk_regmap(hw);
> +
> + return container_of(clkr, struct clk_pll_mmc, clkr);
> +}
> +
> +static inline int get_phrt0(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + u32 reg;
> + int ret;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET, ®);
> + if (ret)
> + return ret;
> +
> + *val = (reg >> PLL_PHRT0_SHIFT) & PLL_PHRT0_MASK;
Sashiko reports the following:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
With PLL_PHRT0_SHIFT defined as 1 and PLL_PHRT0_MASK as BIT(1) (0x02), shifting
right by 1 moves the target bit 1 to position 0, but masking with 0x02 checks
position 1 of the shifted value.
Will this cause clk_pll_mmc_is_enabled() to always evaluate to false since it
expects val == 0x1?
> + return 0;
> +}
> +
> +static inline int set_phrt0(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET,
> + PLL_PHRT0_MASK, val << PLL_PHRT0_SHIFT);
> +}
> +
> +static inline int get_phsel(struct clk_pll_mmc *clkm, int id, u32 *val)
> +{
> + int ret;
> + u32 raw_val;
> + u32 sft = id ? 8 : 3;
Put variables in reverse Christmas tree order.
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = (raw_val >> sft) & PLL_PHSEL_MASK;
> + return 0;
> +}
> +
> +static inline int set_phsel(struct clk_pll_mmc *clkm, int id, u32 val)
> +{
> + u32 sft = id ? 8 : 3;
> +
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET,
> + PLL_PHSEL_MASK << sft, val << sft);
> +}
> +
> +static inline int set_sscpll_rs(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_SSCPLL_RS_MASK, val << PLL_SSCPLL_RS_SHIFT);
> +}
> +
> +static inline int set_sscpll_icp(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_SSCPLL_ICP_MASK, val << PLL_SSCPLL_ICP_SHIFT);
> +}
> +
> +static inline int get_ssc_div_ext_f(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + u32 raw_val;
> + int ret;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = (raw_val & PLL_SSC_DIV_EXT_F_MASK) >> PLL_SSC_DIV_EXT_F_SHIFT;
> + return 0;
> +}
> +
> +static inline int set_ssc_div_ext_f(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_SSC_DIV_EXT_F_MASK,
> + val << PLL_SSC_DIV_EXT_F_SHIFT);
> +}
> +
> +static inline int set_pi_ibselh(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_PI_IBSELH_MASK, val << PLL_PI_IBSELH_SHIFT);
> +}
> +
> +static inline int set_ssc_div_n(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC3_OFFSET,
> + PLL_SSC_DIV_N_MASK, val << PLL_SSC_DIV_N_SHIFT);
> +}
> +
> +static inline int get_ssc_div_n(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + int ret;
> + u32 raw_val;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC3_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = (raw_val & PLL_SSC_DIV_N_MASK) >> PLL_SSC_DIV_N_SHIFT;
> + return 0;
> +}
> +
> +static inline int set_pow_ctl(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_write(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC4_OFFSET, val);
> +}
> +
> +static inline int get_pow_ctl(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + int ret;
> + u32 raw_val;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC4_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = raw_val;
> +
> + return 0;
> +}
> +
> +static int clk_pll_mmc_phase_set_phase(struct clk_hw *hw, int degrees)
> +{
> + struct clk_hw *hwp = clk_hw_get_parent(hw);
> + struct clk_pll_mmc *clkm;
> + int phase_id;
> + int ret;
> + u32 val;
> +
> + if (!hwp)
> + return -ENOENT;
> +
> + clkm = to_clk_pll_mmc(hwp);
> + phase_id = (hw - &clkm->phase0_hw) ? 1 : 0;
Are you checking to see if these two pointers are the same? If so, what
do you think about this instead?
hw == &clkm->phase0_hw
> + val = DIV_ROUND_CLOSEST(degrees * 100, PHASE_SCALE_FACTOR);
> + ret = set_phsel(clkm, phase_id, val);
> + if (ret)
> + return ret;
> +
> + usleep_range(10, 20);
> + return 0;
> +}
> +
> +static int clk_pll_mmc_phase_get_phase(struct clk_hw *hw)
> +{
> + struct clk_hw *hwp;
> + struct clk_pll_mmc *clkm;
> + int phase_id;
> + int ret;
> + u32 val;
> +
> + hwp = clk_hw_get_parent(hw);
> + if (!hwp)
> + return -ENOENT;
> +
> + clkm = to_clk_pll_mmc(hwp);
> + phase_id = (hw - &clkm->phase0_hw) ? 1 : 0;
> + ret = get_phsel(clkm, phase_id, &val);
> + if (ret)
> + return ret;
> +
> + val = DIV_ROUND_CLOSEST(val * CYCLE_DEGREES, PHASE_STEPS);
> +
> + return val;
> +}
> +
> +const struct clk_ops rtk_clk_pll_mmc_phase_ops = {
> + .set_phase = clk_pll_mmc_phase_set_phase,
> + .get_phase = clk_pll_mmc_phase_get_phase,
> +};
> +EXPORT_SYMBOL_NS_GPL(rtk_clk_pll_mmc_phase_ops, "REALTEK_CLK");
> +
> +static int clk_pll_mmc_prepare(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> +
> + return set_pow_ctl(clkm, 7);
> +}
> +
> +static void clk_pll_mmc_unprepare(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> +
> + set_pow_ctl(clkm, 0);
> +}
> +
> +static int clk_pll_mmc_is_prepared(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val;
> + int ret;
> +
> + ret = get_pow_ctl(clkm, &val);
> + if (ret)
> + return 1;
> +
> + return val != 0x0;
> +}
> +
> +static int clk_pll_mmc_enable(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + int ret;
> +
> + ret = set_phrt0(clkm, 1);
> + if (ret)
> + return ret;
> +
> + udelay(10);
> + return 0;
> +}
> +
> +static void clk_pll_mmc_disable(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> +
> + set_phrt0(clkm, 0);
> + udelay(10);
> +}
> +
> +static int clk_pll_mmc_is_enabled(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val;
> + int ret;
> +
> + ret = get_phrt0(clkm, &val);
> + if (ret)
> + return 1;
> +
> + return val == 0x1;
> +}
> +
> +static unsigned long clk_pll_mmc_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val, ext_f;
> + int ret;
> +
> + ret = get_ssc_div_n(clkm, &val);
> + if (ret)
> + return ret;
> +
> + ret = get_ssc_div_ext_f(clkm, &ext_f);
> + if (ret)
> + return ret;
> +
> + return parent_rate / 4 * (val + 2) + (parent_rate / 4 * ext_f) / 8192;
> +}
> +
> +static int clk_pll_mmc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
> +{
Should there be a check for a parent rate of zero before the division is
done?
> + u32 val = DIV_ROUND_CLOSEST(req->rate * 4, req->best_parent_rate);
> +
> + req->rate = req->best_parent_rate * val / 4;
> + return 0;
> +}
> +
> +static int clk_pll_mmc_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val = PLL_MMC_SSC_DIV_N_VAL;
> + int ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_FLAG_INITAL_EMMC_MASK, 0x0 << PLL_FLAG_INITAL_EMMC_SHIFT);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_n(clkm, val);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_ext_f(clkm, 1517);
> + if (ret)
> + return ret;
> +
> + switch (val) {
> + case 31 ... 46:
> + ret |= set_pi_ibselh(clkm, 3);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 2);
> + break;
> +
> + case 20 ... 30:
> + ret |= set_pi_ibselh(clkm, 2);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 10 ... 19:
> + ret |= set_pi_ibselh(clkm, 1);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 5 ... 9:
> + ret |= set_pi_ibselh(clkm, 0);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 0);
> + break;
> + }
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC3_OFFSET,
> + PLL_NCODE_SSC_EMMC_MASK,
> + 27 << PLL_NCODE_SSC_EMMC_SHIFT);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC3_OFFSET,
> + PLL_FCODE_SSC_EMMC_MASK, 321);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC4_OFFSET,
> + PLL_GRAN_EST_EM_MC_MASK, 5985);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_EN_SSC_EMMC_MASK, 0x1);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_EN_SSC_EMMC_MASK, 0x0);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_FLAG_INITAL_EMMC_MASK,
> + 0x1 << PLL_FLAG_INITAL_EMMC_SHIFT);
It looks like the rate and parent rate are not used in this function.
Will this always end up with the same rate when everything is
successful?
Brian
^ permalink raw reply
* Re: [PATCH v6 06/10] clk: realtek: Add support for mux clock
From: Brian Masney @ 2026-04-03 14:54 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-7-eleanor.lin@realtek.com>
Hi Yu-Chun and Cheng-Yu,
On Thu, Apr 02, 2026 at 03:39:53PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add a simple regmap-based clk_ops implementation for Realtek mux clocks.
>
> The implementation supports parent selection and rate determination through
> regmap-backed register access.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> ---
> drivers/clk/realtek/Makefile | 1 +
> drivers/clk/realtek/clk-regmap-mux.c | 48 ++++++++++++++++++++++++++++
> drivers/clk/realtek/clk-regmap-mux.h | 43 +++++++++++++++++++++++++
> 3 files changed, 92 insertions(+)
> create mode 100644 drivers/clk/realtek/clk-regmap-mux.c
> create mode 100644 drivers/clk/realtek/clk-regmap-mux.h
>
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index 74375f8127ac..f90dc57fcfdb 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -5,4 +5,5 @@ clk-rtk-y += common.o
>
> clk-rtk-y += clk-pll.o
> clk-rtk-y += clk-regmap-gate.o
> +clk-rtk-y += clk-regmap-mux.o
> clk-rtk-y += freq_table.o
> diff --git a/drivers/clk/realtek/clk-regmap-mux.c b/drivers/clk/realtek/clk-regmap-mux.c
> new file mode 100644
> index 000000000000..068b056d61f0
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-regmap-mux.c
> @@ -0,0 +1,48 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <linux/regmap.h>
> +#include <linux/clk-provider.h>
Sort the includes.
> +#include "clk-regmap-mux.h"
> +
> +static u8 clk_regmap_mux_get_parent(struct clk_hw *hw)
> +{
> + struct clk_regmap_mux *clkm = to_clk_regmap_mux(hw);
> + int num_parents = clk_hw_get_num_parents(hw);
> + u32 val;
> + int ret;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->mux_ofs, &val);
> + if (ret)
> + return 0;
This is another case where it'd be nice to get the get_parent
declaration fixed. Stephen recently linked to some work of his from 2022
here.
https://lore.kernel.org/linux-clk/177431305509.5403.15386021337517970667@lazor/
There's nothing for you to do right now.
> +
> + val = val >> clkm->shift & clkm->mask;
I know there's the order of operations, however for clarity I would just
include some () here to make it clear the expected order.
> +
> + if (val >= num_parents)
Remove newline before if.
> + return 0;
> +
> + return val;
Or you could just use a ternary operator:
return val >= num_parents ? 0 : val;
> +}
> +
> +static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index)
> +{
> + struct clk_regmap_mux *clkm = to_clk_regmap_mux(hw);
> +
> + return regmap_update_bits(clkm->clkr.regmap, clkm->mux_ofs,
> + clkm->mask << clkm->shift, index << clkm->shift);
> +}
> +
> +const struct clk_ops rtk_clk_regmap_mux_ops = {
> + .set_parent = clk_regmap_mux_set_parent,
> + .get_parent = clk_regmap_mux_get_parent,
> + .determine_rate = __clk_mux_determine_rate,
> +};
> +EXPORT_SYMBOL_NS_GPL(rtk_clk_regmap_mux_ops, "REALTEK_CLK");
> +
> +const struct clk_ops rtk_clk_regmap_mux_ro_ops = {
> + .get_parent = clk_regmap_mux_get_parent,
> +};
> +EXPORT_SYMBOL_NS_GPL(rtk_clk_regmap_mux_ro_ops, "REALTEK_CLK");
rtk_clk_regmap_mux_ro_ops is exported, however the declaration is not actually
declared in any header files.
Brian
^ permalink raw reply
* Re: [PATCH v3 1/2] mailbox: Use per-thread completion to fix wrong completion order
From: Joonwon Kang @ 2026-04-03 14:51 UTC (permalink / raw)
To: jassisinghbrar
Cc: angelogioacchino.delregno, jonathanh, joonwonkang,
linux-arm-kernel, linux-kernel, linux-mediatek, linux-tegra,
matthias.bgg, stable, thierry.reding
In-Reply-To: <CABb+yY0ub51k-eFpPfgARXtwYjWzRSjbPDLtoMD77YQR8JH+=Q@mail.gmail.com>
> On Thu, Apr 2, 2026 at 12:07 PM Joonwon Kang <joonwonkang@google.com> wrote:
> >
> > Previously, a sender thread in mbox_send_message() could be woken up at
> > a wrong time in blocking mode. It is because there was only a single
> > completion for a channel whereas messages from multiple threads could be
> > sent in any order; since the shared completion could be signalled in any
> > order, it could wake up a wrong sender thread.
> >
> > This commit resolves the false wake-up issue with the following changes:
> > - Completions are created just as many as the number of concurrent sender
> > threads
> > - A completion is created on a sender thread's stack
> > - Each slot of the message queue, i.e. `msg_data`, contains a pointer to
> > its target completion
> > - tx_tick() signals the completion of the currently active slot of the
> > message queue
> >
> I think I reviewed it already or is this happening on
> one-channel-one-client usage? Because mailbox api does not support
> channels shared among multiple clients.
Yes, this patch is handling the one-channel-one-client usage but when that
single channel is shared between multiple threads. From my understanding, the
discussion back then ended with how to circumvent the issue rather than whether
we will eventually solve this in the mailbox framework or not, and if yes, how
we will, and if not, why. I think it should still be resolved in the framework
for the reasons in the cover letter. Could you help to give a second review
with regards to those aspects?
Thanks,
Joonwon Kang
^ permalink raw reply
* Re: [PATCH v6 04/10] clk: realtek: Add support for phase locked loops (PLLs)
From: Brian Masney @ 2026-04-03 14:44 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-5-eleanor.lin@realtek.com>
Hi Cheng-Yu and Yu-Chun,
On Thu, Apr 02, 2026 at 03:39:51PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Provide a full set of PLL operations for programmable PLLs and a read-only
> variant for fixed or hardware-managed PLLs.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> + const struct freq_table *fv;
> + int ret;
> +
> + fv = ftbl_find_by_rate(clkp->freq_tbl, rate);
> + if (!fv || fv->rate != rate)
> + return -EINVAL;
> +
> + if (clkp->seq_pre_set_freq) {
> + ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_pre_set_freq,
> + clkp->num_seq_pre_set_freq);
> + if (ret)
> + return ret;
> + }
> +
> + ret = regmap_update_bits(clkp->clkr.regmap, clkp->freq_reg,
> + clkp->freq_mask, fv->val);
> + if (ret)
> + return ret;
> +
> + if (clkp->seq_post_set_freq) {
> + ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_post_set_freq,
> + clkp->num_seq_post_set_freq);
> + if (ret)
> + return ret;
> + }
> +
> + if (is_power_on(clkp)) {
> + ret = wait_freq_ready(clkp);
I should have checked Sashiko before I hit send on my last review.
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
It suggested the following:
In the Common Clock Framework, .set_rate executes under the prepare_lock
mutex, while .enable and .disable execute under the enable_lock spinlock.
Could an interleaved clk_pll_enable() corrupt the hardware state by running
its seq_power_on sequence concurrently with these multi-step register
updates?
There also appears to be a potential race condition later in this function:
if (is_power_on(clkp)) {
ret = wait_freq_ready(clkp);
...
}
If .disable() powers off the PLL right before wait_freq_ready() is called,
will wait_freq_ready() poll a disabled PLL and erroneously return
-ETIMEDOUT? Is a private spinlock needed to serialize these operations?
Brian
^ permalink raw reply
* Re: [PATCH] arm64: dts: ti: k3-j721e-main: Update delay select values for MMC1/2 subsystems
From: Romain Naour @ 2026-04-03 14:42 UTC (permalink / raw)
To: Moteen Shah, devicetree, linux-arm-kernel, linux-omap
Cc: conor+dt, krzk+dt, robh, kristo, vigneshr, nm, stable
In-Reply-To: <8d4a2839-5b1e-479e-a462-dbbc3d016020@ti.com>
Hello Moteen, All,
Le 31/03/2026 à 14:19, Moteen Shah a écrit :
> Hey Romain,
>
> Thanks for the patch
>
> On 19/02/26 02:08, Romain Naour wrote:
>> The previous SPRSP36J datasheet recommends to set ti,otap-del-sel-sd-hs
>> value to 0 for MMC1 and MMC2 interfaces. These values were updated in
>> kernel 6.5. As a result we have some occasional regression with ultra
>> high speed DDR50 SDXC cards while mounting the rootfs:
>
> This error shouldn't be limited to just DDR50, were you seeing similar behavior
> with other speed modes?
I have a followup patch to enable back the SDR104 support with j721e SoC (SR 1.1
and 2.0) and I noticed the same behavior with some "specific" SDcards.
The J721e SR 1.0 doesn't support SDR104 due to an errata.
Nowadays, even the TI J721e EVM board revA (reference board) uses a SR1.1 SoC.
See the post on TI forum with further analysis:
https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1626659/dra829j-q1-mmcsd-ultra-high-speed-uhs-modes-issues
It turnout that the kernel is not able to detect UHS speed with some SDcards
vendors after uboot initialized them with UHS speed (SDR104). I'm not sure why.
Still, the datasheet was updated with a new set of timing values for HS and
legacy speed.
Maybe I should remove the part about SD card initialization issues, it may be
related to another issue.
>>
>> mmc1: error -110 whilst initialising SD card
>>
>> A similar issue may occur with u-boot after a reboot while
>> initialising the SD card:
>>
>> mmc_init: -110, time 67
>>
>> Update the delay values for legacy and high speed modes, based on
>> the latest revised datasheet SPRSP36K released in April 2024 [1].
>>
>> (MMC1/2 - SD/SDIO Interface): Updated/Changed the
>> "OTAPDLYENA, DELAY ENABLE" and "OTAPDLYSEL, DELAY VALUE" for the
>> Default Speed and High Speed modes from "0x0" to "0x1"
>>
>> [1] Table 6-86. MMC1/2 DLL Delay Mapping for All Timing Modes, in
>> https://www.ti.com/lit/ds/symlink/tda4vm.pdf,
>> (SPRSP36K – SEPTEMBER 2021 – REVISED APRIL 2024)
>>
>> Cc: stable@vger.kernel.org # 6.5+
>> Fixes: af398252d68e ("arm64: dts: ti: k3-j721e-main: Update delay select
>> values for MMC subsystems")
>> Signed-off-by: Romain Naour <romain.naour@smile.fr>
>> ---
>> arch/arm64/boot/dts/ti/k3-j721e-main.dtsi | 8 ++++----
>> 1 file changed, 4 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/
>> ti/k3-j721e-main.dtsi
>> index d5fd30a01032..418e6010ef1f 100644
>> --- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
>> +++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
>> @@ -1643,8 +1643,8 @@ main_sdhci1: mmc@4fb0000 {
>> clocks = <&k3_clks 92 5>, <&k3_clks 92 0>;
>> assigned-clocks = <&k3_clks 92 0>;
>> assigned-clock-parents = <&k3_clks 92 1>;
>> - ti,otap-del-sel-legacy = <0x0>;
>> - ti,otap-del-sel-sd-hs = <0x0>;
>> + ti,otap-del-sel-legacy = <0x1>;
>> + ti,otap-del-sel-sd-hs = <0x1>;
>> ti,otap-del-sel-sdr12 = <0xf>;
>> ti,otap-del-sel-sdr25 = <0xf>;
>> ti,otap-del-sel-sdr50 = <0xc>;
>> @@ -1671,8 +1671,8 @@ main_sdhci2: mmc@4f98000 {
>> clocks = <&k3_clks 93 5>, <&k3_clks 93 0>;
>> assigned-clocks = <&k3_clks 93 0>;
>> assigned-clock-parents = <&k3_clks 93 1>;
>> - ti,otap-del-sel-legacy = <0x0>;
>> - ti,otap-del-sel-sd-hs = <0x0>;
>> + ti,otap-del-sel-legacy = <0x1>;
>> + ti,otap-del-sel-sd-hs = <0x1>;
>> ti,otap-del-sel-sdr12 = <0xf>;
>> ti,otap-del-sel-sdr25 = <0xf>;
>> ti,otap-del-sel-sdr50 = <0xc>;
>
>
> Reviewed-by: Moteen Shah <m-shah@ti.com>
Thanks!
Best regards,
Romain
>
> Regards,
> Moteen
>
^ permalink raw reply
* Re: [PATCH] Subject: ASoC stm32_sai: fix incorrect BCLK polarity for DSP_A/B, LEFT_J
From: Mark Brown @ 2026-04-03 14:41 UTC (permalink / raw)
To: Tomasz Merta
Cc: alsa-devel@alsa-project.org, olivier.moysan@foss.st.com,
arnaud.pouliquen@foss.st.com, lgirdwood@gmail.com, perex@perex.cz,
tiwai@suse.com, mcoquelin.stm32@gmail.com,
alexandre.torgue@foss.st.com,
linux-stm32@st-md-mailman.stormreply.com,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <SA1PR04MB8467CE79DCA58DF65FD9A798935EA@SA1PR04MB8467.namprd04.prod.outlook.com>
[-- Attachment #1: Type: text/plain, Size: 989 bytes --]
On Fri, Apr 03, 2026 at 02:07:52PM +0000, Tomasz Merta wrote:
> From 553c09cfa84fa801fbd8dcd5c9ae96e94a54ee31 Mon Sep 17 00:00:00 2001
>
> Tomasz Merta
> Software Engineer
> E: Tomasz.Merta@arrow.com
> Arrow Electronics | arrow.com
> From: Tomasz Merta <tomasz.merta@arrow.com>
> Date: Fri, 3 Apr 2026 10:33:11 +0200
> Subject: [PATCH] Subject: ASoC stm32_sai: fix incorrect BCLK polarity for
> DSP_A/B, LEFT_J
>
> The STM32 SAI driver do not set the clock strobing bit (CKSTR) for DSP_A,
> DSP_B and LEFT_J formats, causing data to be sampled on the wrong BCLK
> edge when SND_SOC_DAIFMT_NB_NF is used.
Your mail is pretty mangled here, there's a HTML part and the patch
appears to be appended after a signature, it looks like all the tabs got
converted into spaces too. If you're having trouble sending b4's web
submission API:
https://b4.docs.kernel.org/en/latest/contributor/send.html
bypasses your mail infrastructure which tends to make life easier.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH 1/1] dt-bindings: timer: fsl,imxgpt: add compatible string fsl,imx25-epit
From: Daniel Lezcano @ 2026-04-03 14:40 UTC (permalink / raw)
To: Mark Brown
Cc: Frank Li, Daniel Lezcano, Thomas Gleixner, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:CLOCKSOURCE, CLOCKEVENT DRIVERS,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
Stephen Rothwell
In-Reply-To: <3ba9e33e-8d58-469c-9c21-5861c0f6c5eb@sirena.org.uk>
On 4/3/26 13:43, Mark Brown wrote:
> On Fri, Apr 03, 2026 at 10:15:49AM +0200, Daniel Lezcano wrote:
>> On 4/3/26 10:00, Frank Li wrote:
>
>>> Can't find it at linux-next master branch, anything wrong!
>
>> The patch is in timer/next but may be linux-next disabled my branch
>
> I have a timers/drivers/next branch in your git tree in -next but
> no record of anything else. That branch was last updated on January
> 20th. If you want something else adding let me know.
No it is ok, I had a confusion in my branches. I updated the wrong one.
Now it is fixed.
Thanks
^ permalink raw reply
* Re: [PATCH v6 05/10] clk: realtek: Add support for gate clock
From: Brian Masney @ 2026-04-03 14:40 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-6-eleanor.lin@realtek.com>
Hi Cheng-Yu,
On Thu, Apr 02, 2026 at 03:39:52PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Introduce clk_regmap_gate_ops supporting enable, disable, is_enabled, and
> disable_unused for standard regmap gate clocks.
disable_unused is not implemented below.
>
> Add clk_regmap_gate_ro_ops as a read-only variant exposing only is_enabled.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> ---
> drivers/clk/realtek/Makefile | 2 +
> drivers/clk/realtek/clk-regmap-gate.c | 69 +++++++++++++++++++++++++++
> drivers/clk/realtek/clk-regmap-gate.h | 65 +++++++++++++++++++++++++
> 3 files changed, 136 insertions(+)
> create mode 100644 drivers/clk/realtek/clk-regmap-gate.c
> create mode 100644 drivers/clk/realtek/clk-regmap-gate.h
>
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index a89ad77993e9..74375f8127ac 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -2,5 +2,7 @@
> obj-$(CONFIG_RTK_CLK_COMMON) += clk-rtk.o
>
> clk-rtk-y += common.o
> +
> clk-rtk-y += clk-pll.o
> +clk-rtk-y += clk-regmap-gate.o
> clk-rtk-y += freq_table.o
> diff --git a/drivers/clk/realtek/clk-regmap-gate.c b/drivers/clk/realtek/clk-regmap-gate.c
> new file mode 100644
> index 000000000000..8738d6c6f8dd
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-regmap-gate.c
> @@ -0,0 +1,69 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <linux/regmap.h>
> +#include <linux/bits.h>
> +#include "clk-regmap-gate.h"
> +#include <linux/clk-provider.h>
linux/clk-provider.h needs to be included before clk-regmap-gate.h.
Also Sashiko reports that linux/export.h should also be included.
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Brian
^ permalink raw reply
* Re: [PATCH v6 04/10] clk: realtek: Add support for phase locked loops (PLLs)
From: Brian Masney @ 2026-04-03 14:34 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-5-eleanor.lin@realtek.com>
Hi Cheng-Yu,
On Thu, Apr 02, 2026 at 03:39:51PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Provide a full set of PLL operations for programmable PLLs and a read-only
> variant for fixed or hardware-managed PLLs.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> - Move to_clk_pll() from clk-pll.h to clk-pll.c to limit its scope.
> ---
> drivers/clk/realtek/Makefile | 2 +
> drivers/clk/realtek/clk-pll.c | 164 +++++++++++++++++++++++++++++++
> drivers/clk/realtek/clk-pll.h | 42 ++++++++
> drivers/clk/realtek/freq_table.c | 36 +++++++
> drivers/clk/realtek/freq_table.h | 21 ++++
> 5 files changed, 265 insertions(+)
> create mode 100644 drivers/clk/realtek/clk-pll.c
> create mode 100644 drivers/clk/realtek/clk-pll.h
> create mode 100644 drivers/clk/realtek/freq_table.c
> create mode 100644 drivers/clk/realtek/freq_table.h
>
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index 377ec776ee47..a89ad77993e9 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -2,3 +2,5 @@
> obj-$(CONFIG_RTK_CLK_COMMON) += clk-rtk.o
>
> clk-rtk-y += common.o
> +clk-rtk-y += clk-pll.o
> +clk-rtk-y += freq_table.o
> diff --git a/drivers/clk/realtek/clk-pll.c b/drivers/clk/realtek/clk-pll.c
> new file mode 100644
> index 000000000000..44730b22a94c
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-pll.c
> @@ -0,0 +1,164 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2024 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <linux/regmap.h>
> +#include "clk-pll.h"
> +
> +#define TIMEOUT 2000
> +
> +static inline struct clk_pll *to_clk_pll(struct clk_hw *hw)
> +{
> + struct clk_regmap *clkr = to_clk_regmap(hw);
> +
> + return container_of(clkr, struct clk_pll, clkr);
> +}
> +
> +static int wait_freq_ready(struct clk_pll *clkp)
> +{
> + u32 pollval;
> +
> + if (!clkp->freq_ready_valid)
> + return 0;
> +
> + return regmap_read_poll_timeout_atomic(clkp->clkr.regmap, clkp->freq_ready_reg, pollval,
> + (pollval & clkp->freq_ready_mask)
> + == clkp->freq_ready_val, 0, TIMEOUT);
I would put the "(pollval & clkp->freq_ready_mask) == clkp->freq_ready_val" on
the same line to improve readability. You can go out to 100 characters.
Also should the delay be greater than 0 to avoid tons of constant
retries?
> +}
> +
> +static bool is_power_on(struct clk_pll *clkp)
> +{
> + u32 val;
> +
> + if (!clkp->power_reg)
> + return true;
> +
> + if (regmap_read(clkp->clkr.regmap, clkp->power_reg, &val))
> + return true;
Is the intention if there is an error, then it marks it as success?
> +
> + return (val & clkp->power_mask) == clkp->power_val_on;
> +}
> +
> +static void clk_pll_disable(struct clk_hw *hw)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> +
> + if (!clkp->seq_power_off)
> + return;
> +
> + regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_power_off,
> + clkp->num_seq_power_off);
> +}
> +
> +static int clk_pll_is_enabled(struct clk_hw *hw)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> +
> + return is_power_on(clkp);
> +}
> +
> +static int clk_pll_determine_rate(struct clk_hw *hw,
> + struct clk_rate_request *req)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> + const struct freq_table *ftblv = NULL;
> +
> + ftblv = ftbl_find_by_rate(clkp->freq_tbl, req->rate);
> + if (!ftblv)
> + return -EINVAL;
> +
> + req->rate = ftblv->rate;
> + return 0;
Add newline before return.
> +}
> +
> +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> + const struct freq_table *fv;
> + u32 freq_val;
> +
> + if (regmap_read(clkp->clkr.regmap, clkp->freq_reg, &freq_val))
> + return 0;
> +
> + freq_val &= clkp->freq_mask;
> +
> + fv = ftbl_find_by_val_with_mask(clkp->freq_tbl, clkp->freq_mask,
> + freq_val);
> + return fv ? fv->rate : 0;
Add newline before return.
> +}
> +
> +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> + const struct freq_table *fv;
> + int ret;
> +
> + fv = ftbl_find_by_rate(clkp->freq_tbl, rate);
> + if (!fv || fv->rate != rate)
> + return -EINVAL;
> +
> + if (clkp->seq_pre_set_freq) {
> + ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_pre_set_freq,
> + clkp->num_seq_pre_set_freq);
> + if (ret)
> + return ret;
> + }
> +
> + ret = regmap_update_bits(clkp->clkr.regmap, clkp->freq_reg,
> + clkp->freq_mask, fv->val);
> + if (ret)
> + return ret;
> +
> + if (clkp->seq_post_set_freq) {
> + ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_post_set_freq,
> + clkp->num_seq_post_set_freq);
> + if (ret)
> + return ret;
> + }
> +
> + if (is_power_on(clkp)) {
> + ret = wait_freq_ready(clkp);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int clk_pll_enable(struct clk_hw *hw)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> + int ret;
> +
> + if (!clkp->seq_power_on)
> + return 0;
> +
> + if (is_power_on(clkp))
> + return 0;
> +
> + ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_power_on,
> + clkp->num_seq_power_on);
> + if (ret)
> + return ret;
> +
> + return wait_freq_ready(clkp);
> +}
> +
> +const struct clk_ops rtk_clk_pll_ops = {
> + .enable = clk_pll_enable,
> + .disable = clk_pll_disable,
> + .is_enabled = clk_pll_is_enabled,
> + .recalc_rate = clk_pll_recalc_rate,
> + .determine_rate = clk_pll_determine_rate,
> + .set_rate = clk_pll_set_rate,
> +};
> +EXPORT_SYMBOL_NS_GPL(rtk_clk_pll_ops, "REALTEK_CLK");
> +
> +const struct clk_ops rtk_clk_pll_ro_ops = {
> + .recalc_rate = clk_pll_recalc_rate,
> +};
> +EXPORT_SYMBOL_NS_GPL(rtk_clk_pll_ro_ops, "REALTEK_CLK");
> diff --git a/drivers/clk/realtek/clk-pll.h b/drivers/clk/realtek/clk-pll.h
> new file mode 100644
> index 000000000000..00884585a242
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-pll.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2017-2019 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#ifndef __CLK_REALTEK_CLK_PLL_H
> +#define __CLK_REALTEK_CLK_PLL_H
> +
> +#include "common.h"
> +#include "freq_table.h"
> +
> +struct reg_sequence;
> +
> +struct clk_pll {
> + struct clk_regmap clkr;
> + const struct reg_sequence *seq_power_on;
> + u32 num_seq_power_on;
> + const struct reg_sequence *seq_power_off;
> + u32 num_seq_power_off;
> + const struct reg_sequence *seq_pre_set_freq;
> + u32 num_seq_pre_set_freq;
> + const struct reg_sequence *seq_post_set_freq;
> + u32 num_seq_post_set_freq;
> + const struct freq_table *freq_tbl;
> + u32 freq_reg;
> + u32 freq_mask;
> + u32 freq_ready_valid;
> + u32 freq_ready_mask;
> + u32 freq_ready_reg;
> + u32 freq_ready_val;
> + u32 power_reg;
> + u32 power_mask;
> + u32 power_val_on;
> +};
> +
> +#define __clk_pll_hw(_ptr) __clk_regmap_hw(&(_ptr)->clkr)
> +
> +extern const struct clk_ops rtk_clk_pll_ops;
> +extern const struct clk_ops rtk_clk_pll_ro_ops;
> +
> +#endif /* __CLK_REALTEK_CLK_PLL_H */
> diff --git a/drivers/clk/realtek/freq_table.c b/drivers/clk/realtek/freq_table.c
> new file mode 100644
> index 000000000000..272a10e75a54
> --- /dev/null
> +++ b/drivers/clk/realtek/freq_table.c
> @@ -0,0 +1,36 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <linux/bitops.h>
> +#include "freq_table.h"
> +
> +const struct freq_table *ftbl_find_by_rate(const struct freq_table *ftbl,
> + unsigned long rate)
> +{
> + unsigned long best_rate = 0;
> + const struct freq_table *best = NULL;
Put variables in reverse Christmas tree order.
> +
> + for (; !IS_FREQ_TABLE_END(ftbl); ftbl++) {
> + if (ftbl->rate == rate)
> + return ftbl;
> +
> + if (ftbl->rate > rate)
> + continue;
> +
> + if (ftbl->rate > best_rate) {
> + best_rate = ftbl->rate;
> + best = ftbl;
> + }
> + }
> +
> + return best;
> +}
> +
> +const struct freq_table *
> +ftbl_find_by_val_with_mask(const struct freq_table *ftbl, u32 mask, u32 value)
> +{
> + for (; !IS_FREQ_TABLE_END(ftbl); ftbl++) {
> + if ((ftbl->val & mask) == (value & mask))
> + return ftbl;
> + }
> + return NULL;
> +};
> diff --git a/drivers/clk/realtek/freq_table.h b/drivers/clk/realtek/freq_table.h
> new file mode 100644
> index 000000000000..6d9116651105
> --- /dev/null
> +++ b/drivers/clk/realtek/freq_table.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +struct freq_table {
> + u32 val;
> + unsigned long rate;
> +};
> +
> +/* ofs check */
> +#define CLK_OFS_INVALID -1
> +#define CLK_OFS_IS_VALID(_ofs) ((_ofs) != CLK_OFS_INVALID)
Is this used anywhere?
Brian
> +
> +#define FREQ_TABLE_END \
> + { \
> + .rate = 0 \
> + }
> +#define IS_FREQ_TABLE_END(_f) ((_f)->rate == 0)
> +
> +const struct freq_table *ftbl_find_by_rate(const struct freq_table *ftbl,
> + unsigned long rate);
> +const struct freq_table *
> +ftbl_find_by_val_with_mask(const struct freq_table *ftbl, u32 mask, u32 value);
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH] ARM: mvebu: validate memory node device_type strings
From: Andrew Lunn @ 2026-04-03 14:31 UTC (permalink / raw)
To: Pengpeng Hou
Cc: Gregory Clement, Sebastian Hesselbarth, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260403151504.4-dt-arm-mvebu-resend-pengpeng@iscas.ac.cn>
On Fri, Apr 03, 2026 at 10:42:46AM +0800, Pengpeng Hou wrote:
> mvebu_scan_mem() fetches the raw device_type property and immediately
> compares it with strcmp(). Flat DT properties are external boot input,
> and this path does not prove that the property is NUL-terminated within
> its declared bounds.
>
> Use fdt_stringlist_get() so malformed unterminated device_type
> properties are rejected before they are used as C strings.
>
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
> ---
> arch/arm/mach-mvebu/board-v7.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c
> index a0740ab0dca9..f867f6233108 100644
> --- a/arch/arm/mach-mvebu/board-v7.c
> +++ b/arch/arm/mach-mvebu/board-v7.c
> @@ -11,6 +11,7 @@
>
> #include <linux/kernel.h>
> #include <linux/init.h>
> +#include <linux/libfdt.h>
> #include <linux/of_address.h>
> #include <linux/of_fdt.h>
> #include <linux/io.h>
> @@ -66,7 +67,8 @@ void __iomem *mvebu_get_scu_base(void)
> static int __init mvebu_scan_mem(unsigned long node, const char *uname,
> int depth, void *data)
> {
> - const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
> + const char *type = fdt_stringlist_get(initial_boot_params, node,
> + "device_type", 0, NULL);
> const __be32 *reg, *endp;
> int l;
Did you read the comment?
/*
* When returning from suspend, the platform goes through the
* bootloader, which executes its DDR3 training code. This code has
* the unfortunate idea of using the first 10 KB of each DRAM bank to
* exercise the RAM and calculate the optimal timings. Therefore, this
* area of RAM is overwritten, and shouldn't be used by the kernel if
* suspend/resume is supported.
*/
You probably want to make use of:
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
* -FDT_ERR_NOTFOUND if the property does not exist
Andrew
^ permalink raw reply
* Re: [PATCH bpf-next v12 2/5] bpf: Pass bpf_verifier_env to JIT
From: bot+bpf-ci @ 2026-04-03 14:30 UTC (permalink / raw)
To: xukuohai, bpf, linux-kernel, linux-arm-kernel
Cc: ast, daniel, andrii, martin.lau, eddyz87, yonghong.song, puranjay,
a.s.protopopov, alexis.lothore, list+bpf, linux, yangtiezhu,
hengqi.chen, johan.almbladh, paulburton, hbathini, chleroy,
naveen, luke.r.nels, xi.wang, bjorn, pulehui, iii, hca, gor,
davem, udknight, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260403132811.753894-3-xukuohai@huaweicloud.com>
[-- Attachment #1: Type: text/plain, Size: 2348 bytes --]
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index cc61fe57b98d..093ab0f68c81 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
[ ... ]
> @@ -2551,47 +2528,63 @@ static bool bpf_prog_select_interpreter(struct bpf_prog *fp)
> return select_interpreter;
> }
>
> -static struct bpf_prog *bpf_prog_jit_compile(struct bpf_prog *prog)
> +static struct bpf_prog *bpf_prog_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
> {
> #ifdef CONFIG_BPF_JIT
> bool blinded = false;
> struct bpf_prog *orig_prog = prog;
> + struct bpf_insn_aux_data *orig_insn_aux;
>
> if (bpf_prog_need_blind(orig_prog)) {
> + if (env) {
> + /* If env is not NULL, we are called from the end of bpf_check(), at this
> + * point, only insn_aux_data is used after failure, so we only restore it
> + * here.
> + */
> + orig_insn_aux = bpf_dup_insn_aux_data(env);
> + if (!orig_insn_aux)
> + return orig_prog;
> + }
> + prog = bpf_jit_blind_constants(env, orig_prog);
[ ... ]
> + return prog;
> +
> +out_restore:
> + bpf_restore_insn_aux_data(env, orig_insn_aux);
> +out_free:
> + kvfree(orig_insn_aux);
> #endif
> return prog;
> }
When the out_restore label is reached (blinding or JIT failure with
env != NULL), bpf_restore_insn_aux_data() sets env->insn_aux_data to
point to orig_insn_aux:
kernel/bpf/verifier.c:bpf_restore_insn_aux_data() {
vfree(env->insn_aux_data);
env->insn_aux_data = orig_insn_aux;
}
The code then falls through to the out_free label, which calls
kvfree(orig_insn_aux). This frees the memory that env->insn_aux_data
now points to, leaving it as a dangling pointer.
Since this function is called from inside bpf_check() via
__bpf_prog_select_runtime(), the subsequent cleanup in bpf_check()
accesses the freed memory:
kernel/bpf/verifier.c:bpf_check() {
...
clear_insn_aux_data(env, 0, env->prog->len);
vfree(env->insn_aux_data);
}
Could the out_restore path return directly instead of falling through
to out_free, since after the restore env now owns orig_insn_aux and
bpf_check() will free it during normal cleanup?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/23948799625
^ permalink raw reply
* Re: [PATCH bpf-next v12 1/5] bpf: Move constants blinding out of arch-specific JITs
From: bot+bpf-ci @ 2026-04-03 14:30 UTC (permalink / raw)
To: xukuohai, bpf, linux-kernel, linux-arm-kernel
Cc: ast, daniel, andrii, martin.lau, eddyz87, yonghong.song, puranjay,
a.s.protopopov, alexis.lothore, list+bpf, linux, yangtiezhu,
hengqi.chen, johan.almbladh, paulburton, hbathini, chleroy,
naveen, luke.r.nels, xi.wang, bjorn, pulehui, iii, hca, gor,
davem, udknight, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260403132811.753894-2-xukuohai@huaweicloud.com>
[-- Attachment #1: Type: text/plain, Size: 1947 bytes --]
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index a431b7d50e1b..66cef3744fde 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
[ ... ]
> +static void restore_insn_aux_data(struct bpf_verifier_env *env,
> + struct bpf_insn_aux_data *orig_insn_aux)
> +{
> + /* the expanded elements are zero-filled, so no special handling is required */
> + vfree(env->insn_aux_data);
> + env->insn_aux_data = orig_insn_aux;
> +}
[ ... ]
> +out_restore:
> + restore_subprog_starts(env, orig_subprog_starts);
> + restore_insn_aux_data(env, orig_insn_aux);
> + kvfree(orig_subprog_starts);
> +out_free_aux:
> + kvfree(orig_insn_aux);
> +out_cleanup:
> + /* cleanup main prog to be interpreted */
> + prog->jit_requested = 0;
> + prog->blinding_requested = 0;
> + return err;
Is there a double-free of env->insn_aux_data on the out_restore path?
restore_insn_aux_data() sets env->insn_aux_data = orig_insn_aux, then
out_restore falls through to out_free_aux which does
kvfree(orig_insn_aux), freeing the just-restored pointer.
Later, bpf_check() cleanup runs:
clear_insn_aux_data(env, 0, env->prog->len);
vfree(env->insn_aux_data);
which would be a use-after-free followed by a double-free.
The out_restore path is reached when bpf_jit_blind_constants() or
__jit_subprogs() fails while blinding was active, which can happen
under memory pressure with multi-subprog BPF programs.
It looks like out_restore needs a goto out_cleanup (or similar) after
kvfree(orig_subprog_starts) to skip the out_free_aux label, since after
restoring, orig_insn_aux is owned by env->insn_aux_data and must not be
freed here.
This regression is not fixed by later commits in the series.
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/23948799625
^ permalink raw reply
* [PATCH 3/3] arm64: dts: broadcom: rp1: Add PWM node
From: Andrea della Porta @ 2026-04-03 14:31 UTC (permalink / raw)
To: Uwe Kleine-König, linux-pwm, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Broadcom internal kernel review list, Andrea della Porta,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov
In-Reply-To: <cover.1775223441.git.andrea.porta@suse.com>
From: Stanimir Varbanov <svarbanov@suse.de>
The RP1 chipset used on the Raspberry Pi 5 features an integrated
PWM controller to drive the cooling fan.
Add the corresponding DT node for this PWM controller.
Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
Co-developed-by: Andrea della Porta <andrea.porta@suse.com>
Signed-off-by: Andrea della Porta <andrea.porta@suse.com>
---
arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 12 ++++++++++++
arch/arm64/boot/dts/broadcom/rp1-common.dtsi | 10 ++++++++++
2 files changed, 22 insertions(+)
diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
index 2856082814462..a4e5ba23bf536 100644
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
@@ -64,12 +64,24 @@ phy1: ethernet-phy@1 {
};
&rp1_gpio {
+ fan_pwm_default_state: fan-pwm-default-state {
+ function = "pwm1";
+ pins = "gpio45";
+ bias-pull-down;
+ };
+
usb_vbus_default_state: usb-vbus-default-state {
function = "vbus1";
groups = "vbus1";
};
};
+&rp1_pwm {
+ pinctrl-0 = <&fan_pwm_default_state>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
&rp1_usb0 {
pinctrl-0 = <&usb_vbus_default_state>;
pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/broadcom/rp1-common.dtsi b/arch/arm64/boot/dts/broadcom/rp1-common.dtsi
index 5a815c3797945..7e78501e62b0c 100644
--- a/arch/arm64/boot/dts/broadcom/rp1-common.dtsi
+++ b/arch/arm64/boot/dts/broadcom/rp1-common.dtsi
@@ -56,6 +56,16 @@ rp1_eth: ethernet@40100000 {
#size-cells = <0>;
};
+ rp1_pwm: pwm@4009c000 {
+ compatible = "raspberrypi,rp1-pwm";
+ reg = <0x00 0x4009c000 0x0 0x100>;
+ clocks = <&rp1_clocks RP1_CLK_PWM1>;
+ assigned-clocks = <&rp1_clocks RP1_CLK_PWM1>;
+ assigned-clock-rates = <50000000>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
rp1_usb0: usb@40200000 {
compatible = "snps,dwc3";
reg = <0x00 0x40200000 0x0 0x100000>;
--
2.35.3
^ permalink raw reply related
* [PATCH 2/3] pwm: rp1: Add RP1 PWM controller driver
From: Andrea della Porta @ 2026-04-03 14:31 UTC (permalink / raw)
To: Uwe Kleine-König, linux-pwm, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Broadcom internal kernel review list, Andrea della Porta,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov
In-Reply-To: <cover.1775223441.git.andrea.porta@suse.com>
From: Naushir Patuck <naush@raspberrypi.com>
The Raspberry Pi RP1 southbridge features an embedded PWM
controller with 4 output channels, alongside an RPM interface
to read the fan speed on the Raspberry Pi 5.
Add the supporting driver.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Co-developed-by: Stanimir Varbanov <svarbanov@suse.de>
Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
Signed-off-by: Andrea della Porta <andrea.porta@suse.com>
---
drivers/pwm/Kconfig | 10 ++
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-rp1.c | 244 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 255 insertions(+)
create mode 100644 drivers/pwm/pwm-rp1.c
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 6f3147518376a..22e4fc6385da2 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -625,6 +625,16 @@ config PWM_ROCKCHIP
Generic PWM framework driver for the PWM controller found on
Rockchip SoCs.
+config PWM_RP1
+ tristate "RP1 PWM support"
+ depends on MISC_RP1 || COMPILE_TEST
+ depends on HWMON
+ help
+ PWM framework driver for Raspberry Pi RP1 controller
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-rp1.
+
config PWM_SAMSUNG
tristate "Samsung PWM support"
depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 0dc0d2b69025d..895a7c42fe9c0 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_PWM_RENESAS_RZG2L_GPT) += pwm-rzg2l-gpt.o
obj-$(CONFIG_PWM_RENESAS_RZ_MTU3) += pwm-rz-mtu3.o
obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
+obj-$(CONFIG_PWM_RP1) += pwm-rp1.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o
diff --git a/drivers/pwm/pwm-rp1.c b/drivers/pwm/pwm-rp1.c
new file mode 100644
index 0000000000000..0a1c1c1dd27e9
--- /dev/null
+++ b/drivers/pwm/pwm-rp1.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * pwm-rp1.c
+ *
+ * Raspberry Pi RP1 PWM.
+ *
+ * Copyright © 2026 Raspberry Pi Ltd.
+ *
+ * Author: Naushir Patuck (naush@raspberrypi.com)
+ *
+ * Based on the pwm-bcm2835 driver by:
+ * Bart Tanghe <bart.tanghe@thomasmore.be>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+#define PWM_GLOBAL_CTRL 0x000
+#define PWM_CHANNEL_CTRL(x) (0x014 + ((x) * 0x10))
+#define PWM_RANGE(x) (0x018 + ((x) * 0x10))
+#define PWM_PHASE(x) (0x01C + ((x) * 0x10))
+#define PWM_DUTY(x) (0x020 + ((x) * 0x10))
+
+/* 8:FIFO_POP_MASK + 0:Trailing edge M/S modulation */
+#define PWM_CHANNEL_DEFAULT (BIT(8) + BIT(0))
+#define PWM_CHANNEL_ENABLE(x) BIT(x)
+#define PWM_POLARITY BIT(3)
+#define SET_UPDATE BIT(31)
+#define PWM_MODE_MASK GENMASK(1, 0)
+
+#define NUM_PWMS 4
+
+struct rp1_pwm {
+ void __iomem *base;
+ struct clk *clk;
+};
+
+static const struct hwmon_channel_info * const rp1_fan_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
+ NULL
+};
+
+static umode_t rp1_fan_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ umode_t mode = 0;
+
+ if (type == hwmon_fan && attr == hwmon_fan_input)
+ mode = 0444;
+
+ return mode;
+}
+
+static int rp1_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct rp1_pwm *rp1 = dev_get_drvdata(dev);
+
+ if (type != hwmon_fan || attr != hwmon_fan_input)
+ return -EOPNOTSUPP;
+
+ *val = readl(rp1->base + PWM_PHASE(2));
+
+ return 0;
+}
+
+static const struct hwmon_ops rp1_fan_hwmon_ops = {
+ .is_visible = rp1_fan_hwmon_is_visible,
+ .read = rp1_fan_hwmon_read,
+};
+
+static const struct hwmon_chip_info rp1_fan_hwmon_chip_info = {
+ .ops = &rp1_fan_hwmon_ops,
+ .info = rp1_fan_hwmon_info,
+};
+
+static void rp1_pwm_apply_config(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+ u32 value;
+
+ value = readl(rp1->base + PWM_GLOBAL_CTRL);
+ value |= SET_UPDATE;
+ writel(value, rp1->base + PWM_GLOBAL_CTRL);
+}
+
+static int rp1_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+
+ writel(PWM_CHANNEL_DEFAULT, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
+ return 0;
+}
+
+static void rp1_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+ u32 value;
+
+ value = readl(rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
+ value &= ~PWM_MODE_MASK;
+ writel(value, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
+
+ rp1_pwm_apply_config(chip, pwm);
+}
+
+static int rp1_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+ unsigned long clk_rate = clk_get_rate(rp1->clk);
+ unsigned long clk_period;
+ u32 value;
+
+ if (!clk_rate) {
+ dev_err(&chip->dev, "failed to get clock rate\n");
+ return -EINVAL;
+ }
+
+ /* set period and duty cycle */
+ clk_period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, clk_rate);
+
+ writel(DIV_ROUND_CLOSEST(state->duty_cycle, clk_period),
+ rp1->base + PWM_DUTY(pwm->hwpwm));
+
+ writel(DIV_ROUND_CLOSEST(state->period, clk_period),
+ rp1->base + PWM_RANGE(pwm->hwpwm));
+
+ /* set polarity */
+ value = readl(rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
+ if (state->polarity == PWM_POLARITY_NORMAL)
+ value &= ~PWM_POLARITY;
+ else
+ value |= PWM_POLARITY;
+ writel(value, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
+
+ /* enable/disable */
+ value = readl(rp1->base + PWM_GLOBAL_CTRL);
+ if (state->enabled)
+ value |= PWM_CHANNEL_ENABLE(pwm->hwpwm);
+ else
+ value &= ~PWM_CHANNEL_ENABLE(pwm->hwpwm);
+ writel(value, rp1->base + PWM_GLOBAL_CTRL);
+
+ rp1_pwm_apply_config(chip, pwm);
+
+ return 0;
+}
+
+static const struct pwm_ops rp1_pwm_ops = {
+ .request = rp1_pwm_request,
+ .free = rp1_pwm_free,
+ .apply = rp1_pwm_apply,
+};
+
+static int rp1_pwm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device *hwmon_dev;
+ struct pwm_chip *chip;
+ struct rp1_pwm *rp1;
+ int ret;
+
+ chip = devm_pwmchip_alloc(dev, NUM_PWMS, sizeof(*rp1));
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ rp1 = pwmchip_get_drvdata(chip);
+
+ rp1->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(rp1->base))
+ return PTR_ERR(rp1->base);
+
+ rp1->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(rp1->clk))
+ return dev_err_probe(dev, PTR_ERR(rp1->clk), "clock not found\n");
+
+ ret = devm_clk_rate_exclusive_get(dev, rp1->clk);
+ if (ret)
+ return dev_err_probe(dev, ret, "fail to get exclusive rate\n");
+
+ chip->ops = &rp1_pwm_ops;
+
+ platform_set_drvdata(pdev, chip);
+
+ ret = devm_pwmchip_add(dev, chip);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register PWM chip\n");
+
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, "rp1_fan_tach", rp1,
+ &rp1_fan_hwmon_chip_info,
+ NULL);
+
+ if (IS_ERR(hwmon_dev))
+ return dev_err_probe(dev, PTR_ERR(hwmon_dev),
+ "failed to register hwmon fan device\n");
+
+ return 0;
+}
+
+static int rp1_pwm_suspend(struct device *dev)
+{
+ struct rp1_pwm *rp1 = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(rp1->clk);
+
+ return 0;
+}
+
+static int rp1_pwm_resume(struct device *dev)
+{
+ struct rp1_pwm *rp1 = dev_get_drvdata(dev);
+
+ return clk_prepare_enable(rp1->clk);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(rp1_pwm_pm_ops, rp1_pwm_suspend, rp1_pwm_resume);
+
+static const struct of_device_id rp1_pwm_of_match[] = {
+ { .compatible = "raspberrypi,rp1-pwm" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rp1_pwm_of_match);
+
+static struct platform_driver rp1_pwm_driver = {
+ .probe = rp1_pwm_probe,
+ .driver = {
+ .name = "rp1-pwm",
+ .of_match_table = rp1_pwm_of_match,
+ .pm = pm_ptr(&rp1_pwm_pm_ops),
+ },
+};
+module_platform_driver(rp1_pwm_driver);
+
+MODULE_DESCRIPTION("RP1 PWM driver");
+MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>");
+MODULE_LICENSE("GPL");
--
2.35.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox