From 5b7f39687b173f042cb9530bcee5f5805020bffd Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 25 Mar 2026 00:43:49 +0800 Subject: [PATCH 1/7] dt-bindings: sram: Document Allwinner H616 VE SRAM The Allwinner H616 has two switchable peripheral SRAM regions: - The VE SRAM is a 2 MB dedicated SRAM for the Video Engine. CPU access to this region is enabled by default. CPU access can be disabled, after which reads will show the same stale value for all addresses, while writes are ignored. The mux value for this region is different from previous generations, and thus needs a completely new compatible. - The SRAM C region is an alias of the first 128 KB of VE SRAM, plus 64 KB of DE SRAM. The latter is otherwise unaccessible from the CPU. When CPU access is disabled, the whole region reads as zero, while writes are ignored. The mux value for this region is the same as on the A64 and H6. The existing compatible for the A64 already covers this. Add the compatible for the VE SRAM to the list of covered compatibles in the generic SRAM region binding. Acked-by: Rob Herring (Arm) Acked-by: Jernej Skrabec Link: https://patch.msgid.link/20260324164357.1607247-2-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- Documentation/devicetree/bindings/sram/sram.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sram/sram.yaml b/Documentation/devicetree/bindings/sram/sram.yaml index 8985f89170be..9019c43d37a6 100644 --- a/Documentation/devicetree/bindings/sram/sram.yaml +++ b/Documentation/devicetree/bindings/sram/sram.yaml @@ -83,6 +83,7 @@ patternProperties: - allwinner,sun4i-a10-sram-d - allwinner,sun9i-a80-smp-sram - allwinner,sun50i-a64-sram-c + - allwinner,sun50i-h616-ve-sram - amlogic,meson8-ao-arc-sram - amlogic,meson8b-ao-arc-sram - amlogic,meson8-smp-sram From 775c75e4ae2b0277b5e55644f9890afef4dedee9 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 25 Mar 2026 00:43:50 +0800 Subject: [PATCH 2/7] dt-bindings: sram: sunxi-sram: Add H616 SRAM regions The Allwinner H616 has two switchable peripheral SRAM regions: - The VE SRAM is a 2 MB dedicated SRAM for the Video Engine. CPU access to this region is enabled by default. CPU access can be disabled, after which reads will show the same stale value for all addresses, while writes are ignored. The mux value for this region is different from previous generations. - The SRAM C region is an alias of the first 128 KB of VE SRAM, plus 64 KB of DE SRAM. The latter is otherwise unaccessible from the CPU. When CPU access is disabled, the whole region reads as zero, while writes are ignored. The mux value for this region is the same as on the A64 and H6. Add compatible strings for both of them. Acked-by: Rob Herring (Arm) Acked-by: Jernej Skrabec Link: https://patch.msgid.link/20260324164357.1607247-3-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- .../bindings/sram/allwinner,sun4i-a10-system-control.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml b/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml index e7f7cf72719e..6e6ab2168a2a 100644 --- a/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml +++ b/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml @@ -80,6 +80,7 @@ patternProperties: - const: allwinner,sun4i-a10-sram-c1 - const: allwinner,sun4i-a10-sram-d - const: allwinner,sun50i-a64-sram-c + - const: allwinner,sun50i-h616-ve-sram - items: - enum: - allwinner,sun5i-a13-sram-a3-a4 @@ -103,7 +104,9 @@ patternProperties: - allwinner,sun7i-a20-sram-d - const: allwinner,sun4i-a10-sram-d - items: - - const: allwinner,sun50i-h6-sram-c + - enum: + - allwinner,sun50i-h6-sram-c + - allwinner,sun50i-h616-sram-c - const: allwinner,sun50i-a64-sram-c required: From 7765752f528b5b516d8cdf94faaabcba935dff41 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 25 Mar 2026 00:43:51 +0800 Subject: [PATCH 3/7] soc: sunxi: sram: Const-ify sunxi_sram_func data and references sunxi_sram_func contains value mapping that do not change at runtime. Const-ify them. Reviewed-by: Jernej Skrabec Link: https://patch.msgid.link/20260324164357.1607247-4-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- drivers/soc/sunxi/sunxi_sram.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index 446b9fc1f175..5e8c80ae3509 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -29,11 +29,11 @@ struct sunxi_sram_func { }; struct sunxi_sram_data { - char *name; - u8 reg; - u8 offset; - u8 width; - struct sunxi_sram_func *func; + char *name; + u8 reg; + u8 offset; + u8 width; + const struct sunxi_sram_func *func; }; struct sunxi_sram_desc { @@ -54,7 +54,7 @@ struct sunxi_sram_desc { .reg = _reg, \ .offset = _off, \ .width = _width, \ - .func = (struct sunxi_sram_func[]){ \ + .func = (const struct sunxi_sram_func[]){ \ __VA_ARGS__, { } }, \ } @@ -111,7 +111,7 @@ static int sunxi_sram_show(struct seq_file *s, void *data) struct device_node *sram_node, *section_node; const struct sunxi_sram_data *sram_data; const struct of_device_id *match; - struct sunxi_sram_func *func; + const struct sunxi_sram_func *func; const __be32 *sram_addr_p, *section_addr_p; u32 val; @@ -169,7 +169,7 @@ static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *nod { const struct of_device_id *match; const struct sunxi_sram_data *data; - struct sunxi_sram_func *func; + const struct sunxi_sram_func *func; struct of_phandle_args args; u8 val; int ret; From 67890da74dd1b85a47769561bfc6e0c542762d45 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 25 Mar 2026 00:43:52 +0800 Subject: [PATCH 4/7] soc: sunxi: sram: Allow SRAM to be claimed multiple times On the H616, the SRAM C region is an alias mapping to part of the VE SRAM (accessible in whole at a different address) and part of the DE SRAM (otherwise unaccessible). As such both the VE and DE need to claim this SRAM region to prevent access from the CPU. The SRAM claim API is designed so that a "claim" routes the SRAM to the peripheral device, disabling access from the CPU. So long as the written register value is the same for all the claimants involved, allowing multiple or repeated claims is trivial. This is indeed the case for all supported SRAM regions. The only known SRAM region to have multiple different settings is the SRAM C2 region; this can be claimed by the AE, CE, or ACE (assumed to be AE + CE). This region is not supported, and likely will never be needed nor supported, as there is no documentation for the peripherals involved. Change the SRAM region "claimed" field from a boolean to a reference count. A claim will increment the count, while a release decreases it. The first claim will trigger the register value write. The driver otherwise behaves as before. Reviewed-by: Jernej Skrabec Link: https://patch.msgid.link/20260324164357.1607247-5-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- drivers/soc/sunxi/sunxi_sram.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index 5e8c80ae3509..aba155379ccc 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -38,7 +39,7 @@ struct sunxi_sram_data { struct sunxi_sram_desc { struct sunxi_sram_data data; - bool claimed; + u8 claim_cnt; }; #define SUNXI_SRAM_MAP(_reg_val, _val, _func) \ @@ -244,9 +245,11 @@ int sunxi_sram_claim(struct device *dev) spin_lock(&sram_lock); - if (sram_desc->claimed) { + if (sram_desc->claim_cnt) { + if (!WARN_ON(sram_desc->claim_cnt == U8_MAX)) + sram_desc->claim_cnt++; spin_unlock(&sram_lock); - return -EBUSY; + return 0; } mask = GENMASK(sram_data->offset + sram_data->width - 1, @@ -256,7 +259,7 @@ int sunxi_sram_claim(struct device *dev) writel(val | ((device << sram_data->offset) & mask), base + sram_data->reg); - sram_desc->claimed = true; + sram_desc->claim_cnt++; spin_unlock(&sram_lock); return 0; @@ -278,7 +281,8 @@ void sunxi_sram_release(struct device *dev) sram_desc = to_sram_desc(sram_data); spin_lock(&sram_lock); - sram_desc->claimed = false; + if (!WARN_ON(sram_desc->claim_cnt == 0)) + sram_desc->claim_cnt--; spin_unlock(&sram_lock); } EXPORT_SYMBOL(sunxi_sram_release); From be99eb936b4ffffbf87d34c4a202e15c05b30417 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 25 Mar 2026 00:43:53 +0800 Subject: [PATCH 5/7] soc: sunxi: sram: Support claiming multiple regions per device On the H616, the video engine needs to claim two SRAM regions. Support claiming multiple regions per device. Reviewed-by: Jernej Skrabec Link: https://patch.msgid.link/20260324164357.1607247-6-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- drivers/soc/sunxi/sunxi_sram.c | 164 +++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 68 deletions(-) diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index aba155379ccc..4d81897179e7 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -165,79 +165,48 @@ static inline struct sunxi_sram_desc *to_sram_desc(const struct sunxi_sram_data return container_of(data, struct sunxi_sram_desc, data); } -static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *node, - unsigned int *reg_value) +static const struct sunxi_sram_data *sunxi_sram_get_match(struct device_node *np, u8 val, + unsigned int *reg_value) { const struct of_device_id *match; const struct sunxi_sram_data *data; const struct sunxi_sram_func *func; - struct of_phandle_args args; - u8 val; - int ret; - ret = of_parse_phandle_with_fixed_args(node, "allwinner,sram", 1, 0, - &args); - if (ret) - return ERR_PTR(ret); + if (!of_device_is_available(np)) + return ERR_PTR(-ENODEV); - if (!of_device_is_available(args.np)) { - ret = -EBUSY; - goto err; - } - - val = args.args[0]; - - match = of_match_node(sunxi_sram_dt_ids, args.np); - if (!match) { - ret = -EINVAL; - goto err; - } + match = of_match_node(sunxi_sram_dt_ids, np); + if (!match) + return ERR_PTR(-ENODEV); data = match->data; - if (!data) { - ret = -EINVAL; - goto err; - } - - for (func = data->func; func->func; func++) { - if (val == func->val) { - if (reg_value) - *reg_value = func->reg_val; + if (!data) + return ERR_PTR(-EINVAL); + for (func = data->func; func->func; func++) + if (val == func->val) break; - } - } - if (!func->func) { - ret = -EINVAL; - goto err; - } + if (!func->func) + return ERR_PTR(-EINVAL); - of_node_put(args.np); - return match->data; + if (reg_value) + *reg_value = func->reg_val; -err: - of_node_put(args.np); - return ERR_PTR(ret); + return data; } -int sunxi_sram_claim(struct device *dev) +#define SUNXI_SRAM_PROP "allwinner,sram" +#define SUNXI_SRAM_CELLS 1 + +static int sunxi_sram_claim_one(struct device_node *np, u8 arg) { const struct sunxi_sram_data *sram_data; struct sunxi_sram_desc *sram_desc; unsigned int device; u32 val, mask; - if (IS_ERR(base)) - return PTR_ERR(base); - - if (!base) - return -EPROBE_DEFER; - - if (!dev || !dev->of_node) - return -EINVAL; - - sram_data = sunxi_sram_of_parse(dev->of_node, &device); + sram_data = sunxi_sram_get_match(np, arg, &device); if (IS_ERR(sram_data)) return PTR_ERR(sram_data); @@ -248,33 +217,28 @@ int sunxi_sram_claim(struct device *dev) if (sram_desc->claim_cnt) { if (!WARN_ON(sram_desc->claim_cnt == U8_MAX)) sram_desc->claim_cnt++; - spin_unlock(&sram_lock); - return 0; + } else { + mask = GENMASK(sram_data->offset + sram_data->width - 1, + sram_data->offset); + val = readl(base + sram_data->reg); + val &= ~mask; + writel(val | ((device << sram_data->offset) & mask), + base + sram_data->reg); + + sram_desc->claim_cnt++; } - mask = GENMASK(sram_data->offset + sram_data->width - 1, - sram_data->offset); - val = readl(base + sram_data->reg); - val &= ~mask; - writel(val | ((device << sram_data->offset) & mask), - base + sram_data->reg); - - sram_desc->claim_cnt++; spin_unlock(&sram_lock); return 0; } -EXPORT_SYMBOL(sunxi_sram_claim); -void sunxi_sram_release(struct device *dev) +static void sunxi_sram_release_one(struct device_node *np, u8 arg) { const struct sunxi_sram_data *sram_data; struct sunxi_sram_desc *sram_desc; - if (!dev || !dev->of_node) - return; - - sram_data = sunxi_sram_of_parse(dev->of_node, NULL); + sram_data = sunxi_sram_get_match(np, arg, NULL); if (IS_ERR(sram_data)) return; @@ -285,6 +249,70 @@ void sunxi_sram_release(struct device *dev) sram_desc->claim_cnt--; spin_unlock(&sram_lock); } + +int sunxi_sram_claim(struct device *dev) +{ + struct of_phandle_iterator it; + int err; + int count = 0; + + if (IS_ERR(base)) + return PTR_ERR(base); + + if (!base) + return -EPROBE_DEFER; + + if (!dev || !dev->of_node) + return -EINVAL; + + of_for_each_phandle(&it, err, dev->of_node, SUNXI_SRAM_PROP, + NULL, SUNXI_SRAM_CELLS) { + u32 args[SUNXI_SRAM_CELLS]; + + of_phandle_iterator_args(&it, args, SUNXI_SRAM_CELLS); + + err = sunxi_sram_claim_one(it.node, args[0]); + if (err) + goto err; + + count++; + } + + if (count == 0) + return -ENOENT; + + return 0; + +err: + while (count--) { + struct of_phandle_args args; + + of_parse_phandle_with_fixed_args(dev->of_node, SUNXI_SRAM_PROP, + SUNXI_SRAM_CELLS, count, &args); + sunxi_sram_release_one(args.np, args.args[0]); + } + + return err; +} +EXPORT_SYMBOL(sunxi_sram_claim); + +void sunxi_sram_release(struct device *dev) +{ + struct of_phandle_iterator it; + int err; + + if (!dev || !dev->of_node) + return; + + of_for_each_phandle(&it, err, dev->of_node, SUNXI_SRAM_PROP, + NULL, SUNXI_SRAM_CELLS) { + u32 args[SUNXI_SRAM_CELLS]; + + of_phandle_iterator_args(&it, args, SUNXI_SRAM_CELLS); + + sunxi_sram_release_one(it.node, args[0]); + } +} EXPORT_SYMBOL(sunxi_sram_release); struct sunxi_sramc_variant { From b708294322745ce30035d960a1118b4b8d857120 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 25 Mar 2026 00:43:54 +0800 Subject: [PATCH 6/7] soc: sunxi: sram: Add H616 SRAM regions The Allwinner H616 has two switchable peripheral SRAM regions: - The VE SRAM is a 2 MB dedicated SRAM for the Video Engine. CPU access to this region is enabled by default. CPU access can be disabled, after which reads will show the same stale value for all addresses, while writes are ignored. The mux value for this region is different from previous generations. - The SRAM C region is an alias of the first 128 KB of VE SRAM, plus 64 KB of DE SRAM. The latter is otherwise unaccessible from the CPU. When CPU access is disabled, the whole region reads as zero, while writes are ignored. The mux value for this region is the same as on the A64 and H6. Add data for the VE SRAM. The register values were taken from the BSP vendor kernel. Reviewed-by: Jernej Skrabec Link: https://patch.msgid.link/20260324164357.1607247-7-wens@kernel.org Signed-off-by: Chen-Yu Tsai --- drivers/soc/sunxi/sunxi_sram.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index 4d81897179e7..2ccaeacf8c70 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -83,6 +83,12 @@ static struct sunxi_sram_desc sun50i_a64_sram_c = { SUNXI_SRAM_MAP(0, 1, "de2")), }; +static struct sunxi_sram_desc sun50i_h616_ve_sram = { + .data = SUNXI_SRAM_DATA("VE", 0x0, 0, 1, + SUNXI_SRAM_MAP(1, 0, "cpu"), + SUNXI_SRAM_MAP(0, 1, "ve")), +}; + static const struct of_device_id sunxi_sram_dt_ids[] = { { .compatible = "allwinner,sun4i-a10-sram-a3-a4", @@ -100,6 +106,10 @@ static const struct of_device_id sunxi_sram_dt_ids[] = { .compatible = "allwinner,sun50i-a64-sram-c", .data = &sun50i_a64_sram_c.data, }, + { + .compatible = "allwinner,sun50i-h616-ve-sram", + .data = &sun50i_h616_ve_sram.data, + }, {} }; From 61192938a5870ac36edae81e4775b680dcf02c61 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 1 Mar 2026 17:49:39 +0300 Subject: [PATCH 7/7] bus: sunxi-rsb: Always check register address validity The register address was already validated for read operations in regmap_sunxi_rsb_reg_read before being truncated to a u8. Write operations have the same set of possible addresses, and the address is being truncated from u32 to u8 here as well, so the same check is needed. Signed-off-by: Samuel Holland Signed-off-by: Andrey Skvortsov Fixes: d787dcdb9c8f ("bus: sunxi-rsb: Add driver for Allwinner Reduced Serial Bus") Reviewed-by: Chen-Yu Tsai Reviewed-by: Jernej Skrabec Link: https://patch.msgid.link/20260301144939.1832806-1-andrej.skvortzov@gmail.com Signed-off-by: Chen-Yu Tsai --- drivers/bus/sunxi-rsb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index b4f2c64ac181..daf0ea563e47 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -445,6 +445,9 @@ static int regmap_sunxi_rsb_reg_write(void *context, unsigned int reg, struct sunxi_rsb_ctx *ctx = context; struct sunxi_rsb_device *rdev = ctx->rdev; + if (reg > 0xff) + return -EINVAL; + return sunxi_rsb_write(rdev->rsb, rdev->rtaddr, reg, &val, ctx->size); }