* [PATCH v3 1/3] dt-bindings: arm: cpus: Add brcm,bca-smp enable method
2026-10-21 15:09 [PATCH v3 0/3] ARM: bcm: Enable CFE SMP on BCMBCA Linus Walleij
@ 2026-10-21 15:09 ` Linus Walleij
2026-10-21 15:09 ` [PATCH v3 2/3] ARM: bcm: Add CFE SMP support for BCMBCA Linus Walleij
2026-10-21 15:09 ` [PATCH v3 3/3] ARM: dts: broadcom: Use CFE CPU bring-up on the XG6846B Linus Walleij
2 siblings, 0 replies; 5+ messages in thread
From: Linus Walleij @ 2026-10-21 15:09 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Lorenzo Pieralisi,
Florian Fainelli, Broadcom internal kernel review list,
Russell King, William Zhang, Anand Gore, Kursad Oney,
Rafał Miłecki
Cc: devicetree, linux-arm-kernel, Linus Walleij
BCMBCA systems booted through CFE can release a secondary CPU by
writing its ARM-state entry address to a 32-bit MMIO mailbox and
sending a wakeup interrupt.
Document brcm,bca-smp and its single-cell cpu-release-addr property.
The boot CPU does not need a mailbox; secondary CPUs do. Add a
Cortex-A7 example showing both CPU nodes.
Suggested-by: William Zhang <william.zhang@broadcom.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
Documentation/devicetree/bindings/arm/cpus.yaml | 36 +++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml
index 5be89c584026..6771b85f757b 100644
--- a/Documentation/devicetree/bindings/arm/cpus.yaml
+++ b/Documentation/devicetree/bindings/arm/cpus.yaml
@@ -255,6 +255,7 @@ properties:
- amlogic,meson8b-smp
- arm,realview-smp
- aspeed,ast2600-smp
+ - brcm,bca-smp
- brcm,bcm11351-cpu-method
- brcm,bcm23550
- brcm,bcm2836-smp
@@ -471,6 +472,20 @@ allOf:
then:
required:
- secondary-boot-reg
+ - if:
+ properties:
+ enable-method:
+ const: brcm,bca-smp
+ required:
+ - enable-method
+ then:
+ properties:
+ cpu-release-addr:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Physical address of the 32-bit MMIO mailbox read by CFE after
+ a wakeup interrupt. Required on secondary CPUs. The kernel
+ writes the ARM-state entry address before sending the interrupt.
- if:
properties:
enable-method:
@@ -712,4 +727,25 @@ examples:
cpu-release-addr = <0 0x20000000>;
};
};
+ - |
+ // Example 5 (Broadcom BCMBCA with CFE):
+ cpus {
+ #size-cells = <0>;
+ #address-cells = <1>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0>;
+ enable-method = "brcm,bca-smp";
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <1>;
+ enable-method = "brcm,bca-smp";
+ cpu-release-addr = <0xff800568>;
+ };
+ };
...
--
2.56.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v3 2/3] ARM: bcm: Add CFE SMP support for BCMBCA
2026-10-21 15:09 [PATCH v3 0/3] ARM: bcm: Enable CFE SMP on BCMBCA Linus Walleij
2026-10-21 15:09 ` [PATCH v3 1/3] dt-bindings: arm: cpus: Add brcm,bca-smp enable method Linus Walleij
@ 2026-10-21 15:09 ` Linus Walleij
2026-10-21 15:09 ` [PATCH v3 3/3] ARM: dts: broadcom: Use CFE CPU bring-up on the XG6846B Linus Walleij
2 siblings, 0 replies; 5+ messages in thread
From: Linus Walleij @ 2026-10-21 15:09 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Lorenzo Pieralisi,
Florian Fainelli, Broadcom internal kernel review list,
Russell King, William Zhang, Anand Gore, Kursad Oney,
Rafał Miłecki
Cc: devicetree, linux-arm-kernel, Linus Walleij
The XG6846B CFE bootloader powers up CPU1 and leaves it in a holding pen
waiting for an interrupt. After waking, the stub reads the GPIO
GeneralPurpose register at 0xff800568 and branches to the stored address
in ARM state. The vendor kernel uses this mailbox and a wakeup IPI.
Implement the brcm,bca-smp CPU enable-method for BCMBCA systems
booted through CFE.
Read the mailbox address from the secondary CPU's cpu-release-addr
property. Map it as device memory, write secondary_startup_arm and
complete the write before sending the wakeup IPI. CPU1 is already
running, so no power or reset sequence is needed. Using the ARM entry
also supports kernels built in Thumb-2 mode. Clear any Thumb function
pointer tag before programming this ARM entry address.
Register the operations with CPU_METHOD_OF_DECLARE() so the CPU
nodes select CFE bring-up explicitly. Build the BCMBCA machine
description independently of DEBUG_BCMBCA, keeping the debug UART
mapping conditional. The generic ARM startup code retains PSCI priority.
Suggested-by: William Zhang <william.zhang@broadcom.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
arch/arm/mach-bcm/Makefile | 2 +-
arch/arm/mach-bcm/board_bcmbca.c | 56 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index 6baedf4c6304..fcc4e0174adc 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -58,6 +58,6 @@ endif
# BCMBCA
ifeq ($(CONFIG_ARCH_BCMBCA),y)
-obj-$(CONFIG_DEBUG_BCMBCA) += board_bcmbca.o
+obj-y += board_bcmbca.o
obj-$(CONFIG_SMP) += bcm63xx_smp.o bcm63xx_pmb.o
endif
diff --git a/arch/arm/mach-bcm/board_bcmbca.c b/arch/arm/mach-bcm/board_bcmbca.c
index b510d959870a..248b8bd77645 100644
--- a/arch/arm/mach-bcm/board_bcmbca.c
+++ b/arch/arm/mach-bcm/board_bcmbca.c
@@ -1,9 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2024 Linus Walleij <linus.walleij@linaro.org>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/smp.h>
+
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
+#include <asm/smp_plat.h>
+#ifdef CONFIG_DEBUG_BCMBCA
/* This is needed for LL-debug/earlyprintk/debug-macro.S */
static struct map_desc bcmbca_io_desc[] __initdata = {
{
@@ -13,12 +19,62 @@ static struct map_desc bcmbca_io_desc[] __initdata = {
.type = MT_DEVICE,
},
};
+#endif
static void __init bcmbca_map_io(void)
{
+#ifdef CONFIG_DEBUG_BCMBCA
iotable_init(bcmbca_io_desc, ARRAY_SIZE(bcmbca_io_desc));
+#endif
}
+#ifdef CONFIG_SMP
+static int bcmbca_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ struct device_node *np;
+ void __iomem *mailbox;
+ u32 release_addr;
+ int ret;
+
+ /* CFE has already powered up CPU1 and left it waiting in WFI. */
+ if (cpu_logical_map(cpu) != 1)
+ return -EINVAL;
+
+ np = of_get_cpu_node(cpu, NULL);
+ if (!np)
+ return -ENODEV;
+
+ ret = of_property_read_u32(np, "cpu-release-addr", &release_addr);
+ of_node_put(np);
+ if (ret) {
+ pr_err("CPU%u: missing or invalid cpu-release-addr property\n", cpu);
+ return ret;
+ }
+
+ mailbox = ioremap(release_addr, sizeof(u32));
+ if (!mailbox)
+ return -ENOMEM;
+
+ /*
+ * The CFE stub reads GPIO GeneralPurpose after an interrupt and
+ * branches to it in ARM state. Clear any Thumb function pointer
+ * tag and complete the MMIO write before sending the wakeup IPI.
+ */
+ writel(__pa_symbol(secondary_startup_arm) & ~1, mailbox);
+ dsb(sy);
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+ iounmap(mailbox);
+
+ return 0;
+}
+
+static const struct smp_operations bcmbca_smp_ops __initconst = {
+ .smp_boot_secondary = bcmbca_boot_secondary,
+};
+
+CPU_METHOD_OF_DECLARE(bcmbca_smp, "brcm,bca-smp", &bcmbca_smp_ops);
+#endif
+
static const char * const bcmbca_dt_compat[] = {
/* TODO: Add other BCMBCA SoCs here to get debug UART support */
"brcm,bcm6846",
--
2.56.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v3 3/3] ARM: dts: broadcom: Use CFE CPU bring-up on the XG6846B
2026-10-21 15:09 [PATCH v3 0/3] ARM: bcm: Enable CFE SMP on BCMBCA Linus Walleij
2026-10-21 15:09 ` [PATCH v3 1/3] dt-bindings: arm: cpus: Add brcm,bca-smp enable method Linus Walleij
2026-10-21 15:09 ` [PATCH v3 2/3] ARM: bcm: Add CFE SMP support for BCMBCA Linus Walleij
@ 2026-10-21 15:09 ` Linus Walleij
2026-10-21 15:29 ` sashiko-bot
2 siblings, 1 reply; 5+ messages in thread
From: Linus Walleij @ 2026-10-21 15:09 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Lorenzo Pieralisi,
Florian Fainelli, Broadcom internal kernel review list,
Russell King, William Zhang, Anand Gore, Kursad Oney,
Rafał Miłecki
Cc: devicetree, linux-arm-kernel, Linus Walleij
The XG6846B boots through CFE, which parks CPU1 in a holding pen and does
not provide PSCI. Starting Linux from CFE does not install a PSCI
implementation either. The working PSCI interface in newer GenXOS
firmware belongs to a different boot stack.
Disable the inherited PSCI node on this board so Linux does not issue
SMCs to an interface that is absent. Set the CPUs' enable-method to
brcm,bca-smp to select the BCMBCA CFE SMP operations. Describe the CFE
mailbox in CPU1's cpu-release-addr property. Keep both CPU nodes enabled
and leave the SoC's PSCI defaults available to other boards.
Also remove no-map from the secondary-boot reservation. Its overlap
with ARM's initial page tables otherwise causes the reservation to be
rejected, leaving CFE's holding pen unprotected.
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
arch/arm/boot/dts/broadcom/bcm6846-genexis-xg6846b.dts | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/broadcom/bcm6846-genexis-xg6846b.dts b/arch/arm/boot/dts/broadcom/bcm6846-genexis-xg6846b.dts
index a3616fb7b3a8..45d4df523110 100644
--- a/arch/arm/boot/dts/broadcom/bcm6846-genexis-xg6846b.dts
+++ b/arch/arm/boot/dts/broadcom/bcm6846-genexis-xg6846b.dts
@@ -34,7 +34,7 @@ reserved-memory {
ranges;
secondary-boot@0 {
- no-map;
+ /* Includes the kernel's initial page tables. */
reg = <0x00000000 0x00008000>;
};
pmc3-firmware@8000 {
@@ -56,6 +56,20 @@ button-restart {
};
};
+/* CFE parks CPU1 in its holding pen and does not provide PSCI. */
+&{/psci} {
+ status = "disabled";
+};
+
+&CA7_0 {
+ enable-method = "brcm,bca-smp";
+};
+
+&CA7_1 {
+ enable-method = "brcm,bca-smp";
+ cpu-release-addr = <0xff800568>;
+};
+
&gpio0 {
status = "okay";
};
--
2.56.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH v3 3/3] ARM: dts: broadcom: Use CFE CPU bring-up on the XG6846B
2026-10-21 15:09 ` [PATCH v3 3/3] ARM: dts: broadcom: Use CFE CPU bring-up on the XG6846B Linus Walleij
@ 2026-10-21 15:29 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-10-21 15:29 UTC (permalink / raw)
To: Linus Walleij; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] ARM: dts: broadcom: xg6846b partial no-map removal breaks lowmem setup
--
commit 83c5177a7db3728e4dd180472b439b349fdb5f65
Author: Linus Walleij <linusw@kernel.org>
ARM: dts: broadcom: Use CFE CPU bring-up on the XG6846B
This commit disables the inherited PSCI node on the Genexis XG6846B and
configures the CPUs to use the Broadcom BCA CFE SMP bring-up method. It
also removes the no-map property from the secondary-boot@0 reserved-memory
node so the reservation does not fail when overlapping the initial page
tables.
> diff --git a/arch/arm/boot/dts/broadcom/bcm6846-genexis-xg6846b.dts b/arch/arm/boot/dts/broadcom/bcm6846-genexis-xg6846b.dts
> index a3616fb7b3a8d..45d4df5231109 100644
> --- a/arch/arm/boot/dts/broadcom/bcm6846-genexis-xg6846b.dts
> +++ b/arch/arm/boot/dts/broadcom/bcm6846-genexis-xg6846b.dts
> @@ -34,7 +34,7 @@ reserved-memory {
> ranges;
>
> secondary-boot@0 {
> - no-map;
> + /* Includes the kernel's initial page tables. */
> reg = <0x00000000 0x00008000>;
> };
> pmc3-firmware@8000 {
[Severity: High]
Could removing no-map from secondary-boot@0 while leaving no-map on the
immediately adjacent pmc3-firmware@8000 node cause a boot regression in
adjust_lowmem_bounds(), prepare_page_table(), and map_lowmem()?
In arch/arm/boot/dts/broadcom/bcm6846-genexis-xg6846b.dts, reserved-memory
now has a mapped 32 KiB region followed by a 1 MiB no-map region:
secondary-boot@0 {
/* Includes the kernel's initial page tables. */
reg = <0x00000000 0x00008000>;
};
pmc3-firmware@8000 {
no-map;
reg = <0x00008000 0x00100000>;
};
On multi_v7_defconfig (which enables CONFIG_ARCH_BCMBCA=y alongside
CONFIG_ARCH_MESON=y), arch/arm/Makefile sets TEXT_OFFSET to 0x00208000,
placing swapper_pg_dir at physical [0x00204000, 0x00208000) and
KERNEL_START (_stext) at 0x00208000.
During setup_arch() -> arm_memblock_init() ->
early_init_fdt_scan_reserved_mem(), secondary-boot@0 is reserved via
memblock_reserve(0x0, 0x8000) and remains mapped in memblock.memory, while
pmc3-firmware@8000 does not overlap the kernel at 0x00208000 and is marked
MEMBLOCK_NOMAP via memblock_mark_nomap(0x8000, 0x100000). This splits
memblock.memory into:
regions[0] = [0x00000000, 0x00008000) (MEMBLOCK_NONE)
regions[1] = [0x00008000, 0x00108000) (MEMBLOCK_NOMAP)
regions[2] = [0x00108000, 0x10000000) (MEMBLOCK_NONE)
In arch/arm/mm/mmu.c:adjust_lowmem_bounds(), the first loop checks whether
block_start of the first usable range [0x0, 0x8000) is aligned to PMD_SIZE
(which succeeds because 0x0 is aligned) and breaks without aligning
regions[2] (0x00108000). The second loop then checks block_end on
[0x0, 0x8000):
for_each_mem_range(i, &block_start, &block_end) {
if (block_start < vmalloc_limit) {
if (block_end > lowmem_limit)
lowmem_limit = min_t(u64,
vmalloc_limit,
block_end);
if (!memblock_limit) {
if (!IS_ALIGNED(block_start, PMD_SIZE))
memblock_limit = block_start;
else if (!IS_ALIGNED(block_end, PMD_SIZE))
memblock_limit = lowmem_limit;
}
}
}
Because block_end is 0x8000 (!IS_ALIGNED(block_end, PMD_SIZE)),
memblock_limit is set to 0x8000, which round_down(memblock_limit, PMD_SIZE)
rounds down to 0, calling memblock_set_current_limit(0).
Next, in paging_init() -> prepare_page_table(), end is computed from
memblock.memory.regions[0] as 0x8000:
end = memblock.memory.regions[0].base + memblock.memory.regions[0].size;
if (end >= arm_lowmem_limit)
end = arm_lowmem_limit;
for (addr = __phys_to_virt(end);
addr < VMALLOC_START; addr += PMD_SIZE)
pmd_clear(pmd_off_k(addr));
This clears all kernel PMDs from __phys_to_virt(0x8000) up to
VMALLOC_START, unmapping the running kernel at 0xc0208000. Immediately
afterward in paging_init() -> map_lowmem(), processing regions[0]
([0x0, 0x8000)) with kernel_sec_start == 0 == start and end (0x8000) <
kernel_sec_end hits Case 1:
if (kernel_sec_start == start)
start = kernel_sec_end;
if (kernel_sec_end == end)
end = kernel_sec_start;
...
map.pfn = __phys_to_pfn(start);
map.virtual = __phys_to_virt(start);
map.length = end - start;
map.type = MT_MEMORY_RW;
create_mapping(&map);
which sets start = kernel_sec_end while end remains 0x8000, underflowing
map.length = end - start while memblock.current_limit is 0.
Conversely, on configs where TEXT_OFFSET == 0x00008000 (such as
bcm6846_defconfig), KERNEL_START is at physical 0x00008000 and is already
reserved by arm_memblock_init() before early_init_fdt_scan_reserved_mem()
runs, so pmc3-firmware@8000 with no-map overlaps the kernel image and fails
in early_init_dt_reserve_memory() with -EBUSY (which is the only reason
memblock.memory is not split at 0x8000 on bcm6846_defconfig).
Should no-map also be removed from pmc3-firmware@8000, or how is
pmc3-firmware@8000 intended to coexist with the kernel image at physical
0x00008000 and 32-bit ARM's PMD_SIZE lowmem alignment requirements?
[ ... ]
>
>base-commit: 6356fd3dd29d8b5620507a0ce037c644e052b5dd
>--
>2.51.2
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021-genexis-xg6846-smp-v7-3-rc1-v3-0-7c871f1755db@kernel.org?part=3
^ permalink raw reply [flat|nested] 5+ messages in thread