[PATCH v3 1/3] platform: generic: spacemit: add K1

Anup Patel anup at brainfault.org
Sun Oct 19 22:09:10 PDT 2025


On Thu, Sep 25, 2025 at 3:19 PM Troy Mitchell
<troy.mitchell at linux.spacemit.com> wrote:
>
> From: Xianbin Zhu <xianbin.zhu at linux.spacemit.com>
>
> Add initial platform support for the SpacemiT K1 SoC, including
> early/final init hooks, cold boot handling, and CCI-550 snoop/DVM
> enablement.
>
> Co-authored-by: Troy Mitchell <troy.mitchell at linux.spacemit.com>
> Signed-off-by: Troy Mitchell <troy.mitchell at linux.spacemit.com>
> Signed-off-by: Xianbin Zhu <xianbin.zhu at linux.spacemit.com>
> ---
>  platform/generic/Kconfig               |   4 ++
>  platform/generic/include/spacemit/k1.h |  98 +++++++++++++++++++++++++++
>  platform/generic/spacemit/k1.c         | 119 +++++++++++++++++++++++++++++++++
>  3 files changed, 221 insertions(+)
>
> diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
> index 7559a4bd8ccfcf7e0e7366141f632f5f5e13bd98..d0835126287ef080a44e30140b49c022695efd17 100644
> --- a/platform/generic/Kconfig
> +++ b/platform/generic/Kconfig
> @@ -76,6 +76,10 @@ config PLATFORM_MIPS_P8700
>         bool "MIPS P8700 support"
>         default n
>
> +config PLATFORM_SPACEMIT_K1
> +       bool "Spacemit K1 support"
> +       default n
> +
>  source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig"
>  source "$(OPENSBI_SRC_DIR)/platform/generic/thead/Kconfig"
>
> diff --git a/platform/generic/include/spacemit/k1.h b/platform/generic/include/spacemit/k1.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..bd666346564698e04e69029de73eae863ac45d19
> --- /dev/null
> +++ b/platform/generic/include/spacemit/k1.h
> @@ -0,0 +1,98 @@
> +#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
> +
> +/* 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)
> +
> +/* icache invalidation */
> +#define MRAOP_ICACHE_INVALID                   GENMASK(1, 0)
> +
> +#define PMU_AP_BASE                            0xd4282800
> +
> +#define PMU_AP_CORE0_WAKEUP_OFFSET             (PMU_AP_BASE + 0x12c)
> +#define PMU_AP_CORE4_WAKEUP_OFFSET             (PMU_AP_BASE + 0x324)
> +#define PMU_AP_CLUSTER0_WAKEUP_OFFSET(index)   (PMU_AP_CORE0_WAKEUP_OFFSET + index * 4)
> +#define PMU_AP_CLUSTER1_WAKEUP_OFFSET(index)   (PMU_AP_CORE4_WAKEUP_OFFSET + index * 4)
> +
> +#define PMU_AP_CORE0_IDLE_CFG_OFFSET           (PMU_AP_BASE + 0x124)
> +#define PMU_AP_CORE4_IDLE_CFG_OFFSET           (PMU_AP_BASE + 0x304)
> +#define PMU_AP_CLUSTER0_IDLE_CFG_OFFSET(index) (PMU_AP_CORE0_IDLE_CFG_OFFSET + index * 4)
> +#define PMU_AP_CLUSTER1_IDLE_CFG_OFFSET(index) (PMU_AP_CORE4_IDLE_CFG_OFFSET + index * 4)
> +
> +#define PMU_AP_CORE0_WAKEUP                    PMU_AP_CLUSTER0_WAKEUP_OFFSET(0)
> +#define PMU_AP_CORE1_WAKEUP                    PMU_AP_CLUSTER0_WAKEUP_OFFSET(1)
> +#define PMU_AP_CORE2_WAKEUP                    PMU_AP_CLUSTER0_WAKEUP_OFFSET(2)
> +#define PMU_AP_CORE3_WAKEUP                    PMU_AP_CLUSTER0_WAKEUP_OFFSET(3)
> +#define PMU_AP_CORE4_WAKEUP                    PMU_AP_CLUSTER1_WAKEUP_OFFSET(0)
> +#define PMU_AP_CORE5_WAKEUP                    PMU_AP_CLUSTER1_WAKEUP_OFFSET(1)
> +#define PMU_AP_CORE6_WAKEUP                    PMU_AP_CLUSTER1_WAKEUP_OFFSET(2)
> +#define PMU_AP_CORE7_WAKEUP                    PMU_AP_CLUSTER1_WAKEUP_OFFSET(3)
> +
> +#define PMU_AP_CORE0_IDLE_CFG                  PMU_AP_CLUSTER0_IDLE_CFG_OFFSET(0)
> +#define PMU_AP_CORE1_IDLE_CFG                  PMU_AP_CLUSTER0_IDLE_CFG_OFFSET(1)
> +#define PMU_AP_CORE2_IDLE_CFG                  PMU_AP_CLUSTER0_IDLE_CFG_OFFSET(2)
> +#define PMU_AP_CORE3_IDLE_CFG                  PMU_AP_CLUSTER0_IDLE_CFG_OFFSET(3)
> +#define PMU_AP_CORE4_IDLE_CFG                  PMU_AP_CLUSTER1_IDLE_CFG_OFFSET(0)
> +#define PMU_AP_CORE5_IDLE_CFG                  PMU_AP_CLUSTER1_IDLE_CFG_OFFSET(1)
> +#define PMU_AP_CORE6_IDLE_CFG                  PMU_AP_CLUSTER1_IDLE_CFG_OFFSET(2)
> +#define PMU_AP_CORE7_IDLE_CFG                  PMU_AP_CLUSTER1_IDLE_CFG_OFFSET(3)
> +
> +/* 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                     0xd4282c04
> +
> +#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)
> +
> +/* 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
> +
> +#endif
> diff --git a/platform/generic/spacemit/k1.c b/platform/generic/spacemit/k1.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..296365e9c4a7993a3a3560d17aeeeda71520c2b6
> --- /dev/null
> +++ b/platform/generic/spacemit/k1.c
> @@ -0,0 +1,119 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SpacemiT
> + * Authors:
> + *   Xianbin Zhu <xianbin.zhu at linux.spacemit.com>
> + *   Troy Mitchell <troy.mitchell at linux.spacemit.com>
> + */
> +
> +#include <platform_override.h>
> +#include <sbi/riscv_io.h>
> +#include <sbi/sbi_hsm.h>
> +#include <spacemit/k1.h>
> +
> +/* only use 0-1 cluster in SpacemiT K1 */
> +static const int cci_map[] = {
> +       PLAT_CCI_CLUSTER0_IFACE_IX,
> +       PLAT_CCI_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;
> +       struct sbi_scratch *scratch;
> +       int i;
> +
> +       scratch = sbi_scratch_thishart_ptr();
> +
> +       writel(scratch->warmboot_addr, (unsigned int *)C0_RVBADDR_LO_ADDR);
> +       writel(scratch->warmboot_addr >> 32, (unsigned int *)C0_RVBADDR_HI_ADDR);
> +
> +       writel(scratch->warmboot_addr, (unsigned int *)C1_RVBADDR_LO_ADDR);
> +       writel(scratch->warmboot_addr >> 32, (unsigned int *)C1_RVBADDR_HI_ADDR);
> +
> +       for (i = 0; i < PLATFORM_MAX_CPUS; i++) {
> +               clusterid = CPU_TO_CLUSTER(i);
> +
> +               if (!(cluster_enabled & (1 << clusterid))) {
> +                       cluster_enabled |= 1 << clusterid;
> +                       cci_enable_snoop_dvm_reqs(clusterid);
> +               }
> +       }
> +}
> +
> +/*
> + * Platform early initialization.
> + */
> +static int spacemit_k1_early_init(bool cold_boot)
> +{
> +       int rc;
> +
> +       rc = generic_early_init(cold_boot);
> +       if (rc)
> +               return rc;
> +
> +       csr_set(CSR_MSETUP, MSETUP_DE | MSETUP_IE | MSETUP_BPE |
> +               MSETUP_PFE | MSETUP_MME | MSETUP_ECCE);
> +
> +       if (cold_boot)
> +               spacemit_k1_pre_init();
> +
> +       return 0;
> +}
> +
> +static int spacemit_k1_final_init(bool cold_boot)
> +{
> +       return generic_final_init(cold_boot);
> +}

The spacemit_k1_final_init() is redundant because it does nothing
and falls back to generic_final_init();

> +
> +static bool spacemit_cold_boot_allowed(u32 hartid)
> +{
> +       csr_set(CSR_ML2SETUP, 1 << (hartid % PLATFORM_MAX_CPUS_PER_CLUSTER));
> +
> +       return !hartid;

For now it's okay but try to avoid register programming
spacemit_cold_boot_allowed().

> +}
> +
> +static int spacemit_k1_platform_init(const void *fdt, int nodeoff,
> +                                    const struct fdt_match *match)
> +{
> +       generic_platform_ops.early_init = spacemit_k1_early_init;
> +       generic_platform_ops.final_init = spacemit_k1_final_init;
> +       generic_platform_ops.cold_boot_allowed = spacemit_cold_boot_allowed;
> +
> +       return 0;
> +}
> +
> +static const struct fdt_match spacemit_k1_match[] = {
> +       { .compatible = "spacemit,k1" },
> +       { /* sentinel */ }
> +};
> +
> +const struct fdt_driver spacemit_k1 = {
> +       .match_table = spacemit_k1_match,
> +       .init = spacemit_k1_platform_init,
> +};
>
> --
> 2.51.0
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi

Otherwise, this looks good to me. I have dropped
spacemit_k1_final_init() at the time of merging.

Reviewed-by: Anup Patel <anup at brainfault.org>

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup



More information about the opensbi mailing list