* [PATCH v3 5/8] thermal: khadas-mcu-fan: Add fan config from platform data Add regulator support
From: Ronald Claveau @ 2026-04-17 16:27 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: <20260417-add-mcu-fan-khadas-vim4-v3-0-a6a7f570b11b@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 v3 6/8] arm64: dts: amlogic: t7: Add i2c pinctrl node
From: Ronald Claveau @ 2026-04-17 16:27 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: <20260417-add-mcu-fan-khadas-vim4-v3-0-a6a7f570b11b@aliel.fr>
Add the T7 pinctrl used by the Khadas VIM4 for MCU communication.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index 7fe72c94ed623..e96fe10b251a0 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -376,6 +376,16 @@ mux {
};
};
+ i2c0_ao_d_pins: i2c0-ao-d {
+ mux {
+ groups = "i2c0_ao_sck_d",
+ "i2c0_ao_sda_d";
+ function = "i2c0_ao";
+ bias-disable;
+ drive-strength-microamp = <3000>;
+ };
+ };
+
pwm_a_pins: pwm-a {
mux {
groups = "pwm_a";
--
2.49.0
^ permalink raw reply related
* [PATCH v3 7/8] arm64: dts: amlogic: t7: Add i2c controller node
From: Ronald Claveau @ 2026-04-17 16:27 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: <20260417-add-mcu-fan-khadas-vim4-v3-0-a6a7f570b11b@aliel.fr>
Add the T7 i2c controller node used by the Khadas VIM4
for MCU communication.
Use amlogic,meson-axg-i2c as fallback compatible.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index e96fe10b251a0..560c9dce35266 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -711,6 +711,16 @@ pwm_ao_cd: pwm@60000 {
status = "disabled";
};
+ i2c_m_ao_a: i2c@76000 {
+ compatible = "amlogic,t7-i2c", "amlogic,meson-axg-i2c";
+ reg = <0x0 0x76000 0x0 0x48>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 330 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc_periphs CLKID_SYS_I2C_AO_A>;
+ status = "disabled";
+ };
+
sd_emmc_a: mmc@88000 {
compatible = "amlogic,t7-mmc", "amlogic,meson-axg-mmc";
reg = <0x0 0x88000 0x0 0x800>;
--
2.49.0
^ permalink raw reply related
* [PATCH v3 4/8] mfd: khadas-mcu: Add support for VIM4 MCU variant
From: Ronald Claveau @ 2026-04-17 16:27 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: <20260417-add-mcu-fan-khadas-vim4-v3-0-a6a7f570b11b@aliel.fr>
Refactor probe() to use per-variant khadas_mcu_data
instead of hardcoded globals.
Add dedicated regmap configuration and device data for the VIM4 MCU,
with its own volatile/writeable registers.
Add the fan control register
(0–100 levels vs 0–3 for previous supported boards).
Add a new compatible string "khadas,vim4-mcu".
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
drivers/mfd/khadas-mcu.c | 106 ++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 95 insertions(+), 11 deletions(-)
diff --git a/drivers/mfd/khadas-mcu.c b/drivers/mfd/khadas-mcu.c
index ba981a7886921..b36b3b3ab73c0 100644
--- a/drivers/mfd/khadas-mcu.c
+++ b/drivers/mfd/khadas-mcu.c
@@ -75,15 +75,91 @@ static const struct regmap_config khadas_mcu_regmap_config = {
.cache_type = REGCACHE_MAPLE,
};
+static const struct khadas_mcu_fan_pdata khadas_mcu_fan_pdata = {
+ .fan_reg = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
+ .max_level = 3,
+};
+
static struct mfd_cell khadas_mcu_fan_cells[] = {
/* VIM1/2 Rev13+ and VIM3 only */
- { .name = "khadas-mcu-fan-ctrl", },
+ {
+ .name = "khadas-mcu-fan-ctrl",
+ .platform_data = &khadas_mcu_fan_pdata,
+ .pdata_size = sizeof(khadas_mcu_fan_pdata),
+ },
};
static struct mfd_cell khadas_mcu_cells[] = {
{ .name = "khadas-mcu-user-mem", },
};
+static const struct khadas_mcu_data khadas_mcu_data = {
+ .regmap_config = &khadas_mcu_regmap_config,
+ .cells = khadas_mcu_cells,
+ .ncells = ARRAY_SIZE(khadas_mcu_cells),
+ .fan_cells = khadas_mcu_fan_cells,
+ .nfan_cells = ARRAY_SIZE(khadas_mcu_fan_cells),
+};
+
+static bool khadas_mcu_vim4_reg_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case KHADAS_MCU_PWR_OFF_CMD_REG:
+ case KHADAS_MCU_VIM4_REST_CONF_REG:
+ case KHADAS_MCU_WOL_INIT_START_REG:
+ case KHADAS_MCU_VIM4_LED_ON_RAM_REG:
+ case KHADAS_MCU_VIM4_FAN_CTRL_REG:
+ case KHADAS_MCU_VIM4_WDT_EN_REG:
+ case KHADAS_MCU_VIM4_SYS_RST_REG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool khadas_mcu_vim4_reg_writeable(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case KHADAS_MCU_VERSION_0_REG:
+ case KHADAS_MCU_VERSION_1_REG:
+ case KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static const struct regmap_config khadas_mcu_vim4_regmap_config = {
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .max_register = KHADAS_MCU_VIM4_SYS_RST_REG,
+ .volatile_reg = khadas_mcu_vim4_reg_volatile,
+ .writeable_reg = khadas_mcu_vim4_reg_writeable,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static const struct khadas_mcu_fan_pdata khadas_vim4_fan_pdata = {
+ .fan_reg = KHADAS_MCU_VIM4_FAN_CTRL_REG,
+ .max_level = 0x64,
+};
+
+static const struct mfd_cell khadas_mcu_vim4_cells[] = {
+ {
+ .name = "khadas-mcu-fan-ctrl",
+ .platform_data = &khadas_vim4_fan_pdata,
+ .pdata_size = sizeof(khadas_vim4_fan_pdata),
+ },
+};
+
+static const struct khadas_mcu_data khadas_vim4_mcu_data = {
+ .regmap_config = &khadas_mcu_vim4_regmap_config,
+ .cells = NULL,
+ .ncells = 0,
+ .fan_cells = khadas_mcu_vim4_cells,
+ .nfan_cells = ARRAY_SIZE(khadas_mcu_vim4_cells),
+};
+
static int khadas_mcu_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -94,28 +170,35 @@ static int khadas_mcu_probe(struct i2c_client *client)
if (!ddata)
return -ENOMEM;
+ ddata->data = i2c_get_match_data(client);
+ if (!ddata->data)
+ return -EINVAL;
+
i2c_set_clientdata(client, ddata);
ddata->dev = dev;
- ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config);
+ ddata->regmap = devm_regmap_init_i2c(client,
+ ddata->data->regmap_config);
if (IS_ERR(ddata->regmap)) {
ret = PTR_ERR(ddata->regmap);
dev_err(dev, "Failed to allocate register map: %d\n", ret);
return ret;
}
- ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
- khadas_mcu_cells,
- ARRAY_SIZE(khadas_mcu_cells),
- NULL, 0, NULL);
- if (ret)
- return ret;
+ if (ddata->data->cells && ddata->data->ncells) {
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
+ ddata->data->cells,
+ ddata->data->ncells,
+ NULL, 0, NULL);
+ if (ret)
+ return ret;
+ }
if (of_property_present(dev->of_node, "#cooling-cells"))
return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
- khadas_mcu_fan_cells,
- ARRAY_SIZE(khadas_mcu_fan_cells),
+ ddata->data->fan_cells,
+ ddata->data->nfan_cells,
NULL, 0, NULL);
return 0;
@@ -123,7 +206,8 @@ static int khadas_mcu_probe(struct i2c_client *client)
#ifdef CONFIG_OF
static const struct of_device_id khadas_mcu_of_match[] = {
- { .compatible = "khadas,mcu", },
+ { .compatible = "khadas,mcu", .data = &khadas_mcu_data },
+ { .compatible = "khadas,vim4-mcu", .data = &khadas_vim4_mcu_data },
{},
};
MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);
--
2.49.0
^ permalink raw reply related
* [PATCH v3 2/8] dt-bindings: i2c: amlogic: Add compatible for T7 SOC
From: Ronald Claveau @ 2026-04-17 16:27 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: <20260417-add-mcu-fan-khadas-vim4-v3-0-a6a7f570b11b@aliel.fr>
Add the T7 SOC compatible which fallback to AXG compatible.
Acked-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
.../devicetree/bindings/i2c/amlogic,meson6-i2c.yaml | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml b/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml
index c4cc8af182807..7b59b60b62e5b 100644
--- a/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/amlogic,meson6-i2c.yaml
@@ -16,10 +16,15 @@ allOf:
properties:
compatible:
- enum:
- - amlogic,meson6-i2c # Meson6, Meson8 and compatible SoCs
- - amlogic,meson-gxbb-i2c # GXBB and compatible SoCs
- - amlogic,meson-axg-i2c # AXG and compatible SoCs
+ oneOf:
+ - items:
+ - enum:
+ - amlogic,t7-i2c
+ - const: amlogic,meson-axg-i2c
+ - enum:
+ - amlogic,meson6-i2c # Meson6, Meson8 and compatible SoCs
+ - amlogic,meson-gxbb-i2c # GXBB and compatible SoCs
+ - amlogic,meson-axg-i2c # AXG and compatible SoCs
reg:
maxItems: 1
--
2.49.0
^ permalink raw reply related
* [PATCH v3 3/8] mfd: khadas-mcu: Add per-variant configuration infrastructure and VIM4 support
From: Ronald Claveau @ 2026-04-17 16:27 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: <20260417-add-mcu-fan-khadas-vim4-v3-0-a6a7f570b11b@aliel.fr>
Introduce a per-variant configuration structure (khadas_mcu_data)
holding the regmap config and MFD cells,
selected at probe time via the of_device_id match data.
This makes adding other variants straightforward.
Also introduce khadas_mcu_fan_pdata to pass fan register address and
maximum level to the fan sub-driver, removing the hardcoded constants.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
include/linux/mfd/khadas-mcu.h | 39 +++++++++++++++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/include/linux/mfd/khadas-mcu.h b/include/linux/mfd/khadas-mcu.h
index a99ba2ed0e4e0..75e275d3fa8d9 100644
--- a/include/linux/mfd/khadas-mcu.h
+++ b/include/linux/mfd/khadas-mcu.h
@@ -70,6 +70,13 @@
#define KHADAS_MCU_WOL_INIT_START_REG 0x87 /* WO */
#define KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG 0x88 /* WO */
+/* VIM4 specific registers */
+#define KHADAS_MCU_VIM4_REST_CONF_REG 0x2c /* WO - reset EEPROM */
+#define KHADAS_MCU_VIM4_LED_ON_RAM_REG 0x89 /* WO - LED volatile */
+#define KHADAS_MCU_VIM4_FAN_CTRL_REG 0x8a /* WO */
+#define KHADAS_MCU_VIM4_WDT_EN_REG 0x8b /* WO */
+#define KHADAS_MCU_VIM4_SYS_RST_REG 0x91 /* WO */
+
enum {
KHADAS_BOARD_VIM1 = 0x1,
KHADAS_BOARD_VIM2,
@@ -82,10 +89,38 @@ enum {
* struct khadas_mcu - Khadas MCU structure
* @device: device reference used for logs
* @regmap: register map
+ * @data: pointer to variant-specific config
*/
struct khadas_mcu {
- struct device *dev;
- struct regmap *regmap;
+ struct device *dev;
+ struct regmap *regmap;
+ const struct khadas_mcu_data *data;
+};
+
+/**
+ * struct khadas_mcu_data - per-variant configuration
+ * @regmap_config: regmap configuration
+ * @cells: MFD sub-devices
+ * @ncells: number of sub-devices
+ * @fan_cells: MFD fan sub-devices
+ * @nfan_cells: number of fan sub-devices
+ */
+struct khadas_mcu_data {
+ const struct regmap_config *regmap_config;
+ const struct mfd_cell *cells;
+ int ncells;
+ const struct mfd_cell *fan_cells;
+ int nfan_cells;
+};
+
+/**
+ * struct khadas_mcu_fan_pdata - fan sub-driver configuration
+ * @fan_reg: register address to write the fan level
+ * @max_level: maximum fan level
+ */
+struct khadas_mcu_fan_pdata {
+ unsigned int fan_reg;
+ unsigned int max_level;
};
#endif /* MFD_KHADAS_MCU_H */
--
2.49.0
^ permalink raw reply related
* [PATCH v3 1/8] dt-bindings: mfd: khadas: Add new compatible for Khadas VIM4 MCU
From: Ronald Claveau @ 2026-04-17 16:27 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: <20260417-add-mcu-fan-khadas-vim4-v3-0-a6a7f570b11b@aliel.fr>
The Khadas VIM4 MCU register is slightly different
from previous boards' MCU.
This board also features a switchable power source for its fan.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
Documentation/devicetree/bindings/mfd/khadas,mcu.yaml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
index 084960fd5a1fd..a80718f7595ce 100644
--- a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
+++ b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
@@ -18,6 +18,7 @@ properties:
compatible:
enum:
- khadas,mcu # MCU revision is discoverable
+ - khadas,vim4-mcu # Different MCU variant, not discoverable
"#cooling-cells": # Only needed for boards having FAN control feature
const: 2
@@ -25,6 +26,10 @@ properties:
reg:
maxItems: 1
+ fan-supply:
+ description: Phandle to the regulator that powers the fan.
+ $ref: /schemas/types.yaml#/definitions/phandle
+
required:
- compatible
- reg
--
2.49.0
^ permalink raw reply related
* [PATCH v3 0/8] Add VIM4 MCU/FAN support
From: Ronald Claveau @ 2026-04-17 16:27 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 v3:
- PATCH 1: adding comment on vim4 compatible saying it is not discoverable,
thanks to Rob's and Neil's feedback.
- Link to v2: https://lore.kernel.org/r/20260403-add-mcu-fan-khadas-vim4-v2-0-70536b22439a@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: [PATCH 05/40] arm64: dts: rockchip: Add frl-enable-gpios to rk3576-luckfox-core3576
From: Cristian Ciocaltea @ 2026-04-17 16:34 UTC (permalink / raw)
To: Heiko Stuebner, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: kernel, devicetree, linux-arm-kernel, linux-rockchip,
linux-kernel
In-Reply-To: <2000470.6tgchFWduM@phil>
Hi Heiko,
On 4/17/26 2:32 PM, Heiko Stuebner wrote:
> Hi Cristian,
>
> the comments below apply sort of to all patches in that series.
>
> Am Freitag, 17. April 2026, 11:24:39 Mitteleuropäische Sommerzeit schrieb Cristian Ciocaltea:
>> The board exposes the GPIO4_C6 line to control the voltage bias on the
>> HDMI data lines. It must be asserted when operating in HDMI 2.1 FRL
>> mode and deasserted for HDMI 1.4/2.0 TMDS mode.
>>
>> Wire up the HDMI node to the GPIO line using the frl-enable-gpios
>> property and drop the line from the vcc_5v0_hdmi regulator to allow
>> adjusting the bias when transitioning between TMDS and FRL operating
>> modes.
>>
>> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
>> ---
>> arch/arm64/boot/dts/rockchip/rk3576-luckfox-core3576.dtsi | 9 ++++-----
>> 1 file changed, 4 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/arm64/boot/dts/rockchip/rk3576-luckfox-core3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-luckfox-core3576.dtsi
>> index 749f0a54b478..93ae37699366 100644
>> --- a/arch/arm64/boot/dts/rockchip/rk3576-luckfox-core3576.dtsi
>> +++ b/arch/arm64/boot/dts/rockchip/rk3576-luckfox-core3576.dtsi
>> @@ -140,10 +140,7 @@ regulator-state-mem {
>>
>> vcc_5v0_hdmi: regulator-vcc-5v0-hdmi {
>> compatible = "regulator-fixed";
>> - enable-active-high;
>> - gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
>> - pinctrl-names = "default";
>> - pinctrl-0 = <&hdmi_con_en>;
>> + regulator-always-on;
>> regulator-min-microvolt = <5000000>;
>> regulator-max-microvolt = <5000000>;
>> regulator-name = "vcc_5v0_hdmi";
>
> I think this regulator was sort of a complete hack, to set that
> gpio to some sort of default state, by declaring it as hdmi-pwr-supply.
>
> Only 2 rk3576 boards seem, to use that hack, so I think as that "regulator"
> is completely functionless now, the whole thing could be removed?
Ack, let's just drop it.
>
>
>> @@ -231,6 +228,8 @@ &gpu {
>> };
>>
>> &hdmi {
>> + pinctrl-0 = <&hdmi_txm0_pins &hdmi_tx_scl &hdmi_tx_sda &hdmi_frl_en>;
>> + frl-enable-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>;
>
> this should be sorted the other way around I think.
>
> Also please provide a pinctrl-names property too. If for whatever reason
> the dw-hdmi aquires a 2nd pinctrl state in the future, this makes sure
> board DTs are staying in the "old" compatible mode until they are adapted.
Just to make sure I fully understand, the convention is that
pinctrl-names = "default";
should be always provided, even when the node overrides an existing pinctrl-0
property?
E.g. in rk3576.dtsi we have:
hdmi: hdmi@27da0000 {
...
pinctrl-names = "default";
pinctrl-0 = <&hdmi_txm0_pins &hdmi_tx_scl &hdmi_tx_sda>;
...
}
Hence I omitted pinctrl-names which doesn't change and just appended
&hdmi_frl_en to pinctrl-0's original value.
>
>
>> status = "okay";
>> };
>>
>> @@ -655,7 +654,7 @@ &pcie0 {
>>
>> &pinctrl {
>> hdmi {
>> - hdmi_con_en: hdmi-con-en {
>> + hdmi_frl_en: hdmi-frl-en {
>
> pinctrl names should ideally match the naming in schematics, for example the
> "HDMI0_TX_ON_H" for jaguar and tiger. This makes it way easier to> go from DT
> to schematics and back.
I opted for a more descriptive name that could be used consistently across all
boards, given that not all schematics are publicly available.
You make a fair point though, we should probably stick with the pretty terrible
hdmi[N]_tx_on_h naming instead.
Thanks,
Cristian
^ permalink raw reply
* Re: [PATCH v7 1/3] dt-bindings: media: mediatek-jpeg-decoder: add MT8189 compatible string
From: Conor Dooley @ 2026-04-17 16:22 UTC (permalink / raw)
To: Jianhua Lin
Cc: nicolas, mchehab, robh, krzk+dt, conor+dt, matthias.bgg,
angelogioacchino.delregno, devicetree, linux-kernel, linux-media,
linux-arm-kernel, linux-mediatek,
Project_Global_Chrome_Upstream_Group, sirius.wang, vince-wl.liu,
jh.hsu
In-Reply-To: <20260417100519.1043-2-jianhua.lin@mediatek.com>
[-- Attachment #1: Type: text/plain, Size: 3203 bytes --]
On Fri, Apr 17, 2026 at 06:05:17PM +0800, Jianhua Lin wrote:
> Add the compatible string for the JPEG decoder block found in the
> MediaTek MT8189 SoC.
>
> Compared to previous generation ICs, the MT8189 JPEG decoder requires
> 34-bit IOVA address space support and only needs a single clock
> ("jpgdec") instead of two. Therefore, it is added as a standalone
> compatible string without falling back to older SoCs.
>
> Update the binding schema to include the new compatible string and add
> an `allOf` block with conditional checks. This enforces the single clock
> requirement for MT8189 while preserving the two-clock requirement
> ("jpgdec-smi", "jpgdec") for older SoCs.
>
> Signed-off-by: Jianhua Lin <jianhua.lin@mediatek.com>
> ---
> .../bindings/media/mediatek-jpeg-decoder.yaml | 48 +++++++++++++++----
> 1 file changed, 40 insertions(+), 8 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
> index a4aacd3eb189..fd895688a038 100644
> --- a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
> +++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.yaml
> @@ -15,10 +15,10 @@ description: |-
> properties:
> compatible:
> oneOf:
> - - items:
> - - enum:
> - - mediatek,mt8173-jpgdec
> - - mediatek,mt2701-jpgdec
> + - enum:
> + - mediatek,mt2701-jpgdec
> + - mediatek,mt8173-jpgdec
> + - mediatek,mt8189-jpgdec
> - items:
> - enum:
> - mediatek,mt7623-jpgdec
> @@ -32,13 +32,20 @@ properties:
> maxItems: 1
>
> clocks:
> + minItems: 1
> maxItems: 2
> - minItems: 2
>
> clock-names:
> - items:
> - - const: jpgdec-smi
> - - const: jpgdec
> + oneOf:
> + - items:
> + - const: jpgdec
> + - items:
> + - const: jpgdec-smi
> + - const: jpgdec
> +
> + mediatek,larb:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: a phandle to the smi_larb node.
This should be restricted to only the new platform.
>
> power-domains:
> maxItems: 1
> @@ -60,6 +67,31 @@ required:
> - power-domains
> - iommus
>
> +allOf:
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: mediatek,mt8189-jpgdec
> + then:
> + properties:
> + clocks:
> + minItems: 1
> + maxItems: 1
Constraints that duplicate the outtermost ones don't need to
be/shouldn't be repeated here. You only need the maxItems here and the
minItems in the else.
pw-bot: changes-requested
Cheers,
COnor.
> + clock-names:
> + minItems: 1
> + maxItems: 1
> + required:
> + - mediatek,larb
> + else:
> + properties:
> + clocks:
> + minItems: 2
> + maxItems: 2
> + clock-names:
> + minItems: 2
> + maxItems: 2
> +
> additionalProperties: false
>
> examples:
> --
> 2.45.2
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH bpf-next v2] arm32, bpf: Reject BPF-to-BPF calls and callbacks in the JIT
From: Puranjay Mohan @ 2026-04-17 16:15 UTC (permalink / raw)
To: Emil Tsalapatis
Cc: bpf, linux-arm-kernel, Jonas Rebmann, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu, Russell King,
kernel
In-Reply-To: <DHVJQQK6L83L.13DDK8BJXQFXG@etsalapatis.com>
On Fri, Apr 17, 2026 at 4:48 PM Emil Tsalapatis <emil@etsalapatis.com> wrote:
>
> On Fri Apr 17, 2026 at 10:33 AM EDT, Puranjay Mohan wrote:
> > The ARM32 BPF JIT does not support BPF-to-BPF function calls
> > (BPF_PSEUDO_CALL) or callbacks (BPF_PSEUDO_FUNC), but it does
> > not reject them either.
> >
> > When a program with subprograms is loaded (e.g. libxdp's XDP
> > dispatcher uses __noinline__ subprograms, or any program using
> > callbacks like bpf_loop or bpf_for_each_map_elem), the verifier
> > invokes bpf_jit_subprogs() which calls bpf_int_jit_compile()
> > for each subprogram.
> >
> > For BPF_PSEUDO_CALL, since ARM32 does not reject it, the JIT
> > silently emits code using the wrong address computation:
> >
> > func = __bpf_call_base + imm
> >
> > where imm is a pc-relative subprogram offset, producing a bogus
> > function pointer.
> >
> > For BPF_PSEUDO_FUNC, the ldimm64 handler ignores src_reg and
> > loads the immediate as a normal 64-bit value without error.
> >
> > In both cases, build_body() reports success and a JIT image is
> > allocated. ARM32 lacks the jit_data/extra_pass mechanism needed
> > for the second JIT pass in bpf_jit_subprogs(). On the second
> > pass, bpf_int_jit_compile() performs a full fresh compilation,
> > allocating a new JIT binary and overwriting prog->bpf_func. The
> > first allocation is never freed. bpf_jit_subprogs() then detects
> > the function pointer changed and aborts with -ENOTSUPP, but the
> > original JIT binary has already been leaked. Each program
> > load/unload cycle leaks one JIT binary allocation, as reported
> > by kmemleak:
> >
> > unreferenced object 0xbf0a1000 (size 4096):
> > backtrace:
> > bpf_jit_binary_alloc+0x64/0xfc
> > bpf_int_jit_compile+0x14c/0x348
> > bpf_jit_subprogs+0x4fc/0xa60
> >
> > Fix this by rejecting both BPF_PSEUDO_CALL in the BPF_CALL
> > handler and BPF_PSEUDO_FUNC in the BPF_LD_IMM64 handler, falling
> > through to the existing 'notyet' path. This causes build_body()
> > to fail before any JIT binary is allocated, so
> > bpf_int_jit_compile() returns the original program unjitted.
> > bpf_jit_subprogs() then sees !prog->jited and cleanly falls
> > back to the interpreter with no leak.
>
> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
>
> The Fixes tag is a bit unrelated since it's for x64 but the original
> commit that adds the file (ddecdfcea0ae8 ?) is so far back it probably
> doesn't matter.
That fixes tag commit has verifier changes too:
-- 8< --
+ }
+ }
+ for (i = 0; i <= env->subprog_cnt; i++) {
+ old_bpf_func = func[i]->bpf_func;
+ tmp = bpf_int_jit_compile(func[i]);
+ if (tmp != func[i] || func[i]->bpf_func != old_bpf_func) {
+ verbose(env, "JIT doesn't support bpf-to-bpf calls\n");
+ err = -EFAULT;
+ goto out_free;
+ }
+ cond_resched();
+ }
+
-- >8 --
This call to bpf_int_jit_compile() is where the memory leak was
introduced, before this commit, there was no memory leak.
^ permalink raw reply
* Re: [PATCH 09/18] KVM: arm64: vgic-v5: Limit support to 64 PPIs
From: Joey Gouly @ 2026-04-17 16:10 UTC (permalink / raw)
To: Marc Zyngier
Cc: kvmarm, linux-arm-kernel, Suzuki K Poulose, Oliver Upton,
Zenghui Yu, Sascha Bischoff
In-Reply-To: <20260415115559.2227718-10-maz@kernel.org>
On Wed, Apr 15, 2026 at 12:55:50PM +0100, Marc Zyngier wrote:
> Although we have some code supporting 128 PPIs, the only supported
> configuration is 64 PPIs. There is no way to test the 128 PPI code,
> so it is bound to bitrot very quickly.
>
> Given that KVM/arm64's goal has always been to stick to non-IMPDEF
> behaviours, drop the 128 PPI support. Someone motivated enough and
> with very strong arguments can always bring it back -- it's all in
> the git history.
>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
> ---
> arch/arm64/kvm/hyp/vgic-v5-sr.c | 82 ++++++---------------------
> arch/arm64/kvm/sys_regs.c | 17 +++---
> arch/arm64/kvm/vgic/vgic-kvm-device.c | 9 +--
> 3 files changed, 26 insertions(+), 82 deletions(-)
>
> diff --git a/arch/arm64/kvm/hyp/vgic-v5-sr.c b/arch/arm64/kvm/hyp/vgic-v5-sr.c
> index 47e6bcd437029..6d69dfe89a96c 100644
> --- a/arch/arm64/kvm/hyp/vgic-v5-sr.c
> +++ b/arch/arm64/kvm/hyp/vgic-v5-sr.c
> @@ -30,10 +30,9 @@ void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if)
> {
> /*
> * The following code assumes that the bitmap storage that we have for
> - * PPIs is either 64 (architected PPIs, only) or 128 bits (architected &
> - * impdef PPIs).
> + * PPIs is either 64 (architected PPIs, only).
> */
> - BUILD_BUG_ON(VGIC_V5_NR_PRIVATE_IRQS % 64);
> + BUILD_BUG_ON(VGIC_V5_NR_PRIVATE_IRQS != 64);
>
> bitmap_write(host_data_ptr(vgic_v5_ppi_state)->activer_exit,
> read_sysreg_s(SYS_ICH_PPI_ACTIVER0_EL2), 0, 64);
> @@ -49,22 +48,6 @@ void __vgic_v5_save_ppi_state(struct vgic_v5_cpu_if *cpu_if)
> cpu_if->vgic_ppi_priorityr[6] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR6_EL2);
> cpu_if->vgic_ppi_priorityr[7] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR7_EL2);
>
> - if (VGIC_V5_NR_PRIVATE_IRQS == 128) {
> - bitmap_write(host_data_ptr(vgic_v5_ppi_state)->activer_exit,
> - read_sysreg_s(SYS_ICH_PPI_ACTIVER1_EL2), 64, 64);
> - bitmap_write(host_data_ptr(vgic_v5_ppi_state)->pendr,
> - read_sysreg_s(SYS_ICH_PPI_PENDR1_EL2), 64, 64);
> -
> - cpu_if->vgic_ppi_priorityr[8] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR8_EL2);
> - cpu_if->vgic_ppi_priorityr[9] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR9_EL2);
> - cpu_if->vgic_ppi_priorityr[10] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR10_EL2);
> - cpu_if->vgic_ppi_priorityr[11] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR11_EL2);
> - cpu_if->vgic_ppi_priorityr[12] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR12_EL2);
> - cpu_if->vgic_ppi_priorityr[13] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR13_EL2);
> - cpu_if->vgic_ppi_priorityr[14] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR14_EL2);
> - cpu_if->vgic_ppi_priorityr[15] = read_sysreg_s(SYS_ICH_PPI_PRIORITYR15_EL2);
> - }
> -
> /* Now that we are done, disable DVI */
> write_sysreg_s(0, SYS_ICH_PPI_DVIR0_EL2);
> write_sysreg_s(0, SYS_ICH_PPI_DVIR1_EL2);
> @@ -74,9 +57,6 @@ void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if)
> {
> DECLARE_BITMAP(pendr, VGIC_V5_NR_PRIVATE_IRQS);
>
> - /* We assume 64 or 128 PPIs - see above comment */
> - BUILD_BUG_ON(VGIC_V5_NR_PRIVATE_IRQS % 64);
> -
> /* Enable DVI so that the guest's interrupt config takes over */
> write_sysreg_s(bitmap_read(cpu_if->vgic_ppi_dvir, 0, 64),
> SYS_ICH_PPI_DVIR0_EL2);
> @@ -108,50 +88,20 @@ void __vgic_v5_restore_ppi_state(struct vgic_v5_cpu_if *cpu_if)
> write_sysreg_s(cpu_if->vgic_ppi_priorityr[7],
> SYS_ICH_PPI_PRIORITYR7_EL2);
>
> - if (VGIC_V5_NR_PRIVATE_IRQS == 128) {
> - /* Enable DVI so that the guest's interrupt config takes over */
> - write_sysreg_s(bitmap_read(cpu_if->vgic_ppi_dvir, 64, 64),
> - SYS_ICH_PPI_DVIR1_EL2);
> -
> - write_sysreg_s(bitmap_read(cpu_if->vgic_ppi_activer, 64, 64),
> - SYS_ICH_PPI_ACTIVER1_EL2);
> - write_sysreg_s(bitmap_read(cpu_if->vgic_ppi_enabler, 64, 64),
> - SYS_ICH_PPI_ENABLER1_EL2);
> - write_sysreg_s(bitmap_read(pendr, 64, 64),
> - SYS_ICH_PPI_PENDR1_EL2);
> -
> - write_sysreg_s(cpu_if->vgic_ppi_priorityr[8],
> - SYS_ICH_PPI_PRIORITYR8_EL2);
> - write_sysreg_s(cpu_if->vgic_ppi_priorityr[9],
> - SYS_ICH_PPI_PRIORITYR9_EL2);
> - write_sysreg_s(cpu_if->vgic_ppi_priorityr[10],
> - SYS_ICH_PPI_PRIORITYR10_EL2);
> - write_sysreg_s(cpu_if->vgic_ppi_priorityr[11],
> - SYS_ICH_PPI_PRIORITYR11_EL2);
> - write_sysreg_s(cpu_if->vgic_ppi_priorityr[12],
> - SYS_ICH_PPI_PRIORITYR12_EL2);
> - write_sysreg_s(cpu_if->vgic_ppi_priorityr[13],
> - SYS_ICH_PPI_PRIORITYR13_EL2);
> - write_sysreg_s(cpu_if->vgic_ppi_priorityr[14],
> - SYS_ICH_PPI_PRIORITYR14_EL2);
> - write_sysreg_s(cpu_if->vgic_ppi_priorityr[15],
> - SYS_ICH_PPI_PRIORITYR15_EL2);
> - } else {
> - write_sysreg_s(0, SYS_ICH_PPI_DVIR1_EL2);
> -
> - write_sysreg_s(0, SYS_ICH_PPI_ACTIVER1_EL2);
> - write_sysreg_s(0, SYS_ICH_PPI_ENABLER1_EL2);
> - write_sysreg_s(0, SYS_ICH_PPI_PENDR1_EL2);
> -
> - write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR8_EL2);
> - write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR9_EL2);
> - write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR10_EL2);
> - write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR11_EL2);
> - write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR12_EL2);
> - write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR13_EL2);
> - write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR14_EL2);
> - write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR15_EL2);
> - }
> + write_sysreg_s(0, SYS_ICH_PPI_DVIR1_EL2);
> +
> + write_sysreg_s(0, SYS_ICH_PPI_ACTIVER1_EL2);
> + write_sysreg_s(0, SYS_ICH_PPI_ENABLER1_EL2);
> + write_sysreg_s(0, SYS_ICH_PPI_PENDR1_EL2);
> +
> + write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR8_EL2);
> + write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR9_EL2);
> + write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR10_EL2);
> + write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR11_EL2);
> + write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR12_EL2);
> + write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR13_EL2);
> + write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR14_EL2);
> + write_sysreg_s(0, SYS_ICH_PPI_PRIORITYR15_EL2);
> }
>
> void __vgic_v5_save_state(struct vgic_v5_cpu_if *cpu_if)
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 4ef13ac0703df..eba3ef793097d 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -724,6 +724,7 @@ static bool access_gicv5_ppi_enabler(struct kvm_vcpu *vcpu,
> {
> unsigned long *mask = vcpu->kvm->arch.vgic.gicv5_vm.vgic_ppi_mask;
> struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> + unsigned long reg = p->regval;
> int i;
>
> /* We never expect to get here with a read! */
> @@ -731,21 +732,17 @@ static bool access_gicv5_ppi_enabler(struct kvm_vcpu *vcpu,
> return undef_access(vcpu, p, r);
>
> /*
> - * If we're only handling architected PPIs and the guest writes to the
> - * enable for the non-architected PPIs, we just return as there's
> - * nothing to do at all. We don't even allocate the storage for them in
> - * this case.
> + * As we're only handling architected PPIs, the guest writes to the
> + * enable for the non-architected PPIs just return as there's
> + * nothing to do at all. We don't even allocate the storage for them.
> */
> - if (VGIC_V5_NR_PRIVATE_IRQS == 64 && p->Op2 % 2)
> + if (p->Op2 % 2)
> return true;
>
> /*
> - * Merge the raw guest write into out bitmap at an offset of either 0 or
> - * 64, then and it with our PPI mask.
> + * Merge the raw guest write into out bitmap, anded with our PPI mask.
> */
> - bitmap_write(cpu_if->vgic_ppi_enabler, p->regval, 64 * (p->Op2 % 2), 64);
> - bitmap_and(cpu_if->vgic_ppi_enabler, cpu_if->vgic_ppi_enabler, mask,
> - VGIC_V5_NR_PRIVATE_IRQS);
> + bitmap_and(cpu_if->vgic_ppi_enabler, ®, mask, VGIC_V5_NR_PRIVATE_IRQS);
>
> /*
> * Sync the change in enable states to the vgic_irqs. We consider all
> diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
> index a96c77dccf353..90be99443df3b 100644
> --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
> +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
> @@ -730,18 +730,15 @@ static int vgic_v5_get_userspace_ppis(struct kvm_device *dev,
> guard(mutex)(&dev->kvm->arch.config_lock);
>
> /*
> - * We either support 64 or 128 PPIs. In the former case, we need to
> - * return 0s for the second 64 bits as we have no storage backing those.
> + * We only support 64 PPIs, so, we need to return 0s for the
> + * second 64 bits as we have no storage backing those.
> */
> ret = put_user(bitmap_read(gicv5_vm->userspace_ppis, 0, 64), uaddr);
> if (ret)
> return ret;
> uaddr++;
>
> - if (VGIC_V5_NR_PRIVATE_IRQS == 128)
> - ret = put_user(bitmap_read(gicv5_vm->userspace_ppis, 64, 128), uaddr);
> - else
> - ret = put_user(0, uaddr);
> + ret = put_user(0, uaddr);
>
> return ret;
> }
> --
> 2.47.3
>
^ permalink raw reply
* Re: [PATCH v2 3/3] dt-bindings: reserved-memory: Change maintainer for BPMP SHMEM
From: Conor Dooley @ 2026-04-17 16:09 UTC (permalink / raw)
To: Thierry Reding
Cc: Aaro Koskinen, Geert Uytterhoeven, linux-tegra, linux-arm-kernel,
linux-pm, linux-omap, linux-m68k, devicetree, linux-kernel
In-Reply-To: <20260417131549.3154534-3-thierry.reding@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 413 bytes --]
On Fri, Apr 17, 2026 at 03:15:48PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
>
> Peter sadly passed away a while ago, so change the maintainers for BPMP
> SHMEM to Jon and myself.
>
> Suggested-by: Geert Uytterhoeven <geert@linux-m68k.org>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v7 1/3] dt-bindings: pinctrl: Add aspeed,ast2700-soc0-pinctrl
From: Conor Dooley @ 2026-04-17 16:06 UTC (permalink / raw)
To: Billy Tsai
Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Joel Stanley, Andrew Jeffery, Linus Walleij, Bartosz Golaszewski,
Ryan Chen, Andrew Jeffery, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org,
openbmc@lists.ozlabs.org, linux-gpio@vger.kernel.org,
linux-clk@vger.kernel.org
In-Reply-To: <OSQPR06MB7252EB0C2A1A3313DE49406B8B202@OSQPR06MB7252.apcprd06.prod.outlook.com>
[-- Attachment #1: Type: text/plain, Size: 3905 bytes --]
On Fri, Apr 17, 2026 at 02:20:25AM +0000, Billy Tsai wrote:
> > > + properties:
> > > + function:
> > > + enum:
> > > + - EMMC
> > > + - JTAGDDR
> > > + - JTAGM0
> > > + - JTAGPCIEA
> > > + - JTAGPCIEB
> > > + - JTAGPSP
> > > + - JTAGSSP
> > > + - JTAGTSP
> > > + - JTAGUSB3A
> > > + - JTAGUSB3B
> > > + - PCIERC0PERST
> > > + - PCIERC1PERST
> > > + - TSPRSTN
> > > + - UFSCLKI
> > > + - USB2AD0
> > > + - USB2AD1
> > > + - USB2AH
> > > + - USB2AHP
> > > + - USB2AHPD0
> > > + - USB2AXH
> > > + - USB2AXH2B
> > > + - USB2AXHD1
> > > + - USB2AXHP
> > > + - USB2AXHP2B
> > > + - USB2AXHPD1
> > > + - USB2BD0
> > > + - USB2BD1
> > > + - USB2BH
> > > + - USB2BHP
> > > + - USB2BHPD0
> > > + - USB2BXH
> > > + - USB2BXH2A
> > > + - USB2BXHD1
> > > + - USB2BXHP
> > > + - USB2BXHP2A
> > > + - USB2BXHPD1
> > > + - USB3AXH
> > > + - USB3AXH2B
> > > + - USB3AXHD
> > > + - USB3AXHP
> > > + - USB3AXHP2B
> > > + - USB3AXHPD
> > > + - USB3BXH
> > > + - USB3BXH2A
> > > + - USB3BXHD
> > > + - USB3BXHP
> > > + - USB3BXHP2A
> > > + - USB3BXHPD
> > > + - VB
> > > + - VGADDC
> > > +
> > > + groups:
> > > + enum:
> > > + - EMMCCDN
> > > + - EMMCG1
> > > + - EMMCG4
> > > + - EMMCG8
> > > + - EMMCWPN
> > > + - JTAG0
> > > + - PCIERC0PERST
> > > + - PCIERC1PERST
> > > + - TSPRSTN
> > > + - UFSCLKI
> > > + - USB2A
> > > + - USB2AAP
> > > + - USB2ABP
> > > + - USB2ADAP
> > > + - USB2AH
> > > + - USB2AHAP
> > > + - USB2B
> > > + - USB2BAP
> > > + - USB2BBP
> > > + - USB2BDBP
> > > + - USB2BH
> > > + - USB2BHBP
> > > + - USB3A
> > > + - USB3AAP
> > > + - USB3ABP
> > > + - USB3B
> > > + - USB3BAP
> > > + - USB3BBP
> > > + - VB0
> > > + - VB1
> > > + - VGADDC
> > > + pins:
> > > + enum:
> > > + - AB13
> > > + - AB14
> > > + - AC13
> > > + - AC14
> > > + - AD13
> > > + - AD14
> > > + - AE13
> > > + - AE14
> > > + - AE15
> > > + - AF13
> > > + - AF14
> > > + - AF15
>
> > Why do you have groups and pins?
>
> > Is it valid in your device to have groups and pins in the same node?
>
> The intent is to support both group-based mux selection and
> configuration, as well as per-pin configuration.
>
> In our hardware:
>
> - `function` + `groups` are used for pinmux selection.
> - `pins` is used for per-pin configuration (e.g. drive strength,
> bias settings).
> - `groups` may also be used for group-level configuration.
>
> As a result, both `groups` and `pins` may appear in the same node,
> but they serve different purposes and do not conflict:
>
> - `groups` selects the mux function and may apply configuration to
> the entire group.
> - `pins` allows overriding or specifying configuration for individual
> pins.
>
> In most cases, only one of them is needed, but both are allowed when
> both group-level and per-pin configuration are required.
To be honest, that sounds like your groups are not sufficiently
granular and should be reduced such that you can use them for pin
settings.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v6 01/30] mm: Introduce kpkeys
From: Kevin Brodsky @ 2026-04-17 15:59 UTC (permalink / raw)
To: David Hildenbrand (Arm), linux-hardening
Cc: linux-kernel, Andrew Morton, Andy Lutomirski, Catalin Marinas,
Dave Hansen, Ira Weiny, Jann Horn, Jeff Xu, Joey Gouly, Kees Cook,
Linus Walleij, Lorenzo Stoakes, Marc Zyngier, Mark Brown,
Matthew Wilcox, Maxwell Bland, Mike Rapoport (IBM),
Peter Zijlstra, Pierre Langlois, Quentin Perret, Rick Edgecombe,
Ryan Roberts, Thomas Gleixner, Vlastimil Babka, Will Deacon,
Yang Shi, Yeoreum Yun, linux-arm-kernel, linux-mm, x86
In-Reply-To: <00b24db8-0063-48d6-8bc4-e8b670d8f0d5@kernel.org>
On 17/04/2026 16:37, David Hildenbrand (Arm) wrote:
> On 2/27/26 18:54, Kevin Brodsky wrote:
>> kpkeys is a simple framework to enable the use of protection keys
>> (pkeys) to harden the kernel itself. This patch introduces the basic
>> API in <linux/kpkeys.h>: a couple of functions to set and restore
>> the pkey register and macros to define guard objects.
>>
>> kpkeys introduces a new concept on top of pkeys: the kpkeys level.
>> Each level is associated to a set of permissions for the pkeys
>> managed by the kpkeys framework. kpkeys_set_level(lvl) sets those
>> permissions according to lvl, and returns the original pkey
>> register, to be later restored by kpkeys_restore_pkey_reg(). To
>> start with, only KPKEYS_LVL_DEFAULT is available, which is meant
>> to grant RW access to KPKEYS_PKEY_DEFAULT (i.e. all memory since
>> this is the only available pkey for now).
>>
>> Because each architecture implementing pkeys uses a different
>> representation for the pkey register, and may reserve certain pkeys
>> for specific uses, support for kpkeys must be explicitly indicated
>> by selecting ARCH_HAS_KPKEYS and defining the following functions in
>> <asm/kpkeys.h>, in addition to the macros provided in
>> <asm-generic/kpkeys.h>:
>>
>> - arch_kpkeys_set_level()
>> - arch_kpkeys_restore_pkey_reg()
>> - arch_kpkeys_enabled()
> Another thing: why not simply drop the "arch_" stuff from these helpers?
The first two are not meant to be directly called, they're the
arch-specific implementation of kpkeys_set_level() and
kpkeys_restore_pkey_reg(), and those generic functions handle some
generic logic.
arch_kpkeys_enabled() is directly used in generic code, so I suppose it
could be renamed to kpkeys_enabled()? It's actually implemented in an
arch header so I wasn't too sure about it.
- Kevin
^ permalink raw reply
* Re: [PATCH 2/4] KVM: arm64: timer: Kill the per-timer level cache
From: Marc Zyngier @ 2026-04-17 15:56 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel
Cc: Deepanshu Kartikey, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu
In-Reply-To: <20260417124612.2770268-3-maz@kernel.org>
On Fri, 17 Apr 2026 13:46:10 +0100,
Marc Zyngier <maz@kernel.org> wrote:
>
> The timer code makes use of a per-timer irq level cache, which
> looks like a very minor optimisation to avoid taking a lock upon
> updating the GIC view of the interrupt when it is unchanged from
> the previous state.
>
> This is coming in the way of more important correctness issues,
> so get rid of the cache, which simplifies a couple of minor things.
>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
> arch/arm64/kvm/arch_timer.c | 18 +++++++++---------
> include/kvm/arm_arch_timer.h | 5 -----
> 2 files changed, 9 insertions(+), 14 deletions(-)
>
> diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
> index d6802fc87e085..fdc1afff06340 100644
> --- a/arch/arm64/kvm/arch_timer.c
> +++ b/arch/arm64/kvm/arch_timer.c
> @@ -446,9 +446,8 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
> {
> kvm_timer_update_status(timer_ctx, new_level);
>
> - timer_ctx->irq.level = new_level;
> trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_irq(timer_ctx),
> - timer_ctx->irq.level);
> + new_level);
>
> if (userspace_irqchip(vcpu->kvm))
> return;
> @@ -466,7 +465,7 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
>
> kvm_vgic_inject_irq(vcpu->kvm, vcpu,
> timer_irq(timer_ctx),
> - timer_ctx->irq.level,
> + new_level,
> timer_ctx);
> }
>
> @@ -477,8 +476,7 @@ static void timer_emulate(struct arch_timer_context *ctx)
>
> trace_kvm_timer_emulate(ctx, pending);
>
> - if (pending != ctx->irq.level)
> - kvm_timer_update_irq(timer_context_to_vcpu(ctx), pending, ctx);
> + kvm_timer_update_irq(timer_context_to_vcpu(ctx), pending, ctx);
>
> kvm_timer_update_status(ctx, pending);
As my new best mate Sashiko pointed out, kvm_timer_update_status()
here becomes redundant, as the unconditional call to
kvm_timer_update_irq() already contains that.
I'll drop it from the patch when applying, unless there are more
comments.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply
* Re: [PATCH bpf-next v2] arm32, bpf: Reject BPF-to-BPF calls and callbacks in the JIT
From: Emil Tsalapatis @ 2026-04-17 15:48 UTC (permalink / raw)
To: Puranjay Mohan, bpf, linux-arm-kernel
Cc: Jonas Rebmann, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman,
Kumar Kartikeya Dwivedi, Song Liu, Russell King, kernel
In-Reply-To: <20260417143353.838911-1-puranjay@kernel.org>
On Fri Apr 17, 2026 at 10:33 AM EDT, Puranjay Mohan wrote:
> The ARM32 BPF JIT does not support BPF-to-BPF function calls
> (BPF_PSEUDO_CALL) or callbacks (BPF_PSEUDO_FUNC), but it does
> not reject them either.
>
> When a program with subprograms is loaded (e.g. libxdp's XDP
> dispatcher uses __noinline__ subprograms, or any program using
> callbacks like bpf_loop or bpf_for_each_map_elem), the verifier
> invokes bpf_jit_subprogs() which calls bpf_int_jit_compile()
> for each subprogram.
>
> For BPF_PSEUDO_CALL, since ARM32 does not reject it, the JIT
> silently emits code using the wrong address computation:
>
> func = __bpf_call_base + imm
>
> where imm is a pc-relative subprogram offset, producing a bogus
> function pointer.
>
> For BPF_PSEUDO_FUNC, the ldimm64 handler ignores src_reg and
> loads the immediate as a normal 64-bit value without error.
>
> In both cases, build_body() reports success and a JIT image is
> allocated. ARM32 lacks the jit_data/extra_pass mechanism needed
> for the second JIT pass in bpf_jit_subprogs(). On the second
> pass, bpf_int_jit_compile() performs a full fresh compilation,
> allocating a new JIT binary and overwriting prog->bpf_func. The
> first allocation is never freed. bpf_jit_subprogs() then detects
> the function pointer changed and aborts with -ENOTSUPP, but the
> original JIT binary has already been leaked. Each program
> load/unload cycle leaks one JIT binary allocation, as reported
> by kmemleak:
>
> unreferenced object 0xbf0a1000 (size 4096):
> backtrace:
> bpf_jit_binary_alloc+0x64/0xfc
> bpf_int_jit_compile+0x14c/0x348
> bpf_jit_subprogs+0x4fc/0xa60
>
> Fix this by rejecting both BPF_PSEUDO_CALL in the BPF_CALL
> handler and BPF_PSEUDO_FUNC in the BPF_LD_IMM64 handler, falling
> through to the existing 'notyet' path. This causes build_body()
> to fail before any JIT binary is allocated, so
> bpf_int_jit_compile() returns the original program unjitted.
> bpf_jit_subprogs() then sees !prog->jited and cleanly falls
> back to the interpreter with no leak.
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
The Fixes tag is a bit unrelated since it's for x64 but the original
commit that adds the file (ddecdfcea0ae8 ?) is so far back it probably
doesn't matter.
>
> Acked-by: Daniel Borkmann <daniel@iogearbox.net>
> Fixes: 1c2a088a6626 ("bpf: x64: add JIT support for multi-function programs")
> Reported-by: Jonas Rebmann <jre@pengutronix.de>
> Closes: https://lore.kernel.org/bpf/b63e9174-7a3d-4e22-8294-16df07a4af89@pengutronix.de
> Tested-by: Jonas Rebmann <jre@pengutronix.de>
> Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
> ---
>
> Changelog:
> v1: https://lore.kernel.org/all/20260417103004.3552500-1-puranjay@kernel.org/
> Changes in v2:
> - Add Acked-by: Daniel Borkmann <daniel@iogearbox.net>
> - Reject BPF_PSEUDO_FUNC in the BPF_LD | BPF_IMM | BPF_DW handler
> - Move code below declarations
>
> ---
> arch/arm/net/bpf_jit_32.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
> index deeb8f292454..a900aa973885 100644
> --- a/arch/arm/net/bpf_jit_32.c
> +++ b/arch/arm/net/bpf_jit_32.c
> @@ -1852,6 +1852,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
> {
> u64 val = (u32)imm | (u64)insn[1].imm << 32;
>
> + if (insn->src_reg == BPF_PSEUDO_FUNC)
> + goto notyet;
> +
> emit_a32_mov_i64(dst, val, ctx);
>
> return 1;
> @@ -2055,6 +2058,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
> const s8 *r5 = bpf2a32[BPF_REG_5];
> const u32 func = (u32)__bpf_call_base + (u32)imm;
>
> + if (insn->src_reg == BPF_PSEUDO_CALL)
> + goto notyet;
> +
> emit_a32_mov_r64(true, r0, r1, ctx);
> emit_a32_mov_r64(true, r1, r2, ctx);
> emit_push_r64(r5, ctx);
>
> base-commit: 1f5ffc672165ff851063a5fd044b727ab2517ae3
^ permalink raw reply
* Re: [PATCH v3 8/8] unwind: arm64: Use sframe to unwind interrupt frames.
From: Jens Remus @ 2026-04-17 15:45 UTC (permalink / raw)
To: Dylan Hatch, Roman Gushchin, Weinan Liu, Will Deacon,
Josh Poimboeuf, Indu Bhagat, Peter Zijlstra, Steven Rostedt,
Catalin Marinas, Jiri Kosina
Cc: Mark Rutland, Prasanna Kumar T S M, Puranjay Mohan, Song Liu,
joe.lawrence, linux-toolchains, linux-kernel, live-patching,
linux-arm-kernel, Heiko Carstens
In-Reply-To: <20260406185000.1378082-9-dylanbhatch@google.com>
Hello Dylan and Weinan!
On 4/6/2026 8:50 PM, Dylan Hatch wrote:
> Add unwind_next_frame_sframe() function to unwind by sframe info if
> present. Use this method at exception boundaries, falling back to
> frame-pointer unwind only on failure. In such failure cases, the
> stacktrace is considered unreliable.
>
> During normal unwind, prefer frame pointer unwind (for better
> performance) with sframe as a backup.
>
> This change restores the LR behavior originally introduced in commit
> c2c6b27b5aa14fa2 ("arm64: stacktrace: unwind exception boundaries"),
> But later removed in commit 32ed1205682e ("arm64: stacktrace: Skip
> reporting LR at exception boundaries")
>
> This can be done because the sframe data can be used to determine
> whether the LR is current for the PC value recovered from pt_regs at the
> exception boundary.
>
> Signed-off-by: Weinan Liu <wnliu@google.com>
> Signed-off-by: Dylan Hatch <dylanbhatch@google.com>
> Reviewed-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
> diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
> +/*
> + * Unwind to the next frame according to sframe.
> + */
> +static __always_inline int
> +unwind_next_frame_sframe(struct kunwind_state *state)
> +{
> + struct unwind_frame frame;
> + unsigned long cfa, fp, ra;
> + enum kunwind_source source = KUNWIND_SOURCE_FRAME;
> + struct pt_regs *regs = state->regs;
> +
> + int err;
> +
> + /* FP/SP alignment 8 bytes */
> + if (state->common.fp & 0x7 || state->common.sp & 0x7)
> + return -EINVAL;
> +
> + /*
> + * Most/all outermost functions are not visible to sframe. So, check for
> + * a meta frame record if the sframe lookup fails.
> + */
> + err = sframe_find_kernel(state->common.pc, &frame);
> + if (err)
> + return kunwind_next_frame_record_meta(state);
> +
> + if (frame.outermost)
> + return -ENOENT;
> +
> + /* Get the Canonical Frame Address (CFA) */
> + switch (frame.cfa.rule) {
> + case UNWIND_CFA_RULE_SP_OFFSET:
> + cfa = state->common.sp;
> + break;
> + case UNWIND_CFA_RULE_FP_OFFSET:
> + if (state->common.fp < state->common.sp)
> + return -EINVAL;
I wonder whether that check is valid in kernel? Looking at
call_on_irq_stack() saving SP in FP and then loading SP with the IRQ SP.
Is that condition always true then?
> + cfa = state->common.fp;
> + break;
> + case UNWIND_CFA_RULE_REG_OFFSET:
> + case UNWIND_CFA_RULE_REG_OFFSET_DEREF:
> + if (!regs)
if (!regs || frame.cfa.regnum > 30)
> + return -EINVAL;
> + cfa = regs->regs[frame.cfa.regnum];
In unwind user this is guarded by a topmost frame check, as arbitrary
registers are otherwise not available. Isn't this necessary in the
kernel case?
> + break;
> + default:
> + WARN_ON_ONCE(1);
> + return -EINVAL;
> + }
> + cfa += frame.cfa.offset;
> +
> + /*
> + * CFA typically points to a higher address than RA or FP, so don't
> + * consume from the stack when we read it.
> + */
> + if (frame.cfa.rule & UNWIND_RULE_DEREF &&
> + !get_word(&state->common, &cfa))
> + return -EINVAL;
> +
> + /* CFA alignment 8 bytes */
> + if (cfa & 0x7)
> + return -EINVAL;
> +
> + /* Get the Return Address (RA) */
> + switch (frame.ra.rule) {
> + case UNWIND_RULE_RETAIN:
> + if (!regs)
> + return -EINVAL;
> + ra = regs->regs[30];
Likewise: Topmost frame check not required to access arbitrary registers
(including RA/LR)? Furthermore, provided don't have a thinko, LR may
only be in LR in the topmost frame. In any other frame it must have
been saved. Otherwise there would be an endless return loop.
> + source = KUNWIND_SOURCE_REGS_LR;
> + break;
> + /* UNWIND_USER_RULE_CFA_OFFSET not implemented on purpose */
> + case UNWIND_RULE_CFA_OFFSET_DEREF:
> + ra = cfa + frame.ra.offset;
> + break;
> + case UNWIND_RULE_REG_OFFSET:
> + case UNWIND_RULE_REG_OFFSET_DEREF:
> + if (!regs)
if (!regs || frame.cfa.regnum > 30)
> + return -EINVAL;
> + ra = regs->regs[frame.cfa.regnum];
Likewise: Topmost frame check not required to access arbitrary registers?
> + ra += frame.ra.offset;
> + break;
> + default:
> + WARN_ON_ONCE(1);
> + return -EINVAL;
> + }
> +
> + /* Get the Frame Pointer (FP) */
> + switch (frame.fp.rule) {
> + case UNWIND_RULE_RETAIN:
> + fp = state->common.fp;
> + break;
> + /* UNWIND_USER_RULE_CFA_OFFSET not implemented on purpose */
> + case UNWIND_RULE_CFA_OFFSET_DEREF:
> + fp = cfa + frame.fp.offset;
> + break;
> + case UNWIND_RULE_REG_OFFSET:
> + case UNWIND_RULE_REG_OFFSET_DEREF:
> + if (!regs)
if (!regs || frame.cfa.regnum > 30)
> + return -EINVAL;
> + fp = regs->regs[frame.fp.regnum];
Likewise: Topmost frame check not required to access arbitrary registers?
> + fp += frame.fp.offset;
> + break;
> + default:
> + WARN_ON_ONCE(1);
> + return -EINVAL;
> + }
> +
> + /*
> + * Consume RA and FP from the stack. The frame record puts FP at a lower
> + * address than RA, so we always read FP first.
> + */
> + if (frame.fp.rule & UNWIND_RULE_DEREF &&
> + !get_word(&state->common, &fp))
> + return -EINVAL;
> +
> + if (frame.ra.rule & UNWIND_RULE_DEREF &&
> + get_consume_word(&state->common, &ra))
> + return -EINVAL;
> +
> + state->common.pc = ra;
> + state->common.sp = cfa;
> + state->common.fp = fp;
> +
> + state->source = source;
> +
> + return 0;
> +}
Thanks and regards,
Jens
--
Jens Remus
Linux on Z Development (D3303)
jremus@de.ibm.com / jremus@linux.ibm.com
IBM Deutschland Research & Development GmbH; Vorsitzender des Aufsichtsrats: Wolfgang Wendt; Geschäftsführung: David Faller; Sitz der Gesellschaft: Ehningen; Registergericht: Amtsgericht Stuttgart, HRB 243294
IBM Data Privacy Statement: https://www.ibm.com/privacy/
^ permalink raw reply
* Re: [PATCH v2] raid6: arm64: add SVE optimized implementation for syndrome generation
From: Mark Brown @ 2026-04-17 15:36 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Robin Murphy, Demian Shulhan, Christoph Hellwig, Mark Rutland,
Song Liu, Yu Kuai, Will Deacon, Catalin Marinas, linux-arm-kernel,
Li Nan, linux-raid, linux-kernel
In-Reply-To: <c9362db6-1fef-4e70-9525-29b2936f4887@app.fastmail.com>
[-- Attachment #1: Type: text/plain, Size: 1411 bytes --]
On Fri, Apr 17, 2026 at 04:43:06PM +0200, Ard Biesheuvel wrote:
> On arm64, kernel mode NEON is mostly used to gain access to AES and SHA
> instructions, and only to a lesser degree to speed up ordinary
> arithmetic, and so XOR is somewhat of an outlier here.
> Given that Neoverse V1 apparently already carves up ordinary arithmetic
> performed on 256-bit vectors and operates on 128 bits at a time, I am
> rather skeptical that we're likely to see any SVE implementations of the
> crypto extensions soon that are meaningfully faster, given that these
> are presumably much costlier to implement in terms of gate count, and
> therefore likely to be split up even on SVE implementations that can
> perform ordinary arithmetic on 256+ bit vectors in a single cycle. Note
> that even the arm64 SIMD accelerated CRC implementations rely heavily on
> 64x64->128 polynomial multiplication.
I'd not be surprised to see something that delivers useful benefits
using SVE at some point.
> IOW, before we consider kernel mode SVE, I'd like to see some benchmarks
> for other algorithms too.
Definitely, it needs a solid win to merge anything. I do want to get
back to the situation where we've got out of tree infrastructure patches
so that people working on algorithms have something to base their work
on (and see the overheads using SVE incurs) but unless theres's a
practical user they should stay out of tree.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH 15/18] Documentation: KVM: Fix typos in VGICv5 documentation
From: Joey Gouly @ 2026-04-17 15:29 UTC (permalink / raw)
To: Marc Zyngier
Cc: kvmarm, linux-arm-kernel, Suzuki K Poulose, Oliver Upton,
Zenghui Yu, Sascha Bischoff
In-Reply-To: <20260415115559.2227718-16-maz@kernel.org>
On Wed, Apr 15, 2026 at 12:55:56PM +0100, Marc Zyngier wrote:
> From: Sascha Bischoff <sascha.bischoff@arm.com>
>
> Fix two typos in the VGICv5 documentation.
>
> Fixes: d51c978b7d3e ("KVM: arm64: gic-v5: Communicate userspace-driveable PPIs via a UAPI")
> Fixes: eb3c4d2c9a4d ("Documentation: KVM: Introduce documentation for VGICv5")
> Link: https://sashiko.dev/#/patchset/20260319154937.3619520-1-sascha.bischoff%40arm.com
> Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
> Documentation/virt/kvm/devices/arm-vgic-v5.rst | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/virt/kvm/devices/arm-vgic-v5.rst b/Documentation/virt/kvm/devices/arm-vgic-v5.rst
> index 29335ea823fc5..1985b2d880322 100644
> --- a/Documentation/virt/kvm/devices/arm-vgic-v5.rst
> +++ b/Documentation/virt/kvm/devices/arm-vgic-v5.rst
> @@ -12,8 +12,8 @@ Only one VGIC instance may be instantiated through this API. The created VGIC
> will act as the VM interrupt controller, requiring emulated user-space devices
> to inject interrupts to the VGIC instead of directly to CPUs.
>
> -Creating a guest GICv5 device requires a host GICv5 host. The current VGICv5
> -device only supports PPI interrupts. These can either be injected from emulated
> +Creating a guest GICv5 device requires a GICv5 host. The current VGICv5 device
> +only supports PPI interrupts. These can either be injected from emulated
> in-kernel devices (such as the Arch Timer, or PMU), or via the KVM_IRQ_LINE
> ioctl.
>
> @@ -25,7 +25,7 @@ Groups:
> request the initialization of the VGIC, no additional parameter in
> kvm_device_attr.addr. Must be called after all VCPUs have been created.
>
> - KVM_DEV_ARM_VGIC_USERPSPACE_PPIs
> + KVM_DEV_ARM_VGIC_USERPSPACE_PPIS
This still has a typo! There's a P lurking between USER and SPACE!
> request the mask of userspace-drivable PPIs. Only a subset of the PPIs can
> be directly driven from userspace with GICv5, and the returned mask
> informs userspace of which it is allowed to drive via KVM_IRQ_LINE.
> --
> 2.47.3
>
Thanks,
Joey
^ permalink raw reply
* [PATCH net] net: airoha: Fix PPE cpu port configuration for GDM2 loopback path
From: Lorenzo Bianconi @ 2026-04-17 15:24 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Lorenzo Bianconi
Cc: Simon Horman, linux-arm-kernel, linux-mediatek, netdev
When QoS loopback is enabled for GDM3 or GDM4, incoming packets are
forwarded to GDM2. However, the PPE cpu port for GDM2 is not configured
in this path, causing traffic originating from GDM3/GDM4, which may
be set up as WAN ports backed by QDMA1, to be incorrectly directed
to QDMA0 instead.
Configure the PPE cpu port for GDM2 when QoS loopback is active on
GDM3 or GDM4 to ensure traffic is routed to the correct QDMA instance.
Fixes: 9cd451d414f6 ("net: airoha: Add loopback support for GDM2")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 8 ++++++--
drivers/net/ethernet/airoha/airoha_eth.h | 3 ++-
drivers/net/ethernet/airoha/airoha_ppe.c | 6 +++---
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index e1ab15f1ee7d..d2b7c437a782 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -1727,7 +1727,7 @@ static int airoha_set_gdm2_loopback(struct airoha_gdm_port *port)
{
struct airoha_eth *eth = port->qdma->eth;
u32 val, pse_port, chan;
- int src_port;
+ int i, src_port;
/* Forward the traffic to the proper GDM port */
pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3
@@ -1769,6 +1769,9 @@ static int airoha_set_gdm2_loopback(struct airoha_gdm_port *port)
SP_CPORT_MASK(val),
__field_prep(SP_CPORT_MASK(val), FE_PSE_PORT_CDM2));
+ for (i = 0; i < eth->soc->num_ppe; i++)
+ airoha_ppe_set_cpu_port(port, i, AIROHA_GDM2_IDX);
+
if (port->id == AIROHA_GDM4_IDX && airoha_is_7581(eth)) {
u32 mask = FC_ID_OF_SRC_PORT_MASK(port->nbq);
@@ -1807,7 +1810,8 @@ static int airoha_dev_init(struct net_device *dev)
}
for (i = 0; i < eth->soc->num_ppe; i++)
- airoha_ppe_set_cpu_port(port, i);
+ airoha_ppe_set_cpu_port(port, i,
+ airoha_get_fe_port(port));
return 0;
}
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index 95e557638617..715aa26cbac8 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -653,7 +653,8 @@ int airoha_get_fe_port(struct airoha_gdm_port *port);
bool airoha_is_valid_gdm_port(struct airoha_eth *eth,
struct airoha_gdm_port *port);
-void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id);
+void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id,
+ u8 fport);
bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index);
void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
u16 hash, bool rx_wlan);
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index 859818676b69..5c9dff6bccd1 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -85,10 +85,9 @@ static u32 airoha_ppe_get_timestamp(struct airoha_ppe *ppe)
return FIELD_GET(AIROHA_FOE_IB1_BIND_TIMESTAMP, timestamp);
}
-void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id)
+void airoha_ppe_set_cpu_port(struct airoha_gdm_port *port, u8 ppe_id, u8 fport)
{
struct airoha_qdma *qdma = port->qdma;
- u8 fport = airoha_get_fe_port(port);
struct airoha_eth *eth = qdma->eth;
u8 qdma_id = qdma - ð->qdma[0];
u32 fe_cpu_port;
@@ -182,7 +181,8 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
if (!port)
continue;
- airoha_ppe_set_cpu_port(port, i);
+ airoha_ppe_set_cpu_port(port, i,
+ airoha_get_fe_port(port));
}
}
}
---
base-commit: 82c21069028c5db3463f851ae8ac9cc2e38a3827
change-id: 20260417-airoha-ppe-cpu-port-for-gdm2-loopback-96b9b52179c1
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply related
* Re: [PATCH 08/18] KVM: arm64: vgic: Rationalise per-CPU irq accessor
From: Joey Gouly @ 2026-04-17 15:21 UTC (permalink / raw)
To: Marc Zyngier
Cc: kvmarm, linux-arm-kernel, Suzuki K Poulose, Oliver Upton,
Zenghui Yu, Sascha Bischoff
In-Reply-To: <20260415115559.2227718-9-maz@kernel.org>
On Wed, Apr 15, 2026 at 12:55:49PM +0100, Marc Zyngier wrote:
> Despite adding the necessary infrastructure to identify irq types,
> vgic_get_vcpu_irq() treats GICv5 PPIs in a special way, which
> impairs the readability of the code.
>
> Use the existing irq classifiers to handle per-CPU irqs for all
> vgic types, and let the normal control flow reach global interrupt
> handling without any v5-specific path.
>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
> arch/arm64/kvm/vgic/vgic.c | 25 ++++++++++++-------------
> 1 file changed, 12 insertions(+), 13 deletions(-)
>
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index 3ac6d49bc4876..b697678d68b01 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -106,24 +106,23 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid)
>
> struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid)
> {
> + enum kvm_device_type type;
> +
> if (WARN_ON(!vcpu))
> return NULL;
>
> - if (vgic_is_v5(vcpu->kvm)) {
> - u32 int_num, hwirq_id;
> -
> - if (!__irq_is_ppi(KVM_DEV_TYPE_ARM_VGIC_V5, intid))
> - return NULL;
> -
> - hwirq_id = FIELD_GET(GICV5_HWIRQ_ID, intid);
> - int_num = array_index_nospec(hwirq_id, VGIC_V5_NR_PRIVATE_IRQS);
> + type = vcpu->kvm->arch.vgic.vgic_model;
>
> - return &vcpu->arch.vgic_cpu.private_irqs[int_num];
> - }
> + if (__irq_is_sgi(type, intid) || __irq_is_ppi(type, intid)) {
> + switch (type) {
> + case KVM_DEV_TYPE_ARM_VGIC_V5:
> + intid = vgic_v5_get_hwirq_id(intid);
> + intid = array_index_nospec(intid, VGIC_V5_NR_PRIVATE_IRQS);
> + break;
> + default:
> + intid = array_index_nospec(intid, VGIC_NR_PRIVATE_IRQS);
> + }
>
> - /* SGIs and PPIs */
> - if (intid < VGIC_NR_PRIVATE_IRQS) {
> - intid = array_index_nospec(intid, VGIC_NR_PRIVATE_IRQS);
> return &vcpu->arch.vgic_cpu.private_irqs[intid];
> }
>
It preserves the behaviour of returning NULL for anything other than PPI on
gic-v5, because the fallthrough to vgic_get_irq() returns NULL for gic-v5 and
__irq_is_sgi() is always false for gic-v5.
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Thanks,
Joey
^ permalink raw reply
* [PATCH RFC 4/4] clk: rockchip: rk3576: add ROUND_CLOSEST to dclk_vp1_src divider
From: Alexey Charkov @ 2026-04-17 15:11 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Michael Turquette, Stephen Boyd
Cc: Pavel Zhovner, Sebastian Reichel, Andy Yan, devicetree,
linux-arm-kernel, linux-rockchip, linux-kernel, linux-clk,
Alexey Charkov
In-Reply-To: <20260417-rk3576-dclk-v1-0-26a9d0dcb2de@flipper.net>
Without CLK_DIVIDER_ROUND_CLOSEST, the divider's _is_best_div() only
considers candidates where now <= target, rejecting any rate above the
target even when it is closer. Combined with the PLL round-nearest fix,
this causes the divider to still pick a suboptimal rate: with PLL
round-nearest alone, div=8 produces 249.0 MHz (0.048% over) but is
rejected because it exceeds the target, and div=3/248.0 MHz wins
(-0.354% error).
Add CLK_DIVIDER_ROUND_CLOSEST to dclk_vp1_src's div_flags so the
divider picks the rate closest to the target regardless of direction.
Together with the PLL round-nearest change, this yields:
VPLL 1992 MHz / 8 = 249.0 MHz (+0.048% error)
instead of the previous:
VPLL 1488 MHz / 6 = 248.0 MHz (-0.354% error)
This small difference appears to enable more monitors to lock to the VP1
clock when driving output at 2560x1440@60Hz via DisplayPort.
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/clk/rockchip/clk-rk3576.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/clk/rockchip/clk-rk3576.c b/drivers/clk/rockchip/clk-rk3576.c
index 28eb5a802e83..9fc3264ef322 100644
--- a/drivers/clk/rockchip/clk-rk3576.c
+++ b/drivers/clk/rockchip/clk-rk3576.c
@@ -1106,7 +1106,7 @@ static struct rockchip_clk_branch rk3576_clk_branches[] __initdata = {
RK3576_CLKSEL_CON(145), 8, 3, MFLAGS, 0, 8, DFLAGS,
RK3576_CLKGATE_CON(61), 10, GFLAGS),
COMPOSITE(DCLK_VP1_SRC, "dclk_vp1_src", gpll_cpll_vpll_bpll_lpll_p, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
- RK3576_CLKSEL_CON(146), 8, 3, MFLAGS, 0, 8, DFLAGS,
+ RK3576_CLKSEL_CON(146), 8, 3, MFLAGS, 0, 8, DFLAGS | CLK_DIVIDER_ROUND_CLOSEST,
RK3576_CLKGATE_CON(61), 11, GFLAGS),
COMPOSITE(DCLK_VP2_SRC, "dclk_vp2_src", gpll_cpll_vpll_bpll_lpll_p, CLK_SET_RATE_NO_REPARENT,
RK3576_CLKSEL_CON(147), 8, 3, MFLAGS, 0, 8, DFLAGS,
--
2.52.0
^ permalink raw reply related
* [PATCH RFC 3/4] clk: rockchip: rk3576: allow dclk_vp1_src to propagate rate to parent PLL
From: Alexey Charkov @ 2026-04-17 15:11 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Michael Turquette, Stephen Boyd
Cc: Pavel Zhovner, Sebastian Reichel, Andy Yan, devicetree,
linux-arm-kernel, linux-rockchip, linux-kernel, linux-clk,
Alexey Charkov
In-Reply-To: <20260417-rk3576-dclk-v1-0-26a9d0dcb2de@flipper.net>
dclk_vp1_src feeds the display clock for Video Port 1. When parented to
the default GPLL (1188 MHz), the 8-bit divider cannot synthesize the
248.88 MHz pixel clock required for 2560x1440@60 which VP1 supports:
1188 / 5 = 237.6 MHz (-4.53% error). This exceeds DisplayPort's +/-0.5%
tolerance and causes black screens on strict sinks.
Add CLK_SET_RATE_PARENT so that when dclk_vp1_src is reparented to a
programmable PLL (e.g. VPLL via assigned-clock-parents), the CCF divider
can ask the PLL to retune. For example, VPLL at 1992 MHz / 8 = 249 MHz
(0.048% error).
This flag relies on reparenting the VP1 source clock to VPLL at DT level
to ensure no consumer calls clk_set_rate on dclk_vp1 while its parent is
set to the boot-time default of GPLL.
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/clk/rockchip/clk-rk3576.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/clk/rockchip/clk-rk3576.c b/drivers/clk/rockchip/clk-rk3576.c
index 2557358e0b9d..28eb5a802e83 100644
--- a/drivers/clk/rockchip/clk-rk3576.c
+++ b/drivers/clk/rockchip/clk-rk3576.c
@@ -1105,7 +1105,7 @@ static struct rockchip_clk_branch rk3576_clk_branches[] __initdata = {
COMPOSITE(DCLK_VP0_SRC, "dclk_vp0_src", gpll_cpll_vpll_bpll_lpll_p, CLK_SET_RATE_NO_REPARENT,
RK3576_CLKSEL_CON(145), 8, 3, MFLAGS, 0, 8, DFLAGS,
RK3576_CLKGATE_CON(61), 10, GFLAGS),
- COMPOSITE(DCLK_VP1_SRC, "dclk_vp1_src", gpll_cpll_vpll_bpll_lpll_p, CLK_SET_RATE_NO_REPARENT,
+ COMPOSITE(DCLK_VP1_SRC, "dclk_vp1_src", gpll_cpll_vpll_bpll_lpll_p, CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
RK3576_CLKSEL_CON(146), 8, 3, MFLAGS, 0, 8, DFLAGS,
RK3576_CLKGATE_CON(61), 11, GFLAGS),
COMPOSITE(DCLK_VP2_SRC, "dclk_vp2_src", gpll_cpll_vpll_bpll_lpll_p, CLK_SET_RATE_NO_REPARENT,
--
2.52.0
^ permalink raw reply related
* [PATCH RFC 2/4] clk: rockchip: pll: use round-nearest in determine_rate
From: Alexey Charkov @ 2026-04-17 15:11 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Michael Turquette, Stephen Boyd
Cc: Pavel Zhovner, Sebastian Reichel, Andy Yan, devicetree,
linux-arm-kernel, linux-rockchip, linux-kernel, linux-clk,
Alexey Charkov
In-Reply-To: <20260417-rk3576-dclk-v1-0-26a9d0dcb2de@flipper.net>
rockchip_pll_determine_rate() walks the rate table in descending order
and picks the first entry <= the requested rate. This floor-rounding
interacts poorly with consumers that use CLK_SET_RATE_PARENT: a divider
iterating candidates asks the PLL for rate*div, and a tiny undershoot
causes the PLL to snap to a much lower entry.
For example, requesting 1991.04 MHz (248.88 MHz * 8) causes the PLL to
return 1968 MHz instead of 1992 MHz — a 24 MHz table gap that produces
a 1.2% pixel clock error when divided back down.
Change to round-to-nearest: for each table entry compute the absolute
distance from the request, and pick the entry with the smallest delta.
The CCF's divider and composite logic handle over/undershoot preferences
via their own ROUND_CLOSEST flags.
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/clk/rockchip/clk-pll.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 6b853800cb6b..c142f2c4fd99 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -66,19 +66,19 @@ static int rockchip_pll_determine_rate(struct clk_hw *hw,
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
const struct rockchip_pll_rate_table *rate_table = pll->rate_table;
+ unsigned long best = 0;
int i;
- /* Assuming rate_table is in descending order */
for (i = 0; i < pll->rate_count; i++) {
- if (req->rate >= rate_table[i].rate) {
- req->rate = rate_table[i].rate;
-
- return 0;
- }
+ if (abs((long)req->rate - (long)rate_table[i].rate) <
+ abs((long)req->rate - (long)best))
+ best = rate_table[i].rate;
}
- /* return minimum supported value */
- req->rate = rate_table[i - 1].rate;
+ if (best)
+ req->rate = best;
+ else
+ req->rate = rate_table[pll->rate_count - 1].rate;
return 0;
}
--
2.52.0
^ 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