All of lore.kernel.org
 help / color / mirror / Atom feed
From: Samuel Holland <samuel.holland@sifive.com>
To: Troy Mitchell <troy.mitchell@linux.spacemit.com>,
	opensbi@lists.infradead.org
Cc: Xianbin Zhu <xianbin.zhu@linux.spacemit.com>,
	Anup Patel <anup@brainfault.org>, Bo Gan <ganboing@gmail.com>
Subject: Re: [PATCH v2 5/5] platform: generic: spacemit: k3: add platform support
Date: Thu, 20 Aug 2026 09:25:24 -0500	[thread overview]
Message-ID: <d3217c02-1dc6-4bcf-a5eb-da30c9a9860d@sifive.com> (raw)
In-Reply-To: <20260818-spacemit-k3-v2-5-84cb7773a481@linux.spacemit.com>

Hi Troy,

On 2026-08-17 8:14 PM, Troy Mitchell wrote:
> From: Xianbin Zhu <xianbin.zhu@linux.spacemit.com>
> 
> Add initial OpenSBI platform support for the SpacemiT K3 SoC, which has
> 16 harts: eight X100 harts in clusters C0/C1 and eight 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). Wait up to 100 ms for each secondary hart to enter WFI,
> then warn and continue so one failed hart cannot stall boot indefinitely.
> 
> Run per-hart initialization from the nascent hook on both cold- and
> warm-boot paths. Program PMA attributes, enable the D-cache and I-cache
> through MSETUP, set smpen[x] in ML2SETUP to enable L1 D-cache snooping
> and prefetch, and enable the H extension in MISA for X100 harts. MISA.H
> is writable on K3 X100 cores, and M-mode must set it explicitly to
> activate hypervisor support.
> 
> Start secondary harts through an assembly stub that enables caches and
> sets smpen[x] before entering common warm-boot code. This lets them
> observe shared-data writes made by the boot hart during cold-boot
> initialization. Enable global CCI-550 snoop and DVM requests on the boot
> hart before waking the secondary harts.
> 
> 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             | 266 +++++++++++++++++++++++++++++
>  platform/generic/spacemit/k3_asm.S         |  33 ++++
>  platform/generic/spacemit/objects.mk       |   2 +
>  8 files changed, 470 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..e484d67b
> --- /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				0x7de
> +
> +/*
> + * 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..1e8d8c97
> --- /dev/null
> +++ b/platform/generic/spacemit/k3.c
> @@ -0,0 +1,266 @@
> +/*
> + * 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_asm.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);
> +	}
> +}
> +
> +static int spacemit_k3_nascent_init(void)
> +{
> +	spacemit_k3_hart_init(current_hartid());
> +
> +	return generic_nascent_init();
> +}
> +
> +/*
> + * 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;
> +			}
> +		}
> +	}

The operations in these loops should be in a .hart_start function of an HSM
driver, not run in a loop at cold boot. You will need to do this anyway to
support power management, and it makes cold boot faster.

> +}
> +
> +/*
> + * 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)
> +{
> +	return !hartid;
> +}

If harts 1-15 are not powered on until spacemit_k3_pre_init(), this callback
won't do anything, because hart 0 is the only hart running at this point.

Regards,
Samuel

> +
> +static int spacemit_k3_platform_init(const void *fdt, int nodeoff,
> +				     const struct fdt_match *match)
> +{
> +	generic_platform_ops.nascent_init = spacemit_k3_nascent_init;
> +	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
> 


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

  parent reply	other threads:[~2026-08-20 14:25 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-18  1:14 [PATCH v2 0/5] platform: generic: spacemit: add K3 platform support Troy Mitchell
2026-08-18  1:14 ` [PATCH v2 1/5] lib: sbi: select expected trap handler per hart Troy Mitchell
2026-08-20  8:40   ` Bo Gan
2026-08-18  1:14 ` [PATCH v2 2/5] platform: generic: spacemit: k1: rename cache flush operation Troy Mitchell
2026-08-18  1:14 ` [PATCH v2 3/5] platform: generic: spacemit: k1: move hart init to nascent hook Troy Mitchell
2026-08-20  8:42   ` Bo Gan
2026-08-18  1:14 ` [PATCH v2 4/5] platform: generic: spacemit: k1: refactor platform support Troy Mitchell
2026-08-18  1:14 ` [PATCH v2 5/5] platform: generic: spacemit: k3: add " Troy Mitchell
2026-08-20  9:18   ` Bo Gan
2026-08-20 14:25   ` Samuel Holland [this message]
2026-08-21  1:55     ` Troy Mitchell
2026-08-21 13:28   ` Heinrich Schuchardt
2026-08-20  9:26 ` [PATCH v2 0/5] platform: generic: spacemit: add K3 " Bo Gan
2026-08-21  1:18   ` Troy Mitchell
2026-08-21 14:33 ` Heinrich Schuchardt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d3217c02-1dc6-4bcf-a5eb-da30c9a9860d@sifive.com \
    --to=samuel.holland@sifive.com \
    --cc=anup@brainfault.org \
    --cc=ganboing@gmail.com \
    --cc=opensbi@lists.infradead.org \
    --cc=troy.mitchell@linux.spacemit.com \
    --cc=xianbin.zhu@linux.spacemit.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.