* [PATCH 0/3] platform: generic: spacemit: add K3 platform support
@ 2026-07-24 9:27 Troy Mitchell
2026-07-24 9:27 ` [PATCH 1/3] platform: generic: spacemit: k1: rename cache flush operation Troy Mitchell
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Troy Mitchell @ 2026-07-24 9:27 UTC (permalink / raw)
To: opensbi; +Cc: Xianbin Zhu, Anup Patel, Troy Mitchell
Add initial OpenSBI platform support for the SpacemiT K3 SoC. K3 has
16 harts split across four clusters: eight X100 harts in C0/C1 and
eight A100 harts in C2/C3.
The first patch corrects a misleading K1 cache-operation name without
changing its encoded value or behavior.
The second patch refactors the existing K1 support by moving the
definitions and CCI-550 programming helper needed by both SoCs into
common SpacemiT files. The K1 CCI topology, boot flow, and HSM
implementation remain K1-specific.
The third patch adds the K3 platform implementation. During cold boot,
the boot hart configures the cluster warm-boot vectors, enables CCI
snoop and DVM requests, disables core and cluster power-down on WFI,
and wakes the secondary harts. Per-hart initialization configures PMA
attributes, caches, L1 D-cache snooping, prefetch, and the H extension
on X100 harts.
The series has been build-tested with:
- the generic default configuration
- a K1-only configuration with the SpacemiT HSM driver
- a K3-only configuration without the K1 HSM driver
Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
Xianbin Zhu (3):
platform: generic: spacemit: k1: rename cache flush operation
platform: generic: spacemit: k1: refactor platform support
platform: generic: spacemit: k3: add platform support
lib/utils/hsm/fdt_hsm_spacemit.c | 7 +-
platform/generic/Kconfig | 9 +
platform/generic/configs/defconfig | 1 +
platform/generic/include/spacemit/common.h | 88 +++++++++
platform/generic/include/spacemit/k1.h | 96 ++--------
platform/generic/include/spacemit/k3.h | 144 +++++++++++++++
platform/generic/include/spacemit/k3_asm.h | 16 ++
platform/generic/include/spacemit/spacemit.h | 14 ++
platform/generic/spacemit/k1.c | 33 +---
platform/generic/spacemit/k3.c | 264 +++++++++++++++++++++++++++
platform/generic/spacemit/k3_asm.S | 33 ++++
platform/generic/spacemit/objects.mk | 3 +
platform/generic/spacemit/spacemit.c | 36 ++++
13 files changed, 636 insertions(+), 108 deletions(-)
---
base-commit: c0f87f10d1bfb9e72a84ddfafb5604ee1bfe9d04
change-id: 20260723-spacemit-k3-84720a7be53d
Best regards,
--
Troy Mitchell <troy.mitchell@linux.spacemit.com>
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] platform: generic: spacemit: k1: rename cache flush operation
2026-07-24 9:27 [PATCH 0/3] platform: generic: spacemit: add K3 platform support Troy Mitchell
@ 2026-07-24 9:27 ` Troy Mitchell
2026-07-24 9:27 ` [PATCH 2/3] platform: generic: spacemit: k1: refactor platform support Troy Mitchell
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Troy Mitchell @ 2026-07-24 9:27 UTC (permalink / raw)
To: opensbi; +Cc: Xianbin Zhu, Anup Patel, Troy Mitchell
From: Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
MRAOP_ICACHE_INVALID is used to flush the local D-cache before a hart
stops, so the name incorrectly describes I-cache invalidation. Rename
it to MRAOP_CACHE_FLUSH without changing its encoded value.
Signed-off-by: Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
Co-developed-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
lib/utils/hsm/fdt_hsm_spacemit.c | 2 +-
platform/generic/include/spacemit/k1.h | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/utils/hsm/fdt_hsm_spacemit.c b/lib/utils/hsm/fdt_hsm_spacemit.c
index 868e49bf..99c52335 100644
--- a/lib/utils/hsm/fdt_hsm_spacemit.c
+++ b/lib/utils/hsm/fdt_hsm_spacemit.c
@@ -92,7 +92,7 @@ static int spacemit_hart_stop(void)
asm volatile ("fence iorw, iorw");
/* flush local dcache */
- csr_write(CSR_MRAOP, MRAOP_ICACHE_INVALID);
+ csr_write(CSR_MRAOP, MRAOP_CACHE_FLUSH);
asm volatile ("fence iorw, iorw");
/* disable dcache */
diff --git a/platform/generic/include/spacemit/k1.h b/platform/generic/include/spacemit/k1.h
index 7095bc08..ac727b04 100644
--- a/platform/generic/include/spacemit/k1.h
+++ b/platform/generic/include/spacemit/k1.h
@@ -20,8 +20,8 @@
/* ECC enable */
#define MSETUP_ECCE BIT(16)
-/* icache invalidation */
-#define MRAOP_ICACHE_INVALID GENMASK(1, 0)
+/* cache flush */
+#define MRAOP_CACHE_FLUSH GENMASK(1, 0)
#define PMU_AP_BASE 0xd4282800
--
2.55.0
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] platform: generic: spacemit: k1: refactor platform support
2026-07-24 9:27 [PATCH 0/3] platform: generic: spacemit: add K3 platform support Troy Mitchell
2026-07-24 9:27 ` [PATCH 1/3] platform: generic: spacemit: k1: rename cache flush operation Troy Mitchell
@ 2026-07-24 9:27 ` Troy Mitchell
2026-07-24 9:27 ` [PATCH 3/3] platform: generic: spacemit: k3: add " Troy Mitchell
2026-07-26 1:14 ` [PATCH 0/3] platform: generic: spacemit: add K3 " Bo Gan
3 siblings, 0 replies; 5+ messages in thread
From: Troy Mitchell @ 2026-07-24 9:27 UTC (permalink / raw)
To: opensbi; +Cc: Xianbin Zhu, Anup Patel, Troy Mitchell
From: Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
Refactor the K1 platform support by separating definitions and the
CCI-550 programming helper that are also needed by K3 from K1-specific
code.
Introduce the hidden PLATFORM_SPACEMIT option for selecting shared
SpacemiT objects. Move the following definitions from k1.h to
spacemit/common.h:
- common cache-control CSRs and feature bits
- CCI-550 register offsets and control bits
- PMU_AP_IDLE_* bit definitions
- PLATFORM_MAX_CPUS_PER_CLUSTER
The PMU_AP_IDLE_* names replace the original ad-hoc names from k1.h,
which incorrectly called bit 1 SRAM_PWRDWN, bit 3 WAKE_MCE, and bit 4
MC_SW_REQ. The new names match the register fields documented in both
the K1 and K3 User Manuals:
- bit 0: CORE_IDLE
- bit 1: CORE_PWRDWN
- bit 3: MASK_GIC_NIRQ_TO_CORE
- bit 4: MASK_GIC_NFIQ_TO_CORE
Keep the K1 power-down mask in k1.h and rename it accordingly. Its value
remains 0x1b, so K1 power-management behavior is unchanged.
Move cci_enable_snoop_dvm_reqs() from k1.c to spacemit.c so it can be
used by both K1 and K3. The SoC-specific CCI topology maps and boot flows
remain in their respective platform files. K1-specific HSM operations
remain in lib/utils/hsm/fdt_hsm_spacemit.c; that driver only switches to
the common definitions and the renamed K1 constants.
No functional changes to K1 are intended. This refactoring prepares the
shared definitions and CCI helper for the K3 support added by the next
patch.
Signed-off-by: Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
Co-developed-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
lib/utils/hsm/fdt_hsm_spacemit.c | 5 +-
platform/generic/Kconfig | 4 ++
platform/generic/include/spacemit/common.h | 86 +++++++++++++++++++++++++
platform/generic/include/spacemit/k1.h | 94 +++++-----------------------
platform/generic/include/spacemit/spacemit.h | 14 +++++
platform/generic/spacemit/k1.c | 33 ++--------
platform/generic/spacemit/objects.mk | 1 +
platform/generic/spacemit/spacemit.c | 36 +++++++++++
8 files changed, 167 insertions(+), 106 deletions(-)
diff --git a/lib/utils/hsm/fdt_hsm_spacemit.c b/lib/utils/hsm/fdt_hsm_spacemit.c
index 99c52335..a7045569 100644
--- a/lib/utils/hsm/fdt_hsm_spacemit.c
+++ b/lib/utils/hsm/fdt_hsm_spacemit.c
@@ -10,6 +10,7 @@
#include <platform_override.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_hsm.h>
+#include <spacemit/common.h>
#include <spacemit/k1.h>
static const u64 cpu_wakeup_reg[] = {
@@ -42,9 +43,9 @@ static inline void spacemit_set_cpu_power(u32 hartid, bool enable)
value = readl(cpu_idle_base);
if (enable)
- value &= ~PMU_AP_IDLE_PWRDOWN_MASK;
+ value &= ~PMU_AP_IDLE_PWRDOWN_K1_MASK;
else
- value |= PMU_AP_IDLE_PWRDOWN_MASK;
+ value |= PMU_AP_IDLE_PWRDOWN_K1_MASK;
writel(value, cpu_idle_base);
}
diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
index d594b140..958610d3 100644
--- a/platform/generic/Kconfig
+++ b/platform/generic/Kconfig
@@ -100,9 +100,13 @@ config PLATFORM_THEAD
select THEAD_C9XX_PMU
default n
+config PLATFORM_SPACEMIT
+ bool
+
config PLATFORM_SPACEMIT_K1
bool "Spacemit K1 support"
select FDT_HSM_SPACEMIT
+ select PLATFORM_SPACEMIT
default n
config CPU_MIPS_P8700
diff --git a/platform/generic/include/spacemit/common.h b/platform/generic/include/spacemit/common.h
new file mode 100644
index 00000000..317bb3e9
--- /dev/null
+++ b/platform/generic/include/spacemit/common.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2025 SpacemiT
+ * Authors:
+ * Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
+ * Troy Mitchell <troy.mitchell@linux.spacemit.com>
+ */
+
+#ifndef __RISCV_SPACEMIT_COMMON_H__
+#define __RISCV_SPACEMIT_COMMON_H__
+
+#include <sbi/sbi_bitops.h>
+
+#define CSR_MSETUP 0x7c0
+#define CSR_ML2SETUP 0x7f0
+
+/* dcache enable */
+#define MSETUP_DE BIT(0)
+/* icache enable */
+#define MSETUP_IE BIT(1)
+/* branch prediction enable */
+#define MSETUP_BPE BIT(4)
+/* prefetch functionality enable */
+#define MSETUP_PFE BIT(5)
+/* misaligned memory access enable */
+#define MSETUP_MME BIT(6)
+/* ECC enable */
+#define MSETUP_ECCE BIT(16)
+
+#define PMU_AP_BASE 0xd4282800
+
+#define PMU_AP_CORE0_WAKEUP (PMU_AP_BASE + 0x12c)
+#define PMU_AP_CORE1_WAKEUP (PMU_AP_BASE + 0x130)
+#define PMU_AP_CORE2_WAKEUP (PMU_AP_BASE + 0x134)
+#define PMU_AP_CORE3_WAKEUP (PMU_AP_BASE + 0x138)
+#define PMU_AP_CORE4_WAKEUP (PMU_AP_BASE + 0x324)
+#define PMU_AP_CORE5_WAKEUP (PMU_AP_BASE + 0x328)
+#define PMU_AP_CORE6_WAKEUP (PMU_AP_BASE + 0x32c)
+#define PMU_AP_CORE7_WAKEUP (PMU_AP_BASE + 0x330)
+
+#define PMU_AP_CORE0_IDLE_CFG (PMU_AP_BASE + 0x124)
+#define PMU_AP_CORE1_IDLE_CFG (PMU_AP_BASE + 0x128)
+#define PMU_AP_CORE2_IDLE_CFG (PMU_AP_BASE + 0x160)
+#define PMU_AP_CORE3_IDLE_CFG (PMU_AP_BASE + 0x164)
+#define PMU_AP_CORE4_IDLE_CFG (PMU_AP_BASE + 0x304)
+#define PMU_AP_CORE5_IDLE_CFG (PMU_AP_BASE + 0x308)
+#define PMU_AP_CORE6_IDLE_CFG (PMU_AP_BASE + 0x30c)
+#define PMU_AP_CORE7_IDLE_CFG (PMU_AP_BASE + 0x310)
+
+/* boot entry for X100 clusters (C0, C1) */
+#define C0_RVBADDR_LO_ADDR 0xd4282db0
+#define C0_RVBADDR_HI_ADDR 0xd4282db4
+#define C1_RVBADDR_LO_ADDR 0xd4282eb0
+#define C1_RVBADDR_HI_ADDR 0xd4282eb4
+
+/* CCI-550 base and slave interface layout */
+#define CCI_550_PLATFORM_CCI_ADDR 0xd8500000
+#define CCI_550_STATUS 0x000c
+#define CCI_550_STATUS_CHANGE_PENDING BIT(0)
+#define CCI_550_SLAVE_IFACE0_OFFSET 0x1000
+#define CCI_550_SLAVE_IFACE_OFFSET(idx) \
+ (CCI_550_SLAVE_IFACE0_OFFSET + ((0x1000) * (idx)))
+#define CCI_550_SNOOP_CTRL 0x0000
+#define CCI_550_SNOOP_CTRL_ENABLE_SNOOPS BIT(0)
+#define CCI_550_SNOOP_CTRL_ENABLE_DVMS BIT(1)
+
+/*
+ * PMU AP per-core idle control register bits (PMU_AP_COREn_IDLE_CFG).
+ * Bit definitions are identical in K1 and K3 User Manuals.
+ * These replace the original ad-hoc names from k1.h (which incorrectly
+ * called bit 1 SRAM_PWRDWN, bit 3 WAKE_MCE, and bit 4 MC_SW_REQ).
+ */
+/* bit 0: CORE_IDLE - gate core clock externally when core enters WFI */
+#define PMU_AP_IDLE_CORE_IDLE BIT(0)
+/* bit 1: CORE_PWRDWN - power off core on WFI (requires CORE_IDLE set) */
+#define PMU_AP_IDLE_CORE_PWRDWN BIT(1)
+/* bit 2: Core L1 SRAM Power Down - reserved/not used in K1 and K3 */
+#define PMU_AP_IDLE_CORE_L1_SRAM_PWRDWN BIT(2)
+/* bit 3: MASK_GIC_NIRQ_TO_CORE - mask nIRQ from GIC, auto-cleared by HW on power-down entry */
+#define PMU_AP_IDLE_MASK_GIC_NIRQ BIT(3)
+/* bit 4: MASK_GIC_NFIQ_TO_CORE - mask nFIQ from GIC, auto-cleared by HW on power-down entry */
+#define PMU_AP_IDLE_MASK_GIC_NFIQ BIT(4)
+
+#define PLATFORM_MAX_CPUS_PER_CLUSTER 4
+
+#endif /* __RISCV_SPACEMIT_COMMON_H__ */
diff --git a/platform/generic/include/spacemit/k1.h b/platform/generic/include/spacemit/k1.h
index ac727b04..662b42e5 100644
--- a/platform/generic/include/spacemit/k1.h
+++ b/platform/generic/include/spacemit/k1.h
@@ -1,88 +1,28 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2025 SpacemiT
+ * Authors:
+ * Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
+ * Troy Mitchell <troy.mitchell@linux.spacemit.com>
+ */
+
#ifndef __RISCV_SPACEMIT_K1_H__
#define __RISCV_SPACEMIT_K1_H__
-#define CSR_MSETUP 0x7c0
-#define CSR_MHCR 0x7c1
-#define CSR_MRAOP 0x7c2
-#define CSR_MHINT 0x7c5
-#define CSR_ML2SETUP 0x7f0
+#include <spacemit/common.h>
-/* decache enable */
-#define MSETUP_DE BIT(0)
-/* icache enable */
-#define MSETUP_IE BIT(1)
-/* branch prediction enable */
-#define MSETUP_BPE BIT(4)
-/* prefetch functionality enable */
-#define MSETUP_PFE BIT(5)
-/* misaligned memory access enable */
-#define MSETUP_MME BIT(6)
-/* ECC enable */
-#define MSETUP_ECCE BIT(16)
+#define CSR_MRAOP 0x7c2
-/* cache flush */
#define MRAOP_CACHE_FLUSH GENMASK(1, 0)
-#define PMU_AP_BASE 0xd4282800
-
-#define PMU_AP_CORE0_WAKEUP (PMU_AP_BASE + 0x12c)
-#define PMU_AP_CORE1_WAKEUP (PMU_AP_BASE + 0x130)
-#define PMU_AP_CORE2_WAKEUP (PMU_AP_BASE + 0x134)
-#define PMU_AP_CORE3_WAKEUP (PMU_AP_BASE + 0x138)
-#define PMU_AP_CORE4_WAKEUP (PMU_AP_BASE + 0x324)
-#define PMU_AP_CORE5_WAKEUP (PMU_AP_BASE + 0x328)
-#define PMU_AP_CORE6_WAKEUP (PMU_AP_BASE + 0x32c)
-#define PMU_AP_CORE7_WAKEUP (PMU_AP_BASE + 0x330)
-
-#define PMU_AP_CORE0_IDLE_CFG (PMU_AP_BASE + 0x124)
-#define PMU_AP_CORE1_IDLE_CFG (PMU_AP_BASE + 0x128)
-#define PMU_AP_CORE2_IDLE_CFG (PMU_AP_BASE + 0x160)
-#define PMU_AP_CORE3_IDLE_CFG (PMU_AP_BASE + 0x164)
-#define PMU_AP_CORE4_IDLE_CFG (PMU_AP_BASE + 0x304)
-#define PMU_AP_CORE5_IDLE_CFG (PMU_AP_BASE + 0x308)
-#define PMU_AP_CORE6_IDLE_CFG (PMU_AP_BASE + 0x30c)
-#define PMU_AP_CORE7_IDLE_CFG (PMU_AP_BASE + 0x310)
-
-/* power down */
-#define PMU_AP_IDLE_PWRDWN BIT(0)
-/* sram power down */
-#define PMU_AP_IDLE_SRAM_PWRDWN BIT(1)
-/* enable wake up the memory controller */
-#define PMU_AP_IDLE_WAKE_MCE BIT(3)
-/* disable memory controller software req */
-#define PMU_AP_IDLE_MC_SW_REQ BIT(4)
-
-#define PMU_AP_IDLE_PWRDOWN_MASK (PMU_AP_IDLE_PWRDWN | PMU_AP_IDLE_SRAM_PWRDWN | \
- PMU_AP_IDLE_WAKE_MCE | PMU_AP_IDLE_MC_SW_REQ)
-/* cci */
-#define C0_RVBADDR_LO_ADDR 0xd4282db0
-#define C0_RVBADDR_HI_ADDR 0xd4282db4
-#define C1_RVBADDR_LO_ADDR 0xd4282eb0
-#define C1_RVBADDR_HI_ADDR 0xd4282eb4
-
-#define CCI_550_PLATFORM_CCI_ADDR 0xd8500000
-
-/* relative to cci base */
-#define CCI_550_STATUS 0x000c
-/* status register bits */
-#define CCI_550_STATUS_CHANGE_PENDING BIT(0)
-
-/* slave interface registers */
-#define CCI_550_SLAVE_IFACE0_OFFSET 0x1000
-#define CCI_550_SLAVE_IFACE_OFFSET(idx) (CCI_550_SLAVE_IFACE0_OFFSET + ((0x1000) * (idx)))
-
-/* relative to slave interface base */
-#define CCI_550_SNOOP_CTRL 0x0000
-/* snoop control register bits */
-#define CCI_550_SNOOP_CTRL_ENABLE_SNOOPS BIT(0)
-#define CCI_550_SNOOP_CTRL_ENABLE_DVMS BIT(1)
+#define PMU_AP_IDLE_PWRDOWN_K1_MASK (PMU_AP_IDLE_CORE_IDLE | \
+ PMU_AP_IDLE_CORE_PWRDWN | \
+ PMU_AP_IDLE_MASK_GIC_NIRQ | \
+ PMU_AP_IDLE_MASK_GIC_NFIQ)
-/* clusters and CPU mapping */
-#define PLATFORM_MAX_CPUS 8
-#define PLATFORM_MAX_CPUS_PER_CLUSTER 4
#define CPU_TO_CLUSTER(cpu) ((cpu) / PLATFORM_MAX_CPUS_PER_CLUSTER)
-#define PLAT_CCI_CLUSTER0_IFACE_IX 0
-#define PLAT_CCI_CLUSTER1_IFACE_IX 1
+#define PLAT_CCI_K1_CLUSTER0_IFACE_IX 0
+#define PLAT_CCI_K1_CLUSTER1_IFACE_IX 1
-#endif
+#endif /* __RISCV_SPACEMIT_K1_H__ */
diff --git a/platform/generic/include/spacemit/spacemit.h b/platform/generic/include/spacemit/spacemit.h
new file mode 100644
index 00000000..671cfd05
--- /dev/null
+++ b/platform/generic/include/spacemit/spacemit.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2025 SpacemiT
+ * Authors:
+ * Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
+ * Troy Mitchell <troy.mitchell@linux.spacemit.com>
+ */
+
+#ifndef __RISCV_SPACEMIT_H__
+#define __RISCV_SPACEMIT_H__
+
+void cci_enable_snoop_dvm_reqs(const int *cci_map, unsigned int master_id);
+
+#endif
diff --git a/platform/generic/spacemit/k1.c b/platform/generic/spacemit/k1.c
index 7ee5f17a..4c4f9328 100644
--- a/platform/generic/spacemit/k1.c
+++ b/platform/generic/spacemit/k1.c
@@ -11,37 +11,16 @@
#include <sbi/riscv_io.h>
#include <sbi/sbi_hsm.h>
#include <spacemit/k1.h>
+#include <spacemit/spacemit.h>
+
+#define PLATFORM_MAX_CPUS 8
/* only use 0-1 cluster in SpacemiT K1 */
static const int cci_map[] = {
- PLAT_CCI_CLUSTER0_IFACE_IX,
- PLAT_CCI_CLUSTER1_IFACE_IX,
+ PLAT_CCI_K1_CLUSTER0_IFACE_IX,
+ PLAT_CCI_K1_CLUSTER1_IFACE_IX,
};
-static void cci_enable_snoop_dvm_reqs(unsigned int master_id)
-{
- int slave_if_id = cci_map[master_id];
-
- /*
- * Enable Snoops and DVM messages, no need for Read/Modify/Write as
- * rest of bits are write ignore
- */
- writel(CCI_550_SNOOP_CTRL_ENABLE_DVMS | CCI_550_SNOOP_CTRL_ENABLE_SNOOPS,
- (void *)(u64)CCI_550_PLATFORM_CCI_ADDR +
- CCI_550_SLAVE_IFACE_OFFSET(slave_if_id) + CCI_550_SNOOP_CTRL);
-
- /*
- * Wait for the completion of the write to the Snoop Control Register
- * before testing the change_pending bit
- */
- mb();
-
- /* Wait for the dust to settle down */
- while ((readl((void *)(u64)CCI_550_PLATFORM_CCI_ADDR + CCI_550_STATUS) &
- CCI_550_STATUS_CHANGE_PENDING))
- ;
-}
-
static void spacemit_k1_pre_init(void)
{
unsigned int clusterid, cluster_enabled = 0;
@@ -61,7 +40,7 @@ static void spacemit_k1_pre_init(void)
if (!(cluster_enabled & (1 << clusterid))) {
cluster_enabled |= 1 << clusterid;
- cci_enable_snoop_dvm_reqs(clusterid);
+ cci_enable_snoop_dvm_reqs(cci_map, clusterid);
}
}
}
diff --git a/platform/generic/spacemit/objects.mk b/platform/generic/spacemit/objects.mk
index dcb37867..8309ad1f 100644
--- a/platform/generic/spacemit/objects.mk
+++ b/platform/generic/spacemit/objects.mk
@@ -2,5 +2,6 @@
# SPDX-License-Identifier: BSD-2-Clause
#
+platform-objs-$(CONFIG_PLATFORM_SPACEMIT) += spacemit/spacemit.o
carray-platform_override_modules-$(CONFIG_PLATFORM_SPACEMIT_K1) += spacemit_k1
platform-objs-$(CONFIG_PLATFORM_SPACEMIT_K1) += spacemit/k1.o
diff --git a/platform/generic/spacemit/spacemit.c b/platform/generic/spacemit/spacemit.c
new file mode 100644
index 00000000..a215c1ad
--- /dev/null
+++ b/platform/generic/spacemit/spacemit.c
@@ -0,0 +1,36 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SpacemiT
+ * Authors:
+ * Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
+ * Troy Mitchell <troy.mitchell@linux.spacemit.com>
+ */
+
+#include <platform_override.h>
+#include <sbi/riscv_io.h>
+#include <spacemit/common.h>
+
+void cci_enable_snoop_dvm_reqs(const int *cci_map, unsigned int master_id)
+{
+ int slave_if_id = cci_map[master_id];
+
+ /*
+ * Enable Snoops and DVM messages, no need for Read/Modify/Write as
+ * rest of bits are write ignore
+ */
+ writel(CCI_550_SNOOP_CTRL_ENABLE_DVMS | CCI_550_SNOOP_CTRL_ENABLE_SNOOPS,
+ (void *)(unsigned long)CCI_550_PLATFORM_CCI_ADDR +
+ CCI_550_SLAVE_IFACE_OFFSET(slave_if_id) + CCI_550_SNOOP_CTRL);
+
+ /*
+ * Wait for the completion of the write to the Snoop Control Register
+ * before testing the change_pending bit
+ */
+ mb();
+
+ /* Wait for the dust to settle down */
+ while (readl((void *)(unsigned long)CCI_550_PLATFORM_CCI_ADDR + CCI_550_STATUS) &
+ CCI_550_STATUS_CHANGE_PENDING)
+ ;
+}
--
2.55.0
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] platform: generic: spacemit: k3: add platform support
2026-07-24 9:27 [PATCH 0/3] platform: generic: spacemit: add K3 platform support Troy Mitchell
2026-07-24 9:27 ` [PATCH 1/3] platform: generic: spacemit: k1: rename cache flush operation Troy Mitchell
2026-07-24 9:27 ` [PATCH 2/3] platform: generic: spacemit: k1: refactor platform support Troy Mitchell
@ 2026-07-24 9:27 ` Troy Mitchell
2026-07-26 1:14 ` [PATCH 0/3] platform: generic: spacemit: add K3 " Bo Gan
3 siblings, 0 replies; 5+ messages in thread
From: Troy Mitchell @ 2026-07-24 9:27 UTC (permalink / raw)
To: opensbi; +Cc: Xianbin Zhu, Anup Patel, Troy Mitchell
From: Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
Add initial OpenSBI platform support for the SpacemiT K3 SoC, which
has 16 harts (8 X100 harts in clusters C0/C1, 8 A100 harts in C2/C3).
During cold boot, the boot hart sets warm-boot entry vectors for all
four clusters, enables CCI snooping, clears PMU power-down vote bits
for all harts so WFI does not trigger power-down, and wakes all
non-boot harts (1-15) so they enter WFI waiting for the kernel.
Per-hart initialization programs PMA attributes, enables dcache/icache
via MSETUP, sets smpen[x] in ML2SETUP to enable L1 D-cache snooping
and prefetch for this core (hardware then maintains coherency between
this core's L1 D-cache and all other caches in the system), and enables
the H extension in MISA for X100 harts (MISA.H is writable on K3 X100
cores; M-mode must set it explicitly to activate hypervisor support).
k3_asm.S provides the warm-boot entry stub that enables caches and
sets smpen[x] to enable L1 D-cache snooping before jumping to C code.
This ensures that when the boot hart wakes the other cores, those cores
enter with their local caches active and L1 D-cache coherency enabled
so they can observe any shared-data writes made by the boot hart during
cold-boot initialization. The boot hart enables global CCI-550
snoop/DVM requests separately before waking the secondary harts.
New files:
- platform/generic/include/spacemit/k3.h: K3-specific register definitions
- platform/generic/include/spacemit/k3_asm.h:
warm-boot entry symbol declaration
- platform/generic/spacemit/k3.c: K3 platform driver
- platform/generic/spacemit/k3_asm.S: warm-boot assembly entry stub
Signed-off-by: Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
Co-developed-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
platform/generic/Kconfig | 5 +
platform/generic/configs/defconfig | 1 +
platform/generic/include/spacemit/common.h | 4 +-
platform/generic/include/spacemit/k3.h | 144 ++++++++++++++++
platform/generic/include/spacemit/k3_asm.h | 16 ++
platform/generic/spacemit/k3.c | 264 +++++++++++++++++++++++++++++
platform/generic/spacemit/k3_asm.S | 33 ++++
platform/generic/spacemit/objects.mk | 2 +
8 files changed, 468 insertions(+), 1 deletion(-)
diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
index 958610d3..0302eda6 100644
--- a/platform/generic/Kconfig
+++ b/platform/generic/Kconfig
@@ -109,6 +109,11 @@ config PLATFORM_SPACEMIT_K1
select PLATFORM_SPACEMIT
default n
+config PLATFORM_SPACEMIT_K3
+ bool "Spacemit K3 support"
+ select PLATFORM_SPACEMIT
+ default n
+
config CPU_MIPS_P8700
bool
default n
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 341f6b25..58d40898 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -15,6 +15,7 @@ CONFIG_PLATFORM_THEAD=y
CONFIG_PLATFORM_MIPS_P8700_EYEQ7H=y
CONFIG_PLATFORM_MIPS_P8700_BOSTON=y
CONFIG_PLATFORM_SPACEMIT_K1=y
+CONFIG_PLATFORM_SPACEMIT_K3=y
CONFIG_FDT_CACHE=y
CONFIG_FDT_CACHE_ANDES_LLCACHE=y
CONFIG_FDT_CACHE_SIFIVE_CCACHE=y
diff --git a/platform/generic/include/spacemit/common.h b/platform/generic/include/spacemit/common.h
index 317bb3e9..7b50cc4f 100644
--- a/platform/generic/include/spacemit/common.h
+++ b/platform/generic/include/spacemit/common.h
@@ -9,7 +9,9 @@
#ifndef __RISCV_SPACEMIT_COMMON_H__
#define __RISCV_SPACEMIT_COMMON_H__
+#ifndef __ASSEMBLY__
#include <sbi/sbi_bitops.h>
+#endif
#define CSR_MSETUP 0x7c0
#define CSR_ML2SETUP 0x7f0
@@ -74,7 +76,7 @@
#define PMU_AP_IDLE_CORE_IDLE BIT(0)
/* bit 1: CORE_PWRDWN - power off core on WFI (requires CORE_IDLE set) */
#define PMU_AP_IDLE_CORE_PWRDWN BIT(1)
-/* bit 2: Core L1 SRAM Power Down - reserved/not used in K1 and K3 */
+/* bit 2: Core L1 SRAM Power Down - reserved in K1, used in K3 */
#define PMU_AP_IDLE_CORE_L1_SRAM_PWRDWN BIT(2)
/* bit 3: MASK_GIC_NIRQ_TO_CORE - mask nIRQ from GIC, auto-cleared by HW on power-down entry */
#define PMU_AP_IDLE_MASK_GIC_NIRQ BIT(3)
diff --git a/platform/generic/include/spacemit/k3.h b/platform/generic/include/spacemit/k3.h
new file mode 100644
index 00000000..a84d9ed8
--- /dev/null
+++ b/platform/generic/include/spacemit/k3.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2026 SpacemiT
+ * Authors:
+ * Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
+ * Troy Mitchell <troy.mitchell@linux.spacemit.com>
+ */
+
+#ifndef __RISCV_SPACEMIT_K3_H__
+#define __RISCV_SPACEMIT_K3_H__
+
+#include <spacemit/common.h>
+
+/* PMA configuration CSR */
+#define CSR_PMACFG0 0xbc0
+
+/*
+ * PMACFG0 audio buffer region field: bits [55:48].
+ * Mask and attribute are applied after a 48-bit shift because
+ * csrc/csrs only accept a 12-bit immediate or a register.
+ */
+#define PMACFG0_AUDIO_BUF_FIELD_MASK 0xff
+#define PMACFG0_AUDIO_BUF_FIELD_SHIFT 48
+#define PMACFG0_AUDIO_BUF_ATTR_CACHEABLE 0x20
+
+/*
+ * PMACFG0 XIP region field: bits [23:16].
+ * Lower 12 bits are zero so GAS emits a single lui instruction.
+ */
+#define PMACFG0_XIP_FIELD_CLEAR 0x00ff0000UL
+#define PMACFG0_XIP_ATTR_IO 0x00220000UL
+
+#define CSR_ML2HINT 0x7f7
+
+/* Enable instruction prefetch in L2 cache on miss */
+#define ML2SETUP_IPRF BIT(16)
+/* Enable TLB prefetch in L2 cache */
+#define ML2SETUP_TPRF BIT(18)
+/* Enable top-of-clk of trace */
+#define ML2HINT_TRACE_TOP_ICGEN BIT(26)
+
+/*
+ * Combined MSETUP flags enabled at boot time: DE|IE|BPE|PFE|MME|ECCE.
+ * Expressed as a plain hex constant so it can be used in assembly (BIT()
+ * expands to 1UL<<n which GAS cannot evaluate).
+ */
+#define MSETUP_BOOT_FLAGS 0x10073
+
+/* A100 cores: hart 8-11 belong to C2 cluster, hart 12-15 to C3 cluster */
+#define PMU_CAP_CORE8_WAKEUP (PMU_AP_BASE + 0x360)
+#define PMU_CAP_CORE9_WAKEUP (PMU_AP_BASE + 0x364)
+#define PMU_CAP_CORE10_WAKEUP (PMU_AP_BASE + 0x368)
+#define PMU_CAP_CORE11_WAKEUP (PMU_AP_BASE + 0x36c)
+#define PMU_CAP_CORE12_WAKEUP (PMU_AP_BASE + 0x22c)
+#define PMU_CAP_CORE13_WAKEUP (PMU_AP_BASE + 0x230)
+#define PMU_CAP_CORE14_WAKEUP (PMU_AP_BASE + 0x234)
+#define PMU_CAP_CORE15_WAKEUP (PMU_AP_BASE + 0x238)
+
+/* A100 per-core idle config registers (harts 8-15) */
+#define PMU_CAP_CORE8_IDLE_CFG (PMU_AP_BASE + 0x340)
+#define PMU_CAP_CORE9_IDLE_CFG (PMU_AP_BASE + 0x344)
+#define PMU_CAP_CORE10_IDLE_CFG (PMU_AP_BASE + 0x348)
+#define PMU_CAP_CORE11_IDLE_CFG (PMU_AP_BASE + 0x34c)
+#define PMU_CAP_CORE12_IDLE_CFG (PMU_AP_BASE + 0x20c)
+#define PMU_CAP_CORE13_IDLE_CFG (PMU_AP_BASE + 0x210)
+#define PMU_CAP_CORE14_IDLE_CFG (PMU_AP_BASE + 0x214)
+#define PMU_CAP_CORE15_IDLE_CFG (PMU_AP_BASE + 0x218)
+
+/* CX CAPMP cluster idle config registers */
+#define PMU_CX_CAPMP_IDLE_CFG0 (PMU_AP_BASE + 0x120)
+#define PMU_CX_CAPMP_IDLE_CFG1 (PMU_AP_BASE + 0x0e4)
+#define PMU_CX_CAPMP_IDLE_CFG2 (PMU_AP_BASE + 0x150)
+#define PMU_CX_CAPMP_IDLE_CFG3 (PMU_AP_BASE + 0x154)
+#define PMU_CX_CAPMP_IDLE_CFG4 (PMU_AP_BASE + 0x314)
+#define PMU_CX_CAPMP_IDLE_CFG5 (PMU_AP_BASE + 0x318)
+#define PMU_CX_CAPMP_IDLE_CFG6 (PMU_AP_BASE + 0x31c)
+#define PMU_CX_CAPMP_IDLE_CFG7 (PMU_AP_BASE + 0x320)
+#define PMU_CX_CAPMP_IDLE_CFG8 (PMU_AP_BASE + 0x350)
+#define PMU_CX_CAPMP_IDLE_CFG9 (PMU_AP_BASE + 0x354)
+#define PMU_CX_CAPMP_IDLE_CFG10 (PMU_AP_BASE + 0x358)
+#define PMU_CX_CAPMP_IDLE_CFG11 (PMU_AP_BASE + 0x35c)
+#define PMU_CX_CAPMP_IDLE_CFG12 (PMU_AP_BASE + 0x21c)
+#define PMU_CX_CAPMP_IDLE_CFG13 (PMU_AP_BASE + 0x220)
+#define PMU_CX_CAPMP_IDLE_CFG14 (PMU_AP_BASE + 0x224)
+#define PMU_CX_CAPMP_IDLE_CFG15 (PMU_AP_BASE + 0x228)
+
+#define PMU_AP_IDLE_PWRDOWN_K3_MASK (PMU_AP_IDLE_CORE_IDLE | \
+ PMU_AP_IDLE_CORE_PWRDWN | \
+ PMU_AP_IDLE_CORE_L1_SRAM_PWRDWN | \
+ PMU_AP_IDLE_MASK_GIC_NIRQ | \
+ PMU_AP_IDLE_MASK_GIC_NFIQ)
+
+/*
+ * PMU CX per-cluster idle control bits (PMU_CX_CAPMPn_IDLE_CFG).
+ */
+/* bit 0: MP Idle - gate cluster clocks externally on WFI */
+#define PMU_CX_IDLE_MP_IDLE BIT(0)
+/* bit 1: MP Power Down - power off cluster logic when idle */
+#define PMU_CX_IDLE_MP_PWRDWN BIT(1)
+/* bit 2: L2 Cache SRAM Power Down */
+#define PMU_CX_IDLE_L2_SRAM_PWRDWN BIT(2)
+/* bit 3: SCU SRAM Power Down - not used, SCU SRAM does not support retention */
+#define PMU_CX_IDLE_MP_SCU_SRAM_PWRDWN BIT(3)
+/* bit 7: ACNACTM Hardware Control - HW controls ACNACTM port on MP low power entry */
+#define PMU_CX_IDLE_ACNACTM_HW_CTRL BIT(7)
+
+#define CLUSTER_PWR_DOWN_VALUE (PMU_CX_IDLE_MP_IDLE | \
+ PMU_CX_IDLE_MP_PWRDWN | \
+ PMU_CX_IDLE_L2_SRAM_PWRDWN | \
+ PMU_CX_IDLE_MP_SCU_SRAM_PWRDWN | \
+ PMU_CX_IDLE_ACNACTM_HW_CTRL)
+
+/* boot entry for A100 clusters */
+#define C2_RVBADDR_LO_ADDR (0xd4282c00 + 0x3e8)
+#define C2_RVBADDR_HI_ADDR (0xd4282c00 + 0x3ec)
+#define C3_RVBADDR_LO_ADDR (0xd4282c00 + 0x260)
+#define C3_RVBADDR_HI_ADDR (0xd4282c00 + 0x264)
+
+/*
+ * PMU AP core WFI status registers. Each bit indicates the corresponding
+ * core has entered WFI idle state.
+ *
+ * X100 harts (0-7): PMU_AP_X100_IDLE_STATUS
+ * cluster 0 (harts 0-3): bits 4, 7, 10, 13
+ * cluster 1 (harts 4-7): bits 20, 23, 26, 29
+ * A100 harts (8-15): PMU_AP_A100_IDLE_STATUS
+ * cluster 2 (harts 8-11): bits 4, 7, 10, 13
+ * cluster 3 (harts 12-15): bits 20, 23, 26, 29
+ */
+#define PMU_AP_X100_IDLE_STATUS 0xd4282890
+#define PMU_AP_A100_IDLE_STATUS 0xd4282880
+
+#define PLATFORM_A100_FIRST_ID 8
+#define PLATFORM_A100_LAST_ID 15
+
+#define PLAT_CCI_K3_AIDMA_IFACE_IX 0
+#define PLAT_CCI_K3_CLUSTER0_IFACE_IX 1
+#define PLAT_CCI_K3_CLUSTER1_IFACE_IX 2
+#define PLAT_CCI_K3_CLUSTER2_0_IFACE_IX 3
+#define PLAT_CCI_K3_CLUSTER2_1_IFACE_IX 4
+#define PLAT_CCI_K3_CLUSTER3_0_IFACE_IX 5
+#define PLAT_CCI_K3_CLUSTER3_1_IFACE_IX 6
+
+#endif /* __RISCV_SPACEMIT_K3_H__ */
diff --git a/platform/generic/include/spacemit/k3_asm.h b/platform/generic/include/spacemit/k3_asm.h
new file mode 100644
index 00000000..70c00478
--- /dev/null
+++ b/platform/generic/include/spacemit/k3_asm.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2026 SpacemiT
+ * Authors:
+ * Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
+ * Troy Mitchell <troy.mitchell@linux.spacemit.com>
+ */
+
+#ifndef __RISCV_SPACEMIT_K3_ASM_H__
+#define __RISCV_SPACEMIT_K3_ASM_H__
+
+#ifndef __ASSEMBLY__
+void _spacemit_k3_warm_start(void);
+#endif
+
+#endif /* __RISCV_SPACEMIT_K3_ASM_H__ */
diff --git a/platform/generic/spacemit/k3.c b/platform/generic/spacemit/k3.c
new file mode 100644
index 00000000..318aa9e7
--- /dev/null
+++ b/platform/generic/spacemit/k3.c
@@ -0,0 +1,264 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 SpacemiT
+ * Authors:
+ * Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
+ * Troy Mitchell <troy.mitchell@linux.spacemit.com>
+ */
+
+#include <platform_override.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_timer.h>
+#include <spacemit/k3.h>
+#include <spacemit/k3_asm.h>
+#include <spacemit/spacemit.h>
+
+#define PLATFORM_MAX_CPUS 16
+
+/*
+ * Maximum time to wait for each secondary hart to enter WFI after it is
+ * woken during cold boot. Use the platform timer so the timeout does not
+ * depend on CPU frequency or MMIO latency.
+ */
+#define HART_WFI_TIMEOUT_MS 100
+
+static const int cci_map[] = {
+ PLAT_CCI_K3_AIDMA_IFACE_IX,
+ PLAT_CCI_K3_CLUSTER0_IFACE_IX,
+ PLAT_CCI_K3_CLUSTER1_IFACE_IX,
+ PLAT_CCI_K3_CLUSTER2_0_IFACE_IX,
+ PLAT_CCI_K3_CLUSTER2_1_IFACE_IX,
+ PLAT_CCI_K3_CLUSTER3_0_IFACE_IX,
+ PLAT_CCI_K3_CLUSTER3_1_IFACE_IX,
+};
+
+static const unsigned long cx_capmp_idle_cfg[] = {
+ PMU_CX_CAPMP_IDLE_CFG0, PMU_CX_CAPMP_IDLE_CFG1,
+ PMU_CX_CAPMP_IDLE_CFG2, PMU_CX_CAPMP_IDLE_CFG3,
+ PMU_CX_CAPMP_IDLE_CFG4, PMU_CX_CAPMP_IDLE_CFG5,
+ PMU_CX_CAPMP_IDLE_CFG6, PMU_CX_CAPMP_IDLE_CFG7,
+ PMU_CX_CAPMP_IDLE_CFG8, PMU_CX_CAPMP_IDLE_CFG9,
+ PMU_CX_CAPMP_IDLE_CFG10, PMU_CX_CAPMP_IDLE_CFG11,
+ PMU_CX_CAPMP_IDLE_CFG12, PMU_CX_CAPMP_IDLE_CFG13,
+ PMU_CX_CAPMP_IDLE_CFG14, PMU_CX_CAPMP_IDLE_CFG15,
+};
+
+static const unsigned long core_pwrdown_reg[] = {
+ PMU_AP_CORE0_IDLE_CFG, PMU_AP_CORE1_IDLE_CFG,
+ PMU_AP_CORE2_IDLE_CFG, PMU_AP_CORE3_IDLE_CFG,
+ PMU_AP_CORE4_IDLE_CFG, PMU_AP_CORE5_IDLE_CFG,
+ PMU_AP_CORE6_IDLE_CFG, PMU_AP_CORE7_IDLE_CFG,
+ PMU_CAP_CORE8_IDLE_CFG, PMU_CAP_CORE9_IDLE_CFG,
+ PMU_CAP_CORE10_IDLE_CFG, PMU_CAP_CORE11_IDLE_CFG,
+ PMU_CAP_CORE12_IDLE_CFG, PMU_CAP_CORE13_IDLE_CFG,
+ PMU_CAP_CORE14_IDLE_CFG, PMU_CAP_CORE15_IDLE_CFG,
+};
+
+/* Wakeup registers indexed by hart ID (0-15). */
+static const unsigned long core_wakeup_reg[] = {
+ PMU_AP_CORE0_WAKEUP, PMU_AP_CORE1_WAKEUP,
+ PMU_AP_CORE2_WAKEUP, PMU_AP_CORE3_WAKEUP,
+ PMU_AP_CORE4_WAKEUP, PMU_AP_CORE5_WAKEUP,
+ PMU_AP_CORE6_WAKEUP, PMU_AP_CORE7_WAKEUP,
+ PMU_CAP_CORE8_WAKEUP, PMU_CAP_CORE9_WAKEUP,
+ PMU_CAP_CORE10_WAKEUP, PMU_CAP_CORE11_WAKEUP,
+ PMU_CAP_CORE12_WAKEUP, PMU_CAP_CORE13_WAKEUP,
+ PMU_CAP_CORE14_WAKEUP, PMU_CAP_CORE15_WAKEUP,
+};
+
+/*
+ * WFI idle status registers and per-hart mask bits. Each hart has a
+ * dedicated bit in one of two status registers (X100 harts 0-7 in
+ * PMU_AP_X100_IDLE_STATUS, A100 harts 8-15 in PMU_AP_A100_IDLE_STATUS).
+ * Index 0 is unused — the boot hart never waits on itself.
+ */
+static const unsigned long wfi_status_reg[] = {
+ 0,
+ PMU_AP_X100_IDLE_STATUS, PMU_AP_X100_IDLE_STATUS,
+ PMU_AP_X100_IDLE_STATUS, PMU_AP_X100_IDLE_STATUS,
+ PMU_AP_X100_IDLE_STATUS, PMU_AP_X100_IDLE_STATUS,
+ PMU_AP_X100_IDLE_STATUS,
+ PMU_AP_A100_IDLE_STATUS, PMU_AP_A100_IDLE_STATUS,
+ PMU_AP_A100_IDLE_STATUS, PMU_AP_A100_IDLE_STATUS,
+ PMU_AP_A100_IDLE_STATUS, PMU_AP_A100_IDLE_STATUS,
+ PMU_AP_A100_IDLE_STATUS, PMU_AP_A100_IDLE_STATUS,
+};
+static const unsigned long wfi_status_mask[] = {
+ 0,
+ BIT(7), BIT(10), BIT(13), BIT(20),
+ BIT(23), BIT(26), BIT(29),
+ BIT(4), BIT(7), BIT(10), BIT(13),
+ BIT(20), BIT(23), BIT(26), BIT(29),
+};
+
+/*
+ * Clear the power-down bits for both the core and its cluster so that
+ * the hart does not trigger a power-down sequence on WFI. Called during
+ * cold boot to ensure cores and clusters stay powered while SBI initializes.
+ */
+static void spacemit_disable_pwrdown_core(u32 hartid)
+{
+ unsigned int value;
+
+ if (hartid >= array_size(cx_capmp_idle_cfg))
+ return;
+
+ value = readl((void *)(unsigned long)cx_capmp_idle_cfg[hartid]);
+ value &= ~CLUSTER_PWR_DOWN_VALUE;
+ writel(value, (void *)(unsigned long)cx_capmp_idle_cfg[hartid]);
+
+ value = readl((void *)(unsigned long)core_pwrdown_reg[hartid]);
+ value &= ~PMU_AP_IDLE_PWRDOWN_K3_MASK;
+ writel(value, (void *)(unsigned long)core_pwrdown_reg[hartid]);
+}
+
+/*
+ * Per-hart hardware initialization, mirroring what warm-boot harts previously
+ * did in assembly before entering C code. Called on every hart on both cold
+ * and warm boot paths.
+ *
+ * 1. PMA: set audio buffer (bits [55:48]) cacheable and XIP
+ * region (bits [23:16]) as IO before enabling dcache.
+ * 2. Enable dcache/icache and other CPU features (MSETUP).
+ * 3. Set smpen[x] in ML2SETUP to enable L1 D-cache snooping and prefetch.
+ * 4. Enable H extension in MISA (X100 only; not implemented on A100).
+ */
+static void spacemit_k3_hart_init(u32 hartid)
+{
+ csr_clear(CSR_PMACFG0,
+ (unsigned long)PMACFG0_AUDIO_BUF_FIELD_MASK
+ << PMACFG0_AUDIO_BUF_FIELD_SHIFT);
+ csr_set(CSR_PMACFG0,
+ (unsigned long)PMACFG0_AUDIO_BUF_ATTR_CACHEABLE
+ << PMACFG0_AUDIO_BUF_FIELD_SHIFT);
+ csr_clear(CSR_PMACFG0, PMACFG0_XIP_FIELD_CLEAR);
+ csr_set(CSR_PMACFG0, PMACFG0_XIP_ATTR_IO);
+ asm volatile("sfence.vma" : : : "memory");
+
+ csr_set(CSR_MSETUP, MSETUP_DE | MSETUP_IE | MSETUP_BPE |
+ MSETUP_PFE | MSETUP_MME | MSETUP_ECCE);
+ csr_set(CSR_ML2SETUP, 1 << (hartid % PLATFORM_MAX_CPUS_PER_CLUSTER));
+ csr_set(CSR_ML2SETUP, ML2SETUP_IPRF | ML2SETUP_TPRF);
+ csr_set(CSR_ML2HINT, ML2HINT_TRACE_TOP_ICGEN);
+
+ if (hartid < PLATFORM_A100_FIRST_ID) {
+ unsigned long misa = csr_read(CSR_MISA);
+
+ /*
+ * MISA.H is writable on K3 X100 cores: the H extension is
+ * implemented but disabled out of reset, and M-mode must
+ * explicitly set this bit to enable hypervisor support.
+ * A100 cores do not implement H, so this write is X100-only.
+ */
+ misa |= 1UL << ('H' - 'A');
+ csr_write(CSR_MISA, misa);
+ }
+}
+
+/*
+ * One-time platform setup run by the boot hart during cold boot:
+ * set warm-boot entry for all four clusters, enable CCI snooping,
+ * and wake all non-boot harts (1-15) so they enter WFI and wait
+ * for the kernel to bring them online.
+ */
+static void spacemit_k3_pre_init(void)
+{
+ unsigned long entry = (unsigned long)&_spacemit_k3_warm_start;
+ int i;
+
+ writel((u32)entry, (void *)(unsigned long)C0_RVBADDR_LO_ADDR);
+ writel((u32)(entry >> 32), (void *)(unsigned long)C0_RVBADDR_HI_ADDR);
+
+ writel((u32)entry, (void *)(unsigned long)C1_RVBADDR_LO_ADDR);
+ writel((u32)(entry >> 32), (void *)(unsigned long)C1_RVBADDR_HI_ADDR);
+
+ writel((u32)entry, (void *)(unsigned long)C2_RVBADDR_LO_ADDR);
+ writel((u32)(entry >> 32), (void *)(unsigned long)C2_RVBADDR_HI_ADDR);
+
+ writel((u32)entry, (void *)(unsigned long)C3_RVBADDR_LO_ADDR);
+ writel((u32)(entry >> 32), (void *)(unsigned long)C3_RVBADDR_HI_ADDR);
+
+ for (i = 0; i < array_size(cci_map); i++)
+ cci_enable_snoop_dvm_reqs(cci_map, i);
+
+ /* Clear core and cluster power-down votes so WFI does not trigger power-down. */
+ for (i = 0; i < PLATFORM_MAX_CPUS; i++)
+ spacemit_disable_pwrdown_core(i);
+
+ /*
+ * Wake up all non-boot harts (1-15). Each hart N has a dedicated PMU
+ * wakeup register (PMU_AP/CAP_COREn_WAKEUP). Writing BIT(N) to hart N's
+ * register triggers the wakeup pulse for that hart. This is confirmed by
+ * hardware: the register address selects the target hart, and the value
+ * written must have bit N set (not a fixed trigger bit).
+ * See K3 User Manual, "16 Peripherals / Power Management / Wakeup Core".
+ */
+ for (i = 1; i < array_size(core_wakeup_reg); i++)
+ writel(1 << i, (void *)(unsigned long)core_wakeup_reg[i]);
+
+ /*
+ * Wait for each non-boot hart to enter WFI. Status bit positions are
+ * non-uniform (see k3.h), so use the file-scope lookup tables.
+ */
+ for (i = 1; i < PLATFORM_MAX_CPUS; i++) {
+ u64 deadline = sbi_timer_value_after_msecs(HART_WFI_TIMEOUT_MS);
+
+ while (!(readl((void *)(unsigned long)wfi_status_reg[i]) & wfi_status_mask[i])) {
+ if (sbi_timer_value() >= deadline) {
+ sbi_printf("warn: hart %d did not enter WFI\n", i);
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Platform early initialization.
+ */
+static int spacemit_k3_early_init(bool cold_boot)
+{
+ int rc;
+
+ if (cold_boot)
+ spacemit_k3_pre_init();
+
+ rc = generic_early_init(cold_boot);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static bool spacemit_cold_boot_allowed(u32 hartid)
+{
+ /*
+ * Run per-hart hardware init (PMA, dcache/icache, and L1 D-cache
+ * snoop enable) here so it executes on every hart before any SBI
+ * code runs. cold_boot_allowed is the earliest per-hart hook
+ * available in the generic platform.
+ */
+ spacemit_k3_hart_init(hartid);
+
+ return !hartid;
+}
+
+static int spacemit_k3_platform_init(const void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ generic_platform_ops.early_init = spacemit_k3_early_init;
+ generic_platform_ops.cold_boot_allowed = spacemit_cold_boot_allowed;
+
+ return 0;
+}
+
+static const struct fdt_match spacemit_k3_match[] = {
+ { .compatible = "spacemit,k3" },
+ { /* sentinel */ }
+};
+
+const struct fdt_driver spacemit_k3 = {
+ .match_table = spacemit_k3_match,
+ .init = spacemit_k3_platform_init,
+};
diff --git a/platform/generic/spacemit/k3_asm.S b/platform/generic/spacemit/k3_asm.S
new file mode 100644
index 00000000..fe45cca6
--- /dev/null
+++ b/platform/generic/spacemit/k3_asm.S
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2026 SpacemiT
+ * Authors:
+ * Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
+ * Troy Mitchell <troy.mitchell@linux.spacemit.com>
+ */
+
+#define __ASSEMBLY__
+#include <spacemit/common.h>
+#include <spacemit/k3.h>
+
+ .section .entry, "ax", %progbits
+ .align 3
+ .globl _spacemit_k3_warm_start
+_spacemit_k3_warm_start:
+ /* Enable dcache, icache, and CPU features */
+ li t0, MSETUP_BOOT_FLAGS
+ csrs CSR_MSETUP, t0
+
+ /*
+ * Set smpen[x] in ML2SETUP to enable L1 D-cache snooping for this
+ * core, so the hardware maintains coherency between this core's L1
+ * D-cache and all other caches in the system.
+ * The bit position is 1 << (hartid % PLATFORM_MAX_CPUS_PER_CLUSTER).
+ */
+ csrr t0, mhartid
+ andi t0, t0, (PLATFORM_MAX_CPUS_PER_CLUSTER - 1)
+ li t1, 1
+ sll t1, t1, t0
+ csrs CSR_ML2SETUP, t1
+
+ j _start_warm
diff --git a/platform/generic/spacemit/objects.mk b/platform/generic/spacemit/objects.mk
index 8309ad1f..282543b5 100644
--- a/platform/generic/spacemit/objects.mk
+++ b/platform/generic/spacemit/objects.mk
@@ -5,3 +5,5 @@
platform-objs-$(CONFIG_PLATFORM_SPACEMIT) += spacemit/spacemit.o
carray-platform_override_modules-$(CONFIG_PLATFORM_SPACEMIT_K1) += spacemit_k1
platform-objs-$(CONFIG_PLATFORM_SPACEMIT_K1) += spacemit/k1.o
+carray-platform_override_modules-$(CONFIG_PLATFORM_SPACEMIT_K3) += spacemit_k3
+platform-objs-$(CONFIG_PLATFORM_SPACEMIT_K3) += spacemit/k3.o spacemit/k3_asm.o
--
2.55.0
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 0/3] platform: generic: spacemit: add K3 platform support
2026-07-24 9:27 [PATCH 0/3] platform: generic: spacemit: add K3 platform support Troy Mitchell
` (2 preceding siblings ...)
2026-07-24 9:27 ` [PATCH 3/3] platform: generic: spacemit: k3: add " Troy Mitchell
@ 2026-07-26 1:14 ` Bo Gan
3 siblings, 0 replies; 5+ messages in thread
From: Bo Gan @ 2026-07-26 1:14 UTC (permalink / raw)
To: Troy Mitchell, opensbi; +Cc: Xianbin Zhu, Anup Patel
Hi Troy, Xianbin,
On 7/24/26 02:27, Troy Mitchell wrote:
> Add initial OpenSBI platform support for the SpacemiT K3 SoC. K3 has
> 16 harts split across four clusters: eight X100 harts in C0/C1 and
> eight A100 harts in C2/C3.
>
One thing to watch out for is the lack of 'H' in A100. This can cause
issues where the code assumed all cores to have the same extensions:
https://github.com/riscv-software-src/opensbi/blob/c0f87f10d1bfb9e72a84ddfafb5604ee1bfe9d04/lib/sbi/sbi_hart.c#L704
if (cold_boot) {
if (misa_extension('H'))
sbi_hart_expected_trap = &__sbi_expected_trap_hext;
...
At least this `sbi_hart_expected_trap` needs to be enhanced to account for
heterogeneous cores. Perhaps wrap it as a function, such as
ulong sbi_hart_expected_trap_addr(void), and fix up all users:
- register ulong mtvec = (ulong)sbi_hart_expected_trap;
+ register ulong mtvec = sbi_hart_expected_trap_addr();
Please also check other places where it's assuming homogeneous cores. Can
you also describe in detail the different extensions between X100/A100?
Apart from H/no-H, and different vlen's, anything else?
> The first patch corrects a misleading K1 cache-operation name without
> changing its encoded value or behavior.
>
> The second patch refactors the existing K1 support by moving the
> definitions and CCI-550 programming helper needed by both SoCs into
> common SpacemiT files. The K1 CCI topology, boot flow, and HSM
> implementation remain K1-specific.
>
> The third patch adds the K3 platform implementation. During cold boot,
> the boot hart configures the cluster warm-boot vectors, enables CCI
> snoop and DVM requests, disables core and cluster power-down on WFI,
> and wakes the secondary harts. Per-hart initialization configures PMA
> attributes, caches, L1 D-cache snooping, prefetch, and the H extension
> on X100 harts.
>
> The series has been build-tested with:
> - the generic default configuration
> - a K1-only configuration with the SpacemiT HSM driver
> - a K3-only configuration without the K1 HSM driver
>
> Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
> ---
> Xianbin Zhu (3):
> platform: generic: spacemit: k1: rename cache flush operation
> platform: generic: spacemit: k1: refactor platform support
> platform: generic: spacemit: k3: add platform support
>
> lib/utils/hsm/fdt_hsm_spacemit.c | 7 +-
> platform/generic/Kconfig | 9 +
> platform/generic/configs/defconfig | 1 +
> platform/generic/include/spacemit/common.h | 88 +++++++++
> platform/generic/include/spacemit/k1.h | 96 ++--------
> platform/generic/include/spacemit/k3.h | 144 +++++++++++++++
> platform/generic/include/spacemit/k3_asm.h | 16 ++
> platform/generic/include/spacemit/spacemit.h | 14 ++
> platform/generic/spacemit/k1.c | 33 +---
> platform/generic/spacemit/k3.c | 264 +++++++++++++++++++++++++++
> platform/generic/spacemit/k3_asm.S | 33 ++++
> platform/generic/spacemit/objects.mk | 3 +
> platform/generic/spacemit/spacemit.c | 36 ++++
> 13 files changed, 636 insertions(+), 108 deletions(-)
> ---
> base-commit: c0f87f10d1bfb9e72a84ddfafb5604ee1bfe9d04
> change-id: 20260723-spacemit-k3-84720a7be53d
>
> Best regards,
> --
> Troy Mitchell <troy.mitchell@linux.spacemit.com>
>
>
Bo
--
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-26 1:17 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-24 9:27 [PATCH 0/3] platform: generic: spacemit: add K3 platform support Troy Mitchell
2026-07-24 9:27 ` [PATCH 1/3] platform: generic: spacemit: k1: rename cache flush operation Troy Mitchell
2026-07-24 9:27 ` [PATCH 2/3] platform: generic: spacemit: k1: refactor platform support Troy Mitchell
2026-07-24 9:27 ` [PATCH 3/3] platform: generic: spacemit: k3: add " Troy Mitchell
2026-07-26 1:14 ` [PATCH 0/3] platform: generic: spacemit: add K3 " Bo Gan
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.