From anup at brainfault.org  Mon Aug  4 01:36:14 2025
From: anup at brainfault.org (Anup Patel)
Date: Mon, 4 Aug 2025 14:06:14 +0530
Subject: [PATCH v3 01/12] lib: utils: Add cache flush library
In-Reply-To: <20250708074940.10904-2-nick.hu@sifive.com>
References: <20250708074940.10904-1-nick.hu@sifive.com> <20250708074940.10904-2-nick.hu@sifive.com>
Message-ID: <CAAhSdy1TqvpafvDX2Dp+7DrSCynuy=G62yciOFhe+RTW-8QdoA@mail.gmail.com>

On Tue, Jul 8, 2025 at 1:19?PM Nick Hu <nick.hu at sifive.com> wrote:
>
> The current RISC-V CMO only defines how to flush a cache block. However,
> certain use cases, such as power management, may require flushing the
> entire cache. Therefore, a framework is being introduced to allow vendors
> to flush the entire cache using their own methods.
>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Samuel Holland <samuel.holland at sifive.com>

LGTM.

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

Regards,
Anup



> ---
>  include/sbi_utils/cache/cache.h | 69 +++++++++++++++++++++++++++++++++
>  lib/utils/Kconfig               |  2 +
>  lib/utils/cache/Kconfig         |  9 +++++
>  lib/utils/cache/cache.c         | 46 ++++++++++++++++++++++
>  lib/utils/cache/objects.mk      |  7 ++++
>  5 files changed, 133 insertions(+)
>  create mode 100644 include/sbi_utils/cache/cache.h
>  create mode 100644 lib/utils/cache/Kconfig
>  create mode 100644 lib/utils/cache/cache.c
>  create mode 100644 lib/utils/cache/objects.mk
>
> diff --git a/include/sbi_utils/cache/cache.h b/include/sbi_utils/cache/cache.h
> new file mode 100644
> index 00000000..70d9286f
> --- /dev/null
> +++ b/include/sbi_utils/cache/cache.h
> @@ -0,0 +1,69 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#ifndef __CACHE_H__
> +#define __CACHE_H__
> +
> +#include <sbi/sbi_list.h>
> +#include <sbi/sbi_types.h>
> +
> +#define CACHE_NAME_LEN 32
> +
> +struct cache_device;
> +
> +struct cache_ops {
> +       /** Warm init **/
> +       int (*warm_init)(struct cache_device *dev);
> +       /** Flush entire cache **/
> +       int (*cache_flush_all)(struct cache_device *dev);
> +};
> +
> +struct cache_device {
> +       /** Name of the device **/
> +       char name[CACHE_NAME_LEN];
> +       /** List node for search **/
> +       struct sbi_dlist node;
> +       /** Point to the next level cache **/
> +       struct cache_device *next;
> +       /** Cache Management Operations **/
> +       struct cache_ops *ops;
> +       /** CPU private cache **/
> +       bool cpu_private;
> +       /** The unique id of this cache device **/
> +       u32 id;
> +};
> +
> +/**
> + * Find a registered cache device
> + *
> + * @param id unique ID of the cache device
> + *
> + * @return the cache device or NULL
> + */
> +struct cache_device *cache_find(u32 id);
> +
> +/**
> + * Register a cache device
> + *
> + * cache_device->id must be initialized already and must not change during the life
> + * of the cache_device object.
> + *
> + * @param dev the cache device to register
> + *
> + * @return 0 on success, or a negative error code on failure
> + */
> +int cache_add(struct cache_device *dev);
> +
> +/**
> + * Flush the entire cache
> + *
> + * @param dev the cache to flush
> + *
> + * @return 0 on success, or a negative error code on failure
> + */
> +int cache_flush_all(struct cache_device *dev);
> +
> +#endif
> diff --git a/lib/utils/Kconfig b/lib/utils/Kconfig
> index 901ba564..5a5b3b1e 100644
> --- a/lib/utils/Kconfig
> +++ b/lib/utils/Kconfig
> @@ -2,6 +2,8 @@
>
>  menu "Utils and Drivers Support"
>
> +source "$(OPENSBI_SRC_DIR)/lib/utils/cache/Kconfig"
> +
>  source "$(OPENSBI_SRC_DIR)/lib/utils/cppc/Kconfig"
>
>  source "$(OPENSBI_SRC_DIR)/lib/utils/fdt/Kconfig"
> diff --git a/lib/utils/cache/Kconfig b/lib/utils/cache/Kconfig
> new file mode 100644
> index 00000000..24aa41bc
> --- /dev/null
> +++ b/lib/utils/cache/Kconfig
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: BSD-2-Clause
> +
> +menu "Cache Support"
> +
> +config CACHE
> +       bool "Cache support"
> +       default n
> +
> +endmenu
> diff --git a/lib/utils/cache/cache.c b/lib/utils/cache/cache.c
> new file mode 100644
> index 00000000..6bc3d10e
> --- /dev/null
> +++ b/lib/utils/cache/cache.c
> @@ -0,0 +1,46 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#include <sbi/sbi_error.h>
> +#include <sbi_utils/cache/cache.h>
> +
> +static SBI_LIST_HEAD(cache_list);
> +
> +struct cache_device *cache_find(u32 id)
> +{
> +       struct cache_device *dev;
> +
> +       sbi_list_for_each_entry(dev, &cache_list, node) {
> +               if (dev->id == id)
> +                       return dev;
> +       }
> +
> +       return NULL;
> +}
> +
> +int cache_add(struct cache_device *dev)
> +{
> +       if (!dev)
> +               return SBI_ENODEV;
> +
> +       if (cache_find(dev->id))
> +               return SBI_EALREADY;
> +
> +       sbi_list_add(&dev->node, &cache_list);
> +
> +       return SBI_OK;
> +}
> +
> +int cache_flush_all(struct cache_device *dev)
> +{
> +       if (!dev)
> +               return SBI_ENODEV;
> +
> +       if (!dev->ops || !dev->ops->cache_flush_all)
> +               return SBI_ENOTSUPP;
> +
> +       return dev->ops->cache_flush_all(dev);
> +}
> diff --git a/lib/utils/cache/objects.mk b/lib/utils/cache/objects.mk
> new file mode 100644
> index 00000000..21d30ce8
> --- /dev/null
> +++ b/lib/utils/cache/objects.mk
> @@ -0,0 +1,7 @@
> +#
> +# SPDX-License-Identifier: BSD-2-Clause
> +#
> +# Copyright (c) 2025 SiFive
> +#
> +
> +libsbiutils-objs-$(CONFIG_CACHE) += cache/cache.o
> --
> 2.17.1
>


From anup at brainfault.org  Mon Aug  4 01:36:22 2025
From: anup at brainfault.org (Anup Patel)
Date: Mon, 4 Aug 2025 14:06:22 +0530
Subject: [PATCH v3 02/12] lib: utils: Add FDT cache library
In-Reply-To: <20250708074940.10904-3-nick.hu@sifive.com>
References: <20250708074940.10904-1-nick.hu@sifive.com> <20250708074940.10904-3-nick.hu@sifive.com>
Message-ID: <CAAhSdy2cqoNO=grfeiw1_ZksTZLwLG3pr34TpoHeh=zLYmnuhg@mail.gmail.com>

On Tue, Jul 8, 2025 at 1:19?PM Nick Hu <nick.hu at sifive.com> wrote:
>
> Add the FDT cache library so we can build up the cache topology via the
> 'next-level-cache' DT property.
>
> Co-developed-by: Vincent Chen <vincent.chen at sifive.com>
> Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
> Co-developed-by: Andy Chiu <andy.chiu at sifive.com>
> Signed-off-by: Andy Chiu <andy.chiu at sifive.com>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Samuel Holland <samuel.holland at sifive.com>

LGTM.

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

Regards,
Anup


> ---
>  include/sbi_utils/cache/fdt_cache.h      | 34 +++++++++
>  lib/utils/cache/Kconfig                  |  6 ++
>  lib/utils/cache/fdt_cache.c              | 87 ++++++++++++++++++++++++
>  lib/utils/cache/fdt_cache_drivers.carray |  3 +
>  lib/utils/cache/objects.mk               |  3 +
>  platform/generic/configs/defconfig       |  1 +
>  6 files changed, 134 insertions(+)
>  create mode 100644 include/sbi_utils/cache/fdt_cache.h
>  create mode 100644 lib/utils/cache/fdt_cache.c
>  create mode 100644 lib/utils/cache/fdt_cache_drivers.carray
>
> diff --git a/include/sbi_utils/cache/fdt_cache.h b/include/sbi_utils/cache/fdt_cache.h
> new file mode 100644
> index 00000000..b377d6f5
> --- /dev/null
> +++ b/include/sbi_utils/cache/fdt_cache.h
> @@ -0,0 +1,34 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#ifndef __FDT_CACHE_H__
> +#define __FDT_CACHE_H__
> +
> +#include <sbi_utils/cache/cache.h>
> +
> +/**
> + * Register a cache device using information from the DT
> + *
> + * @param fdt devicetree blob
> + * @param noff offset of a node in the devicetree blob
> + * @param dev cache device to register for this devicetree node
> + *
> + * @return 0 on success, or a negative error code on failure
> + */
> +int fdt_cache_add(const void *fdt, int noff, struct cache_device *dev);
> +
> +/**
> + * Get the cache device referencd by the "next-level-cache" property of a DT node
> + *
> + * @param fdt devicetree blob
> + * @param noff offset of a node in the devicetree blob
> + * @param out_dev location to return the cache device
> + *
> + * @return 0 on success, or a negative error code on failure
> + */
> +int fdt_next_cache_get(const void *fdt, int noff, struct cache_device **out_dev);
> +
> +#endif
> diff --git a/lib/utils/cache/Kconfig b/lib/utils/cache/Kconfig
> index 24aa41bc..10602176 100644
> --- a/lib/utils/cache/Kconfig
> +++ b/lib/utils/cache/Kconfig
> @@ -2,6 +2,12 @@
>
>  menu "Cache Support"
>
> +config FDT_CACHE
> +       bool "FDT based cache drivers"
> +       depends on FDT
> +       select CACHE
> +       default n
> +
>  config CACHE
>         bool "Cache support"
>         default n
> diff --git a/lib/utils/cache/fdt_cache.c b/lib/utils/cache/fdt_cache.c
> new file mode 100644
> index 00000000..e1c6f67c
> --- /dev/null
> +++ b/lib/utils/cache/fdt_cache.c
> @@ -0,0 +1,87 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#include <libfdt.h>
> +#include <sbi/sbi_console.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_heap.h>
> +#include <sbi_utils/cache/fdt_cache.h>
> +#include <sbi_utils/fdt/fdt_driver.h>
> +
> +/* List of FDT cache drivers generated at compile time */
> +extern const struct fdt_driver *const fdt_cache_drivers[];
> +
> +int fdt_cache_add(const void *fdt, int noff, struct cache_device *dev)
> +{
> +       int rc;
> +
> +       dev->id = noff;
> +       sbi_strncpy(dev->name, fdt_get_name(fdt, noff, NULL), sizeof(dev->name) - 1);
> +       sbi_dprintf("%s: %s\n", __func__, dev->name);
> +
> +       rc = fdt_next_cache_get(fdt, noff, &dev->next);
> +       if (rc)
> +               return rc;
> +
> +       return cache_add(dev);
> +}
> +
> +static int fdt_cache_add_generic(const void *fdt, int noff)
> +{
> +       struct cache_device *dev;
> +       int rc;
> +
> +       dev = sbi_zalloc(sizeof(*dev));
> +       if (!dev)
> +               return SBI_ENOMEM;
> +
> +       rc = fdt_cache_add(fdt, noff, dev);
> +       if (rc) {
> +               sbi_free(dev);
> +               return rc;
> +       }
> +
> +       return 0;
> +}
> +
> +static int fdt_cache_find(const void *fdt, int noff, struct cache_device **out_dev)
> +{
> +       struct cache_device *dev = cache_find(noff);
> +       int rc;
> +
> +       if (!dev) {
> +               rc = fdt_driver_init_by_offset(fdt, noff, fdt_cache_drivers);
> +               if (rc == SBI_ENODEV)
> +                       rc = fdt_cache_add_generic(fdt, noff);
> +               if (rc)
> +                       return rc;
> +
> +               dev = cache_find(noff);
> +               if (!dev)
> +                       return SBI_EFAIL;
> +       }
> +
> +       if (out_dev)
> +               *out_dev = dev;
> +
> +       return SBI_OK;
> +}
> +
> +int fdt_next_cache_get(const void *fdt, int noff, struct cache_device **out_dev)
> +{
> +       const fdt32_t *val;
> +       int len;
> +
> +       val = fdt_getprop(fdt, noff, "next-level-cache", &len);
> +       if (!val || len < sizeof(*val))
> +               return SBI_OK;
> +
> +       noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(val[0]));
> +       if (noff < 0)
> +               return noff;
> +
> +       return fdt_cache_find(fdt, noff, out_dev);
> +}
> diff --git a/lib/utils/cache/fdt_cache_drivers.carray b/lib/utils/cache/fdt_cache_drivers.carray
> new file mode 100644
> index 00000000..c1b1791c
> --- /dev/null
> +++ b/lib/utils/cache/fdt_cache_drivers.carray
> @@ -0,0 +1,3 @@
> +HEADER: sbi_utils/cache/fdt_cache.h
> +TYPE: const struct fdt_driver
> +NAME: fdt_cache_drivers
> diff --git a/lib/utils/cache/objects.mk b/lib/utils/cache/objects.mk
> index 21d30ce8..2fcf9666 100644
> --- a/lib/utils/cache/objects.mk
> +++ b/lib/utils/cache/objects.mk
> @@ -4,4 +4,7 @@
>  # Copyright (c) 2025 SiFive
>  #
>
> +libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache.o
> +libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache_drivers.carray.o
> +
>  libsbiutils-objs-$(CONFIG_CACHE) += cache/cache.o
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index c7a6531e..b5a7993d 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -7,6 +7,7 @@ CONFIG_PLATFORM_SOPHGO_SG2042=y
>  CONFIG_PLATFORM_STARFIVE_JH7110=y
>  CONFIG_PLATFORM_THEAD=y
>  CONFIG_PLATFORM_MIPS_P8700=y
> +CONFIG_FDT_CACHE=y
>  CONFIG_FDT_CPPC=y
>  CONFIG_FDT_CPPC_RPMI=y
>  CONFIG_FDT_GPIO=y
> --
> 2.17.1
>


From anup at brainfault.org  Mon Aug  4 01:36:28 2025
From: anup at brainfault.org (Anup Patel)
Date: Mon, 4 Aug 2025 14:06:28 +0530
Subject: [PATCH v3 03/12] utils: cache: Add SiFive ccache controller
In-Reply-To: <20250708074940.10904-4-nick.hu@sifive.com>
References: <20250708074940.10904-1-nick.hu@sifive.com> <20250708074940.10904-4-nick.hu@sifive.com>
Message-ID: <CAAhSdy32VoFMwpN-=heupaORsZ=QeJS654LxuUy55GKABkbneg@mail.gmail.com>

On Tue, Jul 8, 2025 at 1:20?PM Nick Hu <nick.hu at sifive.com> wrote:
>
> From: Vincent Chen <vincent.chen at sifive.com>
>
> SiFive Composable cache is a L3 share cache of the core complex. Add this
> driver to support the share cache maintenance operations via the MMIO
> registers.
>
> Co-developed-by: Samuel Holland <samuel.holland at sifive.com>
> Signed-off-by: Samuel Holland <samuel.holland at sifive.com>
> Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
> Co-developed-by: Nick Hu <nick.hu at sifive.com>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Samuel Holland <samuel.holland at sifive.com>

LGTM.

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

Regards,
Anup


> ---
>  lib/utils/cache/Kconfig             |   8 ++
>  lib/utils/cache/fdt_sifive_ccache.c | 175 ++++++++++++++++++++++++++++
>  lib/utils/cache/objects.mk          |   3 +
>  platform/generic/configs/defconfig  |   1 +
>  4 files changed, 187 insertions(+)
>  create mode 100644 lib/utils/cache/fdt_sifive_ccache.c
>
> diff --git a/lib/utils/cache/Kconfig b/lib/utils/cache/Kconfig
> index 10602176..1c7abdc9 100644
> --- a/lib/utils/cache/Kconfig
> +++ b/lib/utils/cache/Kconfig
> @@ -8,6 +8,14 @@ config FDT_CACHE
>         select CACHE
>         default n
>
> +if FDT_CACHE
> +
> +config FDT_CACHE_SIFIVE_CCACHE
> +       bool "SiFive CCACHE FDT cache driver"
> +       default n
> +
> +endif
> +
>  config CACHE
>         bool "Cache support"
>         default n
> diff --git a/lib/utils/cache/fdt_sifive_ccache.c b/lib/utils/cache/fdt_sifive_ccache.c
> new file mode 100644
> index 00000000..ad7511b5
> --- /dev/null
> +++ b/lib/utils/cache/fdt_sifive_ccache.c
> @@ -0,0 +1,175 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#include <libfdt.h>
> +#include <sbi/riscv_barrier.h>
> +#include <sbi/riscv_io.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_heap.h>
> +#include <sbi_utils/cache/fdt_cache.h>
> +#include <sbi_utils/fdt/fdt_driver.h>
> +
> +#define CCACHE_CFG_CSR                 0
> +#define CCACHE_CMD_CSR                 0x280
> +#define CCACHE_STATUS_CSR              0x288
> +
> +#define CFG_CSR_BANK_MASK              0xff
> +#define CFG_CSR_WAY_MASK               0xff00
> +#define CFG_CSR_WAY_OFFSET             8
> +#define CFG_CSR_SET_MASK               0xff0000
> +#define CFG_CSR_SET_OFFSET             16
> +
> +#define CMD_CSR_CMD_OFFSET     56
> +#define CMD_CSR_BANK_OFFSET    6
> +
> +#define CMD_OPCODE_SETWAY      0x1ULL
> +#define CMD_OPCODE_OFFSET      0x2ULL
> +
> +#define CFLUSH_SETWAY_CLEANINV  ((CMD_OPCODE_SETWAY << CMD_OPCODE_OFFSET) | 0x3)
> +
> +#define CCACHE_CMD_QLEN        0xff
> +
> +#define ccache_mb_b()          RISCV_FENCE(rw, o)
> +#define ccache_mb_a()          RISCV_FENCE(o, rw)
> +
> +#define CCACHE_ALL_OP_REQ_BATCH_NUM    0x10
> +#define CCACHE_ALL_OP_REQ_BATCH_MASK (CCACHE_CMD_QLEN + 1 - CCACHE_ALL_OP_REQ_BATCH_NUM)
> +
> +struct sifive_ccache {
> +       struct cache_device dev;
> +       void *addr;
> +       u64 total_lines;
> +};
> +
> +#define to_ccache(_dev) container_of(_dev, struct sifive_ccache, dev)
> +
> +static inline unsigned int sifive_ccache_read_status(void *status_addr)
> +{
> +       return readl_relaxed(status_addr);
> +}
> +
> +static inline void sifive_ccache_write_cmd(u64 cmd, void *cmd_csr_addr)
> +{
> +#if __riscv_xlen != 32
> +       writeq_relaxed(cmd, cmd_csr_addr);
> +#else
> +       /*
> +        * The cache maintenance request is only generated when the "command"
> +        * field (part of the high word) is written.
> +        */
> +       writel_relaxed(cmd, cmd_csr_addr);
> +       writel(cmd >> 32, cmd_csr_addr + 4);
> +#endif
> +}
> +
> +static int sifive_ccache_flush_all(struct cache_device *dev)
> +{
> +       struct sifive_ccache *ccache = to_ccache(dev);
> +       void *status_addr = (char *)ccache->addr + CCACHE_STATUS_CSR;
> +       void *cmd_csr_addr = (char *)ccache->addr + CCACHE_CMD_CSR;
> +       u64 total_cnt = ccache->total_lines;
> +       u64 cmd = CFLUSH_SETWAY_CLEANINV << CMD_CSR_CMD_OFFSET;
> +       int loop_cnt = CCACHE_CMD_QLEN & CCACHE_ALL_OP_REQ_BATCH_MASK;
> +
> +       ccache_mb_b();
> +send_cmd:
> +       total_cnt -= loop_cnt;
> +       while (loop_cnt > 0) {
> +               sifive_ccache_write_cmd(cmd + (0 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (1 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (2 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (3 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (4 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (5 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (6 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (7 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (8 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (9 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (10 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (11 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (12 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (13 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (14 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               sifive_ccache_write_cmd(cmd + (15 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
> +               cmd += CCACHE_ALL_OP_REQ_BATCH_NUM << CMD_CSR_BANK_OFFSET;
> +               loop_cnt -= CCACHE_ALL_OP_REQ_BATCH_NUM;
> +       }
> +       if (!total_cnt)
> +               goto done;
> +
> +       /* Ensure the ccache is able receive more than 16 requests */
> +       do {
> +               loop_cnt = (CCACHE_CMD_QLEN - sifive_ccache_read_status(status_addr));
> +       } while (loop_cnt < CCACHE_ALL_OP_REQ_BATCH_NUM);
> +       loop_cnt &= CCACHE_ALL_OP_REQ_BATCH_MASK;
> +
> +       if (total_cnt < loop_cnt) {
> +               loop_cnt = (total_cnt + CCACHE_ALL_OP_REQ_BATCH_NUM) & CCACHE_ALL_OP_REQ_BATCH_MASK;
> +               cmd -= ((loop_cnt - total_cnt) << CMD_CSR_BANK_OFFSET);
> +               total_cnt = loop_cnt;
> +       }
> +       goto send_cmd;
> +done:
> +       do {} while (sifive_ccache_read_status(status_addr));
> +       ccache_mb_a();
> +
> +       return 0;
> +}
> +
> +static struct cache_ops sifive_ccache_ops = {
> +       .cache_flush_all = sifive_ccache_flush_all,
> +};
> +
> +static int sifive_ccache_cold_init(const void *fdt, int nodeoff, const struct fdt_match *match)
> +{
> +       struct sifive_ccache *ccache;
> +       struct cache_device *dev;
> +       u64 reg_addr = 0;
> +       u32 config_csr, banks, sets, ways;
> +       int rc;
> +
> +       /** find the ccache base control address **/
> +       rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, NULL);
> +       if (rc < 0 && reg_addr)
> +               return SBI_ENODEV;
> +
> +       ccache = sbi_zalloc(sizeof(*ccache));
> +       if (!ccache)
> +               return SBI_ENOMEM;
> +
> +       dev = &ccache->dev;
> +       dev->ops = &sifive_ccache_ops;
> +       rc = fdt_cache_add(fdt, nodeoff, dev);
> +       if (rc) {
> +               sbi_free(ccache);
> +               return rc;
> +       }
> +
> +       ccache->addr = (void *)(uintptr_t)reg_addr;
> +
> +       /** get the info of ccache from config CSR **/
> +       config_csr = readl((char *)reg_addr + CCACHE_CFG_CSR);
> +       banks = config_csr & CFG_CSR_BANK_MASK;
> +
> +       sets = (config_csr & CFG_CSR_SET_MASK) >> CFG_CSR_SET_OFFSET;
> +       sets = (1 << sets);
> +
> +       ways = (config_csr & CFG_CSR_WAY_MASK) >> CFG_CSR_WAY_OFFSET;
> +
> +       ccache->total_lines = sets * ways * banks;
> +
> +       return SBI_OK;
> +}
> +
> +static const struct fdt_match sifive_ccache_match[] = {
> +       { .compatible = "sifive,ccache2" },
> +       {},
> +};
> +
> +const struct fdt_driver fdt_sifive_ccache = {
> +       .match_table = sifive_ccache_match,
> +       .init = sifive_ccache_cold_init,
> +};
> diff --git a/lib/utils/cache/objects.mk b/lib/utils/cache/objects.mk
> index 2fcf9666..a343eb8c 100644
> --- a/lib/utils/cache/objects.mk
> +++ b/lib/utils/cache/objects.mk
> @@ -7,4 +7,7 @@
>  libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache.o
>  libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache_drivers.carray.o
>
> +carray-fdt_cache_drivers-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += fdt_sifive_ccache
> +libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += cache/fdt_sifive_ccache.o
> +
>  libsbiutils-objs-$(CONFIG_CACHE) += cache/cache.o
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index b5a7993d..6b219cfb 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -8,6 +8,7 @@ CONFIG_PLATFORM_STARFIVE_JH7110=y
>  CONFIG_PLATFORM_THEAD=y
>  CONFIG_PLATFORM_MIPS_P8700=y
>  CONFIG_FDT_CACHE=y
> +CONFIG_FDT_CACHE_SIFIVE_CCACHE=y
>  CONFIG_FDT_CPPC=y
>  CONFIG_FDT_CPPC_RPMI=y
>  CONFIG_FDT_GPIO=y
> --
> 2.17.1
>


From anup at brainfault.org  Mon Aug  4 01:37:19 2025
From: anup at brainfault.org (Anup Patel)
Date: Mon, 4 Aug 2025 14:07:19 +0530
Subject: [PATCH v3 04/12] lib: utils/cache: Add fdt cmo helpers
In-Reply-To: <20250708074940.10904-5-nick.hu@sifive.com>
References: <20250708074940.10904-1-nick.hu@sifive.com> <20250708074940.10904-5-nick.hu@sifive.com>
Message-ID: <CAAhSdy21t67pZM_jDtH12oh+W6WNyz5z_rV3-GDTE9XBbujF9Q@mail.gmail.com>

On Tue, Jul 8, 2025 at 1:20?PM Nick Hu <nick.hu at sifive.com> wrote:
>
> Add the helpers to build up the cache hierarchy via FDT and provide some
> cmo functions for the user who want to flush the entire cache.
>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Samuel Holland <samuel.holland at sifive.com>

LGTM.

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

Regards,
Anup


> ---
>  include/sbi_utils/cache/fdt_cmo_helper.h |  34 +++++++
>  lib/utils/cache/fdt_cmo_helper.c         | 112 +++++++++++++++++++++++
>  lib/utils/cache/objects.mk               |   1 +
>  3 files changed, 147 insertions(+)
>  create mode 100644 include/sbi_utils/cache/fdt_cmo_helper.h
>  create mode 100644 lib/utils/cache/fdt_cmo_helper.c
>
> diff --git a/include/sbi_utils/cache/fdt_cmo_helper.h b/include/sbi_utils/cache/fdt_cmo_helper.h
> new file mode 100644
> index 00000000..4275725e
> --- /dev/null
> +++ b/include/sbi_utils/cache/fdt_cmo_helper.h
> @@ -0,0 +1,34 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#ifndef __FDT_CMO_HELPER_H__
> +#define __FDT_CMO_HELPER_H__
> +
> +/**
> + * Flush the private first level cache of the current hart
> + *
> + * @return 0 on success, or a negative error code on failure
> + */
> +int fdt_cmo_private_flc_flush_all(void);
> +
> +/**
> + * Flush the last level cache of the current hart
> + *
> + * @return 0 on success, or a negative error code on failure
> + */
> +int fdt_cmo_llc_flush_all(void);
> +
> +/**
> + * Initialize the cache devices for each hart
> + *
> + * @param fdt devicetree blob
> + * @param cold_boot cold init or warm init
> + *
> + * @return 0 on success, or a negative error code on failure
> + */
> +int fdt_cmo_init(bool cold_boot);
> +
> +#endif
> diff --git a/lib/utils/cache/fdt_cmo_helper.c b/lib/utils/cache/fdt_cmo_helper.c
> new file mode 100644
> index 00000000..6d2e853d
> --- /dev/null
> +++ b/lib/utils/cache/fdt_cmo_helper.c
> @@ -0,0 +1,112 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#include <libfdt.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_scratch.h>
> +#include <sbi_utils/cache/fdt_cache.h>
> +#include <sbi_utils/cache/fdt_cmo_helper.h>
> +#include <sbi_utils/fdt/fdt_helper.h>
> +
> +static unsigned long flc_offset;
> +
> +#define get_hart_flc(_s) \
> +       sbi_scratch_read_type(_s, struct cache_device *, flc_offset)
> +#define set_hart_flc(_s, _p) \
> +       sbi_scratch_write_type(_s, struct cache_device *, flc_offset, _p)
> +
> +int fdt_cmo_private_flc_flush_all(void)
> +{
> +       struct cache_device *flc = get_hart_flc(sbi_scratch_thishart_ptr());
> +
> +       if (!flc || !flc->cpu_private)
> +               return SBI_ENODEV;
> +
> +       return cache_flush_all(flc);
> +}
> +
> +int fdt_cmo_llc_flush_all(void)
> +{
> +       struct cache_device *llc = get_hart_flc(sbi_scratch_thishart_ptr());
> +
> +       if (!llc)
> +               return SBI_ENODEV;
> +
> +       while (llc->next)
> +               llc = llc->next;
> +
> +       return cache_flush_all(llc);
> +}
> +
> +static int fdt_cmo_cold_init(const void *fdt)
> +{
> +       struct sbi_scratch *scratch;
> +       struct cache_device *dev;
> +       int cpu_offset, cpus_offset, rc;
> +       u32 hartid;
> +
> +       cpus_offset = fdt_path_offset(fdt, "/cpus");
> +       if (cpus_offset < 0)
> +               return SBI_EINVAL;
> +
> +       fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
> +               rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
> +               if (rc)
> +                       continue;
> +
> +               scratch = sbi_hartid_to_scratch(hartid);
> +               if (!scratch)
> +                       continue;
> +
> +               rc = fdt_next_cache_get(fdt, cpu_offset, &dev);
> +               if (rc)
> +                       return rc;
> +
> +               set_hart_flc(scratch, dev);
> +       }
> +
> +       return SBI_OK;
> +}
> +
> +static int fdt_cmo_warm_init(void)
> +{
> +       struct cache_device *cur = get_hart_flc(sbi_scratch_thishart_ptr());
> +       int rc;
> +
> +       while (cur) {
> +               if (cur->ops && cur->ops->warm_init) {
> +                       rc = cur->ops->warm_init(cur);
> +                       if (rc)
> +                               return rc;
> +               }
> +
> +               cur = cur->next;
> +       }
> +
> +       return SBI_OK;
> +}
> +
> +int fdt_cmo_init(bool cold_boot)
> +{
> +       const void *fdt = fdt_get_address();
> +       int rc;
> +
> +       if (cold_boot) {
> +               flc_offset = sbi_scratch_alloc_type_offset(struct cache_device *);
> +               if (!flc_offset)
> +                       return SBI_ENOMEM;
> +
> +               rc = fdt_cmo_cold_init(fdt);
> +               if (rc)
> +                       return rc;
> +       }
> +
> +       rc = fdt_cmo_warm_init();
> +       if (rc)
> +               return rc;
> +
> +       return SBI_OK;
> +}
> diff --git a/lib/utils/cache/objects.mk b/lib/utils/cache/objects.mk
> index a343eb8c..6829a966 100644
> --- a/lib/utils/cache/objects.mk
> +++ b/lib/utils/cache/objects.mk
> @@ -6,6 +6,7 @@
>
>  libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache.o
>  libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache_drivers.carray.o
> +libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cmo_helper.o
>
>  carray-fdt_cache_drivers-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += fdt_sifive_ccache
>  libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += cache/fdt_sifive_ccache.o
> --
> 2.17.1
>


From anup at brainfault.org  Mon Aug  4 01:37:32 2025
From: anup at brainfault.org (Anup Patel)
Date: Mon, 4 Aug 2025 14:07:32 +0530
Subject: [PATCH v3 05/12] platform: generic: Add SiFive development platform
In-Reply-To: <20250708074940.10904-6-nick.hu@sifive.com>
References: <20250708074940.10904-1-nick.hu@sifive.com> <20250708074940.10904-6-nick.hu@sifive.com>
Message-ID: <CAAhSdy2+zx8NWFQ8O7-qPNpkb7Xu_8VrNha7+JaBskU1L-woDw@mail.gmail.com>

On Tue, Jul 8, 2025 at 1:20?PM Nick Hu <nick.hu at sifive.com> wrote:
>
> From: Vincent Chen <vincent.chen at sifive.com>
>
> The sifive_dev_platform is a new platform which is compatible to the
> generic platform to place some features which are only for the SiFive
> development machine.
>
> Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
> Co-developed-by: Nick Hu <nick.hu at sifive.com>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> ---
>  platform/generic/Kconfig                      |  5 +++
>  platform/generic/configs/defconfig            |  1 +
>  platform/generic/sifive/objects.mk            |  3 ++
>  platform/generic/sifive/sifive_dev_platform.c | 41 +++++++++++++++++++
>  4 files changed, 50 insertions(+)
>  create mode 100644 platform/generic/sifive/sifive_dev_platform.c
>
> diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
> index a24d6ab2..20c25a83 100644
> --- a/platform/generic/Kconfig
> +++ b/platform/generic/Kconfig
> @@ -43,6 +43,11 @@ config PLATFORM_RENESAS_RZFIVE
>         select ANDES_PMU
>         default n
>
> +config PLATFORM_SIFIVE_DEV
> +       bool "SiFive development platform support"
> +       depends on FDT_CACHE
> +       default n
> +
>  config PLATFORM_SIFIVE_FU540
>         bool "SiFive FU540 support"
>         default n
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index 6b219cfb..42e7ef75 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -1,6 +1,7 @@
>  CONFIG_PLATFORM_ALLWINNER_D1=y
>  CONFIG_PLATFORM_ANDES_AE350=y
>  CONFIG_PLATFORM_RENESAS_RZFIVE=y
> +CONFIG_PLATFORM_SIFIVE_DEV=y
>  CONFIG_PLATFORM_SIFIVE_FU540=y
>  CONFIG_PLATFORM_SIFIVE_FU740=y
>  CONFIG_PLATFORM_SOPHGO_SG2042=y
> diff --git a/platform/generic/sifive/objects.mk b/platform/generic/sifive/objects.mk
> index d75e444a..d32e1273 100644
> --- a/platform/generic/sifive/objects.mk
> +++ b/platform/generic/sifive/objects.mk
> @@ -2,6 +2,9 @@
>  # SPDX-License-Identifier: BSD-2-Clause
>  #
>
> +carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_DEV) += sifive_dev_platform
> +platform-objs-$(CONFIG_PLATFORM_SIFIVE_DEV) += sifive/sifive_dev_platform.o
> +
>  carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive_fu540
>  platform-objs-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive/fu540.o
>
> diff --git a/platform/generic/sifive/sifive_dev_platform.c b/platform/generic/sifive/sifive_dev_platform.c
> new file mode 100644
> index 00000000..ac659868
> --- /dev/null
> +++ b/platform/generic/sifive/sifive_dev_platform.c
> @@ -0,0 +1,41 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#include <platform_override.h>
> +#include <sbi_utils/cache/fdt_cmo_helper.h>
> +
> +static int sifive_early_init(bool cold_boot)
> +{
> +       int rc;
> +
> +       rc = generic_early_init(cold_boot);
> +       if (rc)
> +               return rc;
> +
> +       rc = fdt_cmo_init(cold_boot);
> +       if (rc)
> +               return rc;

Why not call fdt_cmo_init() directly as part of generic_early_init() ?

> +
> +       return 0;
> +}
> +
> +static int sifive_platform_init(const void *fdt, int nodeoff,
> +                               const struct fdt_match *match)
> +{
> +       generic_platform_ops.early_init = sifive_early_init;
> +
> +       return 0;
> +}
> +
> +static const struct fdt_match sifive_dev_platform_match[] = {
> +       { .compatible = "sifive-dev" },
> +       { },
> +};
> +
> +const struct fdt_driver sifive_dev_platform = {
> +       .match_table = sifive_dev_platform_match,
> +       .init = sifive_platform_init,
> +};
> --
> 2.17.1
>

Regards,
Anup


From anup at brainfault.org  Mon Aug  4 01:38:33 2025
From: anup at brainfault.org (Anup Patel)
Date: Mon, 4 Aug 2025 14:08:33 +0530
Subject: [PATCH v3 06/12] lib: sbi: Add SiFive proprietary xsfcflushdlone
In-Reply-To: <20250708074940.10904-7-nick.hu@sifive.com>
References: <20250708074940.10904-1-nick.hu@sifive.com> <20250708074940.10904-7-nick.hu@sifive.com>
Message-ID: <CAAhSdy3WrRuuffYWQdxX2-4AMyUDtrYtuVTayPcQbcDz7hgogg@mail.gmail.com>

On Tue, Jul 8, 2025 at 1:20?PM Nick Hu <nick.hu at sifive.com> wrote:
>
> Using ISA string "xsfcflushdlone" to detect the support of the
> SiFive L1D cache flush custom instruction.
>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
> ---
>  include/sbi/sbi_hart.h | 2 ++
>  lib/sbi/sbi_hart.c     | 1 +
>  2 files changed, 3 insertions(+)
>
> diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
> index dfbe8e4c..567e0130 100644
> --- a/include/sbi/sbi_hart.h
> +++ b/include/sbi/sbi_hart.h
> @@ -81,6 +81,8 @@ enum sbi_hart_extensions {
>         SBI_HART_EXT_SSCTR,
>         /** HART has Ssstateen extension **/
>         SBI_HART_EXT_SSSTATEEN,
> +       /** Hart has Xsfcflushdlone extension */
> +       SBI_HART_EXT_XSF_CFLUSH_D_L1,

s/SBI_HART_EXT_XSF_CFLUSH_D_L1/SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1/

>
>         /** Maximum index of Hart extension */
>         SBI_HART_EXT_MAX,
> diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
> index 054a405c..e91e1123 100644
> --- a/lib/sbi/sbi_hart.c
> +++ b/lib/sbi/sbi_hart.c
> @@ -715,6 +715,7 @@ const struct sbi_hart_ext_data sbi_hart_ext[] = {
>         __SBI_HART_EXT_DATA(smctr, SBI_HART_EXT_SMCTR),
>         __SBI_HART_EXT_DATA(ssctr, SBI_HART_EXT_SSCTR),
>         __SBI_HART_EXT_DATA(ssstateen, SBI_HART_EXT_SSSTATEEN),
> +       __SBI_HART_EXT_DATA(xsfcflushdlone, SBI_HART_EXT_XSF_CFLUSH_D_L1),
>  };
>
>  _Static_assert(SBI_HART_EXT_MAX == array_size(sbi_hart_ext),
> --
> 2.17.1
>

Regards,
Anup


From anup at brainfault.org  Mon Aug  4 01:38:43 2025
From: anup at brainfault.org (Anup Patel)
Date: Mon, 4 Aug 2025 14:08:43 +0530
Subject: [PATCH v3 07/12] lib: sbi: Add SiFive proprietary xsfcease
In-Reply-To: <20250708074940.10904-8-nick.hu@sifive.com>
References: <20250708074940.10904-1-nick.hu@sifive.com> <20250708074940.10904-8-nick.hu@sifive.com>
Message-ID: <CAAhSdy24APsfMTbeaEpPU+rB-9YeYB99wPYBWZARdCSvaepiXQ@mail.gmail.com>

On Tue, Jul 8, 2025 at 1:20?PM Nick Hu <nick.hu at sifive.com> wrote:
>
> Using ISA string "xsfcease" to detect the support of the custom
> instruction "CEASE".
>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
> ---
>  include/sbi/sbi_hart.h | 2 ++
>  lib/sbi/sbi_hart.c     | 1 +
>  2 files changed, 3 insertions(+)
>
> diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
> index 567e0130..db6f4adb 100644
> --- a/include/sbi/sbi_hart.h
> +++ b/include/sbi/sbi_hart.h
> @@ -83,6 +83,8 @@ enum sbi_hart_extensions {
>         SBI_HART_EXT_SSSTATEEN,
>         /** Hart has Xsfcflushdlone extension */
>         SBI_HART_EXT_XSF_CFLUSH_D_L1,
> +       /** Hart has Xsfcease extension */
> +       SBI_HART_EXT_XSF_CEASE,

s/SBI_HART_EXT_XSF_CEASE/SBI_HART_EXT_XSIFIVE_CEASE/

>
>         /** Maximum index of Hart extension */
>         SBI_HART_EXT_MAX,
> diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
> index e91e1123..c9036084 100644
> --- a/lib/sbi/sbi_hart.c
> +++ b/lib/sbi/sbi_hart.c
> @@ -716,6 +716,7 @@ const struct sbi_hart_ext_data sbi_hart_ext[] = {
>         __SBI_HART_EXT_DATA(ssctr, SBI_HART_EXT_SSCTR),
>         __SBI_HART_EXT_DATA(ssstateen, SBI_HART_EXT_SSSTATEEN),
>         __SBI_HART_EXT_DATA(xsfcflushdlone, SBI_HART_EXT_XSF_CFLUSH_D_L1),
> +       __SBI_HART_EXT_DATA(xsfcease, SBI_HART_EXT_XSF_CEASE),
>  };
>
>  _Static_assert(SBI_HART_EXT_MAX == array_size(sbi_hart_ext),
> --
> 2.17.1
>

Regards,
Anup


From anup at brainfault.org  Mon Aug  4 01:38:56 2025
From: anup at brainfault.org (Anup Patel)
Date: Mon, 4 Aug 2025 14:08:56 +0530
Subject: [PATCH v3 10/12] platform: sifive: Add SiFive TMC0 driver
In-Reply-To: <20250708074940.10904-11-nick.hu@sifive.com>
References: <20250708074940.10904-1-nick.hu@sifive.com> <20250708074940.10904-11-nick.hu@sifive.com>
Message-ID: <CAAhSdy3ZHH8BW-FTqKrczRe1cvDQh-o-oFa71cN=iBg038Woig@mail.gmail.com>

On Tue, Jul 8, 2025 at 1:20?PM Nick Hu <nick.hu at sifive.com> wrote:
>
> The SiFive TMC0 controls the tile power domains on SiFive platform. The
> CPU enters the low power state via the `CEASE` instruction after
> configuring the TMC0. Any devices that inside the tile power domain will
> be power gated, including the private cache. Therefore flushing the
> private cache before entering the low power state.
>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
> ---
>  platform/generic/Kconfig                      |   2 +
>  platform/generic/include/sifive/sifive_inst.h |  20 +
>  platform/generic/include/sifive/sifive_tmc0.h |  12 +
>  platform/generic/sifive/Kconfig               |   5 +
>  platform/generic/sifive/objects.mk            |   2 +
>  .../pmdomain/fdt_pmdomain_sifive_tmc0.c       | 371 ++++++++++++++++++
>  platform/generic/sifive/sifive_dev_platform.c |  21 +

The TMC0 driver should be under the lib/utils/hsm/ directory.

Regards,
Anup


>  7 files changed, 433 insertions(+)
>  create mode 100644 platform/generic/include/sifive/sifive_inst.h
>  create mode 100644 platform/generic/include/sifive/sifive_tmc0.h
>  create mode 100644 platform/generic/sifive/Kconfig
>  create mode 100644 platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_tmc0.c
>
> diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
> index 20c25a83..1d6ea3f4 100644
> --- a/platform/generic/Kconfig
> +++ b/platform/generic/Kconfig
> @@ -46,6 +46,7 @@ config PLATFORM_RENESAS_RZFIVE
>  config PLATFORM_SIFIVE_DEV
>         bool "SiFive development platform support"
>         depends on FDT_CACHE
> +       select SIFIVE_TMC0
>         default n
>
>  config PLATFORM_SIFIVE_FU540
> @@ -78,6 +79,7 @@ config PLATFORM_MIPS_P8700
>         default n
>
>  source "$(OPENSBI_SRC_DIR)/platform/generic/andes/Kconfig"
> +source "$(OPENSBI_SRC_DIR)/platform/generic/sifive/Kconfig"
>  source "$(OPENSBI_SRC_DIR)/platform/generic/thead/Kconfig"
>
>  endif
> diff --git a/platform/generic/include/sifive/sifive_inst.h b/platform/generic/include/sifive/sifive_inst.h
> new file mode 100644
> index 00000000..36dddf68
> --- /dev/null
> +++ b/platform/generic/include/sifive/sifive_inst.h
> @@ -0,0 +1,20 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#ifndef __SIFIVE_INST_H__
> +#define __SIFIVE_INST_H__
> +
> +static inline void sifive_cease(void)
> +{
> +       __asm__ __volatile__(".word 0x30500073" ::: "memory");
> +}
> +
> +static inline void sifive_cflush(void)
> +{
> +       __asm__ __volatile__(".word 0xfc000073" ::: "memory");
> +}
> +
> +#endif
> diff --git a/platform/generic/include/sifive/sifive_tmc0.h b/platform/generic/include/sifive/sifive_tmc0.h
> new file mode 100644
> index 00000000..6100e0dc
> --- /dev/null
> +++ b/platform/generic/include/sifive/sifive_tmc0.h
> @@ -0,0 +1,12 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#ifndef __SIFIVE_TMC0_H__
> +#define __SIFIVE_TMC0_H__
> +
> +int sifive_tmc0_cold_init(void);
> +
> +#endif
> diff --git a/platform/generic/sifive/Kconfig b/platform/generic/sifive/Kconfig
> new file mode 100644
> index 00000000..2cbcea08
> --- /dev/null
> +++ b/platform/generic/sifive/Kconfig
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: BSD-2-Clause
> +
> +config SIFIVE_TMC0
> +       bool "SiFive TMC v0 driver support"
> +       default n
> diff --git a/platform/generic/sifive/objects.mk b/platform/generic/sifive/objects.mk
> index d32e1273..f8938713 100644
> --- a/platform/generic/sifive/objects.mk
> +++ b/platform/generic/sifive/objects.mk
> @@ -10,3 +10,5 @@ platform-objs-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive/fu540.o
>
>  carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_FU740) += sifive_fu740
>  platform-objs-$(CONFIG_PLATFORM_SIFIVE_FU740) += sifive/fu740.o
> +
> +platform-objs-$(CONFIG_SIFIVE_TMC0) += sifive/pmdomain/fdt_pmdomain_sifive_tmc0.o
> diff --git a/platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_tmc0.c b/platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_tmc0.c
> new file mode 100644
> index 00000000..70d02b33
> --- /dev/null
> +++ b/platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_tmc0.c
> @@ -0,0 +1,371 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive
> + */
> +
> +#include <libfdt.h>
> +#include <sbi/riscv_asm.h>
> +#include <sbi/riscv_io.h>
> +#include <sbi/sbi_bitops.h>
> +#include <sbi/sbi_console.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_hart.h>
> +#include <sbi/sbi_heap.h>
> +#include <sbi/sbi_hsm.h>
> +#include <sbi/sbi_ipi.h>
> +#include <sbi_utils/cache/fdt_cmo_helper.h>
> +#include <sbi_utils/fdt/fdt_driver.h>
> +#include <sbi_utils/fdt/fdt_helper.h>
> +#include <sbi_utils/ipi/aclint_mswi.h>
> +#include <sifive/sifive_inst.h>
> +#include <sifive/sifive_tmc0.h>
> +
> +struct sifive_tmc0 {
> +       unsigned long reg;
> +       struct sbi_dlist node;
> +       u32 id;
> +};
> +
> +static SBI_LIST_HEAD(tmc0_list);
> +static unsigned long tmc0_offset;
> +
> +#define tmc0_ptr_get(__scratch)                                \
> +       sbi_scratch_read_type((__scratch), struct sifive_tmc0 *, tmc0_offset)
> +
> +#define tmc0_ptr_set(__scratch, __tmc0)                        \
> +       sbi_scratch_write_type((__scratch), struct sifive_tmc0 *, tmc0_offset, (__tmc0))
> +
> +/* TMC.PGPREP */
> +#define SIFIVE_TMC_PGPREP_OFF                  0x0
> +#define SIFIVE_TMC_PGPREP_ENA_REQ              BIT(31)
> +#define SIFIVE_TMC_PGPREP_ENA_ACK              BIT(30)
> +#define SIFIVE_TMC_PGPREP_DIS_REQ              BIT(29)
> +#define SIFIVE_TMC_PGPREP_DIS_ACK              BIT(28)
> +#define SIFIVE_TMC_PGPREP_CLFPNOTQ             BIT(18)
> +#define SIFIVE_TMC_PGPREP_PMCENAERR            BIT(17)
> +#define SIFIVE_TMC_PGPREP_PMCDENY              BIT(16)
> +#define SIFIVE_TMC_PGPREP_BUSERR               BIT(15)
> +#define SIFIVE_TMC_PGPREP_WAKE_DETECT          BIT(12)
> +#define SIFIVE_TMC_PGPREP_INTERNAL_ABORT       BIT(2)
> +#define SIFIVE_TMC_PGPREP_ENARSP               (SIFIVE_TMC_PGPREP_CLFPNOTQ | \
> +                                                SIFIVE_TMC_PGPREP_PMCENAERR | \
> +                                                SIFIVE_TMC_PGPREP_PMCDENY | \
> +                                                SIFIVE_TMC_PGPREP_BUSERR | \
> +                                                SIFIVE_TMC_PGPREP_WAKE_DETECT)
> +
> +/* TMC.PG */
> +#define SIFIVE_TMC_PG_OFF                      0x4
> +#define SIFIVE_TMC_PG_ENA_REQ                  BIT(31)
> +#define SIFIVE_TMC_PG_ENA_ACK                  BIT(30)
> +#define SIFIVE_TMC_PG_DIS_REQ                  BIT(29)
> +#define SIFIVE_TMC_PG_DIS_ACK                  BIT(28)
> +#define SIFIVE_TMC_PG_PMC_ENA_ERR              BIT(17)
> +#define SIFIVE_TMC_PG_PMC_DENY                 BIT(16)
> +#define SIFIVE_TMC_PG_BUS_ERR                  BIT(15)
> +#define SIFIVE_TMC_PG_MASTNOTQ                 BIT(14)
> +#define SIFIVE_TMC_PG_WARM_RESET               BIT(1)
> +#define SIFIVE_TMC_PG_ENARSP                   (SIFIVE_TMC_PG_PMC_ENA_ERR | \
> +                                                SIFIVE_TMC_PG_PMC_DENY | \
> +                                                SIFIVE_TMC_PG_BUS_ERR | \
> +                                                SIFIVE_TMC_PG_MASTNOTQ)
> +
> +/* TMC.RESUMEPC */
> +#define SIFIVE_TMC_RESUMEPC_LO                 0x10
> +#define SIFIVE_TMC_RESUMEPC_HI                 0x14
> +
> +/* TMC.WAKEMASK */
> +#define SIFIVE_TMC_WAKE_MASK_OFF               0x20
> +#define SIFIVE_TMC_WAKE_MASK_WREQ              BIT(31)
> +#define SIFIVE_TMC_WAKE_MASK_ACK               BIT(30)
> +
> +static void sifive_tmc0_set_resumepc(physical_addr_t addr)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +
> +       writel((u32)addr, (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_LO));
> +       writel((u32)(addr >> 32), (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_HI));
> +}
> +
> +static u32 sifive_tmc0_set_pgprep_enareq(void)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> +       u32 v = readl((void *)reg);
> +
> +       writel(v | SIFIVE_TMC_PGPREP_ENA_REQ, (void *)reg);
> +       while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_ENA_ACK));
> +
> +       v = readl((void *)reg);
> +       return v & SIFIVE_TMC_PGPREP_INTERNAL_ABORT;
> +}
> +
> +static void sifive_tmc0_set_pgprep_disreq(void)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> +       u32 v = readl((void *)reg);
> +
> +       writel(v | SIFIVE_TMC_PGPREP_DIS_REQ, (void *)reg);
> +       while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_DIS_ACK));
> +}
> +
> +static u32 sifive_tmc0_get_pgprep_enarsp(void)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> +       u32 v = readl((void *)reg);
> +
> +       return v & SIFIVE_TMC_PGPREP_ENARSP;
> +}
> +
> +static void sifive_tmc0_set_pg_enareq(void)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PG_OFF;
> +       u32 v = readl((void *)reg);
> +
> +       writel(v | SIFIVE_TMC_PG_ENA_REQ, (void *)reg);
> +}
> +
> +static int sifive_tmc0_prep(void)
> +{
> +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> +       u32 rc;
> +
> +       if (!tmc0_ptr_get(scratch))
> +               return SBI_ENODEV;
> +
> +       rc = sifive_tmc0_set_pgprep_enareq();
> +       if (rc) {
> +               sbi_printf("TMC0 error: Internal Abort (Wake detect)\n");
> +               goto fail;
> +       }
> +
> +       rc = sifive_tmc0_get_pgprep_enarsp();
> +       if (rc) {
> +               sifive_tmc0_set_pgprep_disreq();
> +               sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
> +               goto fail;
> +       }
> +
> +       sifive_tmc0_set_resumepc(scratch->warmboot_addr);
> +
> +       return SBI_OK;
> +
> +fail:
> +       return SBI_EFAIL;
> +}
> +
> +static int sifive_tmc0_enter(void)
> +{
> +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> +       u32 rc;
> +
> +       /* Flush cache and check if there is wake detect or bus error */
> +       if (fdt_cmo_private_flc_flush_all() &&
> +           sbi_hart_has_extension(scratch, SBI_HART_EXT_XSF_CFLUSH_D_L1))
> +               sifive_cflush();
> +
> +       rc = sifive_tmc0_get_pgprep_enarsp();
> +       if (rc) {
> +               sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
> +               goto fail;
> +       }
> +
> +       if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XSF_CEASE)) {
> +               sifive_tmc0_set_pg_enareq();
> +               while (1)
> +                       sifive_cease();
> +       }
> +
> +       rc = SBI_ENOTSUPP;
> +fail:
> +       sifive_tmc0_set_pgprep_disreq();
> +       return rc;
> +}
> +
> +static int sifive_tmc0_tile_pg(void)
> +{
> +       int rc;
> +
> +       rc = sifive_tmc0_prep();
> +       if (rc)
> +               return rc;
> +
> +       return sifive_tmc0_enter();
> +}
> +
> +static struct sifive_tmc0 *sifive_tmc0_find(u32 id)
> +{
> +       struct sifive_tmc0 *tmc0;
> +
> +       sbi_list_for_each_entry(tmc0, &tmc0_list, node) {
> +               if (tmc0->id == id)
> +                       return tmc0;
> +       }
> +
> +       return NULL;
> +}
> +
> +static int sifive_tmc0_add(struct sifive_tmc0 *tmc0)
> +{
> +       if (!tmc0)
> +               return SBI_ENODEV;
> +
> +       if (sifive_tmc0_find(tmc0->id))
> +               return SBI_EALREADY;
> +
> +       sbi_list_add(&tmc0->node, &tmc0_list);
> +
> +       return SBI_OK;
> +}
> +
> +static int sifive_tmc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
> +{
> +       struct sifive_tmc0 *tmc0;
> +       int rc;
> +       u64 addr;
> +
> +       tmc0 = sbi_zalloc(sizeof(*tmc0));
> +       if (!tmc0)
> +               return SBI_ENOMEM;
> +
> +       rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
> +       if (rc)
> +               goto free_tmc0;
> +
> +       tmc0->reg = (unsigned long)addr;
> +       tmc0->id = nodeoff;
> +
> +       rc = sifive_tmc0_add(tmc0);
> +       if (rc)
> +               goto free_tmc0;
> +
> +       return SBI_OK;
> +
> +free_tmc0:
> +       sbi_free(tmc0);
> +       return rc;
> +}
> +
> +static const struct fdt_match sifive_tmc0_match[] = {
> +       { .compatible = "sifive,tmc0" },
> +       { },
> +};
> +
> +const struct fdt_driver fdt_sifive_tmc0 = {
> +       .match_table = sifive_tmc0_match,
> +       .init = sifive_tmc0_probe,
> +};
> +
> +static const struct fdt_driver *const sifive_tmc0_drivers[] = {
> +       &fdt_sifive_tmc0,
> +       NULL
> +};
> +
> +static int fdt_sifive_tmc0_get(const void *fdt, int noff, struct sifive_tmc0 **out)
> +{
> +       struct sifive_tmc0 *tmc0;
> +       int rc;
> +
> +       noff = fdt_node_offset_by_phandle(fdt, noff);
> +       if (noff < 0)
> +               return noff;
> +
> +       rc = fdt_driver_init_by_offset(fdt, noff, sifive_tmc0_drivers);
> +       if (rc)
> +               return rc;
> +
> +       tmc0 = sifive_tmc0_find(noff);
> +       if (!tmc0)
> +               return SBI_EFAIL;
> +
> +       if (out)
> +               *out = tmc0;
> +
> +       return SBI_OK;
> +}
> +
> +static int fdt_sifive_tmc0_cold_init(const void *fdt)
> +{
> +       struct sbi_scratch *scratch;
> +       struct sifive_tmc0 *tmc0;
> +       const fdt32_t *val;
> +       int cpus_off, cpu_off, rc;
> +       u32 hartid;
> +
> +       cpus_off = fdt_path_offset(fdt, "/cpus");
> +       if (cpus_off < 0)
> +               return SBI_ENOENT;
> +
> +       fdt_for_each_subnode(cpu_off, fdt, cpus_off) {
> +               rc = fdt_parse_hart_id(fdt, cpu_off, &hartid);
> +               if (rc)
> +                       continue;
> +
> +               val = fdt_getprop(fdt, cpu_off, "power-domains", NULL);
> +               if (!val)
> +                       return SBI_ENOENT;
> +
> +               rc = fdt_sifive_tmc0_get(fdt, fdt32_to_cpu(val[0]), &tmc0);
> +               if (rc)
> +                       return rc;
> +
> +               scratch = sbi_hartid_to_scratch(hartid);
> +               if (!scratch)
> +                       continue;
> +
> +               tmc0_ptr_set(scratch, tmc0);
> +       }
> +
> +       return SBI_OK;
> +}
> +
> +static int sifive_tmc0_start(u32 hartid, ulong saddr)
> +{
> +       struct sbi_ipi_device *clint = aclint_mswi_get();
> +
> +       /*
> +        * In system suspend, the IMSIC will be reset in SiFive platform so
> +        * we use the CLINT IPI as the wake event.
> +        */
> +       if (clint && clint->ipi_send)
> +               clint->ipi_send(sbi_hartid_to_hartindex(hartid));
> +       else
> +               sbi_ipi_raw_send(sbi_hartid_to_hartindex(hartid));
> +
> +       return SBI_OK;
> +}
> +
> +static int sifive_tmc0_stop(void)
> +{
> +       unsigned long mie = csr_read(CSR_MIE);
> +       int rc;
> +       // Set IPI as wake up source
> +       csr_set(CSR_MIE, MIP_MEIP | MIP_MSIP);
> +
> +       rc = sifive_tmc0_tile_pg();
> +       if (rc) {
> +               csr_write(CSR_MIE, mie);
> +               return rc;
> +       }
> +
> +       return SBI_OK;
> +}
> +
> +static struct sbi_hsm_device tmc0_hsm_dev = {
> +       .name = "SiFive TMC0",
> +       .hart_start = sifive_tmc0_start,
> +       .hart_stop = sifive_tmc0_stop,
> +};
> +
> +int sifive_tmc0_cold_init(void)
> +{
> +       tmc0_offset = sbi_scratch_alloc_type_offset(struct sifive_tmc0 *);
> +       if (!tmc0_offset)
> +               return SBI_ENOMEM;
> +
> +       sbi_hsm_set_device(&tmc0_hsm_dev);
> +       return fdt_sifive_tmc0_cold_init(fdt_get_address());
> +}
> diff --git a/platform/generic/sifive/sifive_dev_platform.c b/platform/generic/sifive/sifive_dev_platform.c
> index ac659868..3e433bb3 100644
> --- a/platform/generic/sifive/sifive_dev_platform.c
> +++ b/platform/generic/sifive/sifive_dev_platform.c
> @@ -5,7 +5,11 @@
>   */
>
>  #include <platform_override.h>
> +#include <sbi/sbi_ipi.h>
>  #include <sbi_utils/cache/fdt_cmo_helper.h>
> +#include <sbi_utils/ipi/aclint_mswi.h>
> +
> +#include <sifive/sifive_tmc0.h>
>
>  static int sifive_early_init(bool cold_boot)
>  {
> @@ -19,13 +23,30 @@ static int sifive_early_init(bool cold_boot)
>         if (rc)
>                 return rc;
>
> +       if (cold_boot) {
> +               rc = sifive_tmc0_cold_init();
> +               if (rc)
> +                       return rc;
> +       }
> +
>         return 0;
>  }
>
> +static int sifive_final_init(bool cold_boot)
> +{
> +       struct sbi_ipi_device *clint = aclint_mswi_get();
> +
> +       if (clint && clint->ipi_clear)
> +               clint->ipi_clear();
> +
> +       return generic_final_init(cold_boot);
> +}
> +
>  static int sifive_platform_init(const void *fdt, int nodeoff,
>                                 const struct fdt_match *match)
>  {
>         generic_platform_ops.early_init = sifive_early_init;
> +       generic_platform_ops.final_init = sifive_final_init;
>
>         return 0;
>  }
> --
> 2.17.1
>


From anup at brainfault.org  Mon Aug  4 01:39:08 2025
From: anup at brainfault.org (Anup Patel)
Date: Mon, 4 Aug 2025 14:09:08 +0530
Subject: [PATCH v3 12/12] platform: sifive: Add SiFive SMC0 driver
In-Reply-To: <20250708074940.10904-13-nick.hu@sifive.com>
References: <20250708074940.10904-1-nick.hu@sifive.com> <20250708074940.10904-13-nick.hu@sifive.com>
Message-ID: <CAAhSdy2tdVrDqRUrBh1szSsYCymQS6efT+tp7k+aaXsU7943tw@mail.gmail.com>

On Tue, Jul 8, 2025 at 1:20?PM Nick Hu <nick.hu at sifive.com> wrote:
>
> The SiFive SMC0 controls the clock and power domain of the core complex
> on the SiFive platform. The core complex enters the low power state
> after the secondary cores enter the tile power gating and last core
> execute the `CEASE` instruction with the corresponding SMC0
> configurations. The devices that inside both tile power domain and core
> complex power domain will be off, including caches and timer. Therefore
> we need to flush the last level cache before entering the core complex
> power gating and update the timer after waking up.
>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
> ---
>  platform/generic/Kconfig                      |   1 +
>  platform/generic/include/sifive/sifive_smc0.h |  13 +
>  platform/generic/include/sifive/sifive_tmc0.h |   3 +
>  platform/generic/sifive/Kconfig               |   5 +
>  platform/generic/sifive/objects.mk            |   2 +
>  .../pmdomain/fdt_pmdomain_sifive_smc0.c       | 322 ++++++++++++++++++
>  .../pmdomain/fdt_pmdomain_sifive_tmc0.c       |  88 +++++
>  7 files changed, 434 insertions(+)
>  create mode 100644 platform/generic/include/sifive/sifive_smc0.h
>  create mode 100644 platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_smc0.c

The SMC0 driver should be under the lib/utils/suspend/ directory.

Regards,
Anup


>
> diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
> index 1d6ea3f4..048822ef 100644
> --- a/platform/generic/Kconfig
> +++ b/platform/generic/Kconfig
> @@ -46,6 +46,7 @@ config PLATFORM_RENESAS_RZFIVE
>  config PLATFORM_SIFIVE_DEV
>         bool "SiFive development platform support"
>         depends on FDT_CACHE
> +       select SIFIVE_SMC0
>         select SIFIVE_TMC0
>         default n
>
> diff --git a/platform/generic/include/sifive/sifive_smc0.h b/platform/generic/include/sifive/sifive_smc0.h
> new file mode 100644
> index 00000000..d13bdf4d
> --- /dev/null
> +++ b/platform/generic/include/sifive/sifive_smc0.h
> @@ -0,0 +1,13 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#ifndef __SIFIVE_SMC0_H__
> +#define __SIFIVE_SMC0_H__
> +
> +bool sifive_smc0_check_warm_reset(void);
> +void sifive_smc0_mtime_update(void);
> +
> +#endif
> diff --git a/platform/generic/include/sifive/sifive_tmc0.h b/platform/generic/include/sifive/sifive_tmc0.h
> index 6100e0dc..ad0d2407 100644
> --- a/platform/generic/include/sifive/sifive_tmc0.h
> +++ b/platform/generic/include/sifive/sifive_tmc0.h
> @@ -7,6 +7,9 @@
>  #ifndef __SIFIVE_TMC0_H__
>  #define __SIFIVE_TMC0_H__
>
> +int sifive_tmc0_set_wakemask_enareq(u32 hartid);
> +void sifive_tmc0_set_wakemask_disreq(u32 hartid);
> +bool sifive_tmc0_is_pg(u32 hartid);
>  int sifive_tmc0_cold_init(void);
>
>  #endif
> diff --git a/platform/generic/sifive/Kconfig b/platform/generic/sifive/Kconfig
> index 2cbcea08..efb00c02 100644
> --- a/platform/generic/sifive/Kconfig
> +++ b/platform/generic/sifive/Kconfig
> @@ -1,5 +1,10 @@
>  # SPDX-License-Identifier: BSD-2-Clause
>
> +
> +config SIFIVE_SMC0
> +       bool "SiFive SMC v0 driver support"
> +       default n
> +
>  config SIFIVE_TMC0
>         bool "SiFive TMC v0 driver support"
>         default n
> diff --git a/platform/generic/sifive/objects.mk b/platform/generic/sifive/objects.mk
> index f8938713..28001453 100644
> --- a/platform/generic/sifive/objects.mk
> +++ b/platform/generic/sifive/objects.mk
> @@ -11,4 +11,6 @@ platform-objs-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive/fu540.o
>  carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_FU740) += sifive_fu740
>  platform-objs-$(CONFIG_PLATFORM_SIFIVE_FU740) += sifive/fu740.o
>
> +carray-fdt_early_drivers-$(CONFIG_SIFIVE_SMC0) += fdt_sifive_smc0
> +platform-objs-$(CONFIG_SIFIVE_SMC0) += sifive/pmdomain/fdt_pmdomain_sifive_smc0.o
>  platform-objs-$(CONFIG_SIFIVE_TMC0) += sifive/pmdomain/fdt_pmdomain_sifive_tmc0.o
> diff --git a/platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_smc0.c b/platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_smc0.c
> new file mode 100644
> index 00000000..6c6d5d1f
> --- /dev/null
> +++ b/platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_smc0.c
> @@ -0,0 +1,322 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive
> + */
> +
> +#include <libfdt.h>
> +#include <sbi/riscv_asm.h>
> +#include <sbi/riscv_io.h>
> +#include <sbi/sbi_console.h>
> +#include <sbi/sbi_domain.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_hart.h>
> +#include <sbi/sbi_hsm.h>
> +#include <sbi/sbi_system.h>
> +#include <sbi/sbi_timer.h>
> +#include <sbi_utils/cache/fdt_cmo_helper.h>
> +#include <sbi_utils/fdt/fdt_driver.h>
> +#include <sbi_utils/fdt/fdt_helper.h>
> +#include <sbi_utils/timer/aclint_mtimer.h>
> +#include <sifive/sifive_inst.h>
> +#include <sifive/sifive_smc0.h>
> +#include <sifive/sifive_tmc0.h>
> +
> +#define SIFIVE_SMC_PGPREP_OFF                  0x0
> +#define SIFIVE_SMC_PG_OFF                      0x4
> +#define SIFIVE_SMC_CCTIMER_OFF                 0xc
> +#define SIFIVE_SMC_RESUMEPC_LO_OFF             0x10
> +#define SIFIVE_SMC_RESUMEPC_HI_OFF             0x14
> +#define SIFIVE_SMC_SYNC_PMC_OFF                        0x24
> +#define SIFIVE_SMC_CYCLECOUNT_LO_OFF           0x28
> +#define SIFIVE_SMC_CYCLECOUNT_HI_OFF           0x2c
> +#define SIFIVE_SMC_WFI_UNCORE_CG_OFF           0x50
> +
> +#define SIFIVE_SMC_PGPREP_ENA_REQ              BIT(31)
> +#define SIFIVE_SMC_PGPREP_ENA_ACK              BIT(30)
> +#define SIFIVE_SMC_PGPREP_DIS_REQ              BIT(29)
> +#define SIFIVE_SMC_PGPREP_DIS_ACK              BIT(29)
> +#define SIFIVE_SMC_PGPREP_FRONTNOTQ            BIT(19)
> +#define SIFIVE_SMC_PGPREP_CLFPNOTQ             BIT(18)
> +#define SIFIVE_SMC_PGPREP_PMCENAERR            BIT(17)
> +#define SIFIVE_SMC_PGPREP_WAKE_DETECT          BIT(16)
> +#define SIFIVE_SMC_PGPREP_BUSERR               BIT(15)
> +#define SIFIVE_SMC_PGPREP_EARLY_ABORT          BIT(3)
> +#define SIFIVE_SMC_PGPREP_INTERNAL_ABORT       BIT(2)
> +#define SIFIVE_SMC_PGPREP_ENARSP               (SIFIVE_SMC_PGPREP_FRONTNOTQ | \
> +                                                SIFIVE_SMC_PGPREP_CLFPNOTQ | \
> +                                                SIFIVE_SMC_PGPREP_PMCENAERR | \
> +                                                SIFIVE_SMC_PGPREP_WAKE_DETECT | \
> +                                                SIFIVE_SMC_PGPREP_BUSERR)
> +
> +#define SIFIVE_SMC_PGPREP_ABORT                        (SIFIVE_SMC_PGPREP_EARLY_ABORT | \
> +                                                SIFIVE_SMC_PGPREP_INTERNAL_ABORT)
> +
> +#define SIFIVE_SMC_PG_ENA_REQ                  BIT(31)
> +#define SIFIVE_SMC_PG_WARM_RESET               BIT(1)
> +
> +#define SIFIVE_SMC_SYNCPMC_SYNC_REQ            BIT(31)
> +#define SIFIVE_SMC_SYNCPMC_SYNC_WREQ           BIT(30)
> +#define SIFIVE_SMC_SYNCPMC_SYNC_ACK            BIT(29)
> +
> +static struct aclint_mtimer_data smc_sync_timer;
> +static unsigned long smc0_base;
> +
> +static void sifive_smc0_set_pmcsync(char regid, bool write_mode)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_SYNC_PMC_OFF;
> +       u32 v = regid | SIFIVE_SMC_SYNCPMC_SYNC_REQ;
> +
> +       if (write_mode)
> +               v |= SIFIVE_SMC_SYNCPMC_SYNC_WREQ;
> +
> +       writel(v, (void *)addr);
> +       while (!(readl((void *)addr) & SIFIVE_SMC_SYNCPMC_SYNC_ACK));
> +}
> +
> +static u64 sifive_smc0_time_read(volatile u64 *addr)
> +{
> +       u32 lo, hi;
> +
> +       do {
> +               sifive_smc0_set_pmcsync(SIFIVE_SMC_CYCLECOUNT_LO_OFF, false);
> +               sifive_smc0_set_pmcsync(SIFIVE_SMC_CYCLECOUNT_HI_OFF, false);
> +               hi = readl_relaxed((u32 *)addr + 1);
> +               lo = readl_relaxed((u32 *)addr);
> +       } while (hi != readl_relaxed((u32 *)addr + 1));
> +
> +       return ((u64)hi << 32) | (u64)lo;
> +}
> +
> +static void sifive_smc0_set_resumepc(physical_addr_t raddr)
> +{
> +       /* Set resumepc_lo */
> +       writel((u32)raddr, (void *)(smc0_base + SIFIVE_SMC_RESUMEPC_LO_OFF));
> +       /* copy resumepc_lo from SMC to PMC */
> +       sifive_smc0_set_pmcsync(SIFIVE_SMC_RESUMEPC_LO_OFF, true);
> +
> +       /* Set resumepc_hi */
> +       writel((u32)(raddr >> 32), (void *)(smc0_base + SIFIVE_SMC_RESUMEPC_HI_OFF));
> +       /* copy resumepc_hi from SMC to PMC */
> +       sifive_smc0_set_pmcsync(SIFIVE_SMC_RESUMEPC_HI_OFF, true);
> +}
> +
> +static u32 sifive_smc0_get_pgprep_enarsp(void)
> +{
> +       u32 v = readl((void *)(smc0_base + SIFIVE_SMC_PGPREP_OFF));
> +
> +       return v & SIFIVE_SMC_PGPREP_ENARSP;
> +}
> +
> +static void sifive_smc0_set_pgprep_disreq(void)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_PGPREP_OFF;
> +       u32 v = readl((void *)addr);
> +
> +       writel(v | SIFIVE_SMC_PGPREP_DIS_REQ, (void *)addr);
> +       while (!(readl((void *)addr) & SIFIVE_SMC_PGPREP_DIS_ACK));
> +}
> +
> +static u32 sifive_smc0_set_pgprep_enareq(void)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_PGPREP_OFF;
> +       u32 v = readl((void *)addr);
> +
> +       writel(v | SIFIVE_SMC_PGPREP_ENA_REQ, (void *)addr);
> +       while (!(readl((void *)addr) & SIFIVE_SMC_PGPREP_ENA_ACK));
> +
> +       v = readl((void *)addr);
> +
> +       return v & SIFIVE_SMC_PGPREP_ABORT;
> +}
> +
> +static void sifive_smc0_set_pg_enareq(void)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_PG_OFF;
> +       u32 v = readl((void *)addr);
> +
> +       writel(v | SIFIVE_SMC_PG_ENA_REQ, (void *)addr);
> +}
> +
> +bool sifive_smc0_check_warm_reset(void)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_PG_OFF;
> +
> +       if (!smc0_base)
> +               return false;
> +
> +       sifive_smc0_set_pmcsync(SIFIVE_SMC_PG_OFF, false);
> +
> +       return readl((void *)addr) & SIFIVE_SMC_PG_WARM_RESET ? true : false;
> +}
> +
> +static inline void sifive_smc0_set_cg(bool enable)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_WFI_UNCORE_CG_OFF;
> +
> +       if (enable)
> +               writel(0, (void *)addr);
> +       else
> +               writel(1, (void *)addr);
> +}
> +
> +static int sifive_smc0_prep(void)
> +{
> +       const struct sbi_domain *dom = &root;
> +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> +       unsigned long i;
> +       int rc;
> +       u32 target;
> +
> +       if (!smc0_base)
> +               return SBI_ENODEV;
> +
> +       /* Prevent all secondary tiles from waking up from PG state */
> +       sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
> +               target = sbi_hartindex_to_hartid(i);
> +               if (target != current_hartid()) {
> +                       rc = sifive_tmc0_set_wakemask_enareq(target);
> +                       if (rc) {
> +                               sbi_printf("Fail to enable wakemask for hart %d\n",
> +                                          target);
> +                               goto fail;
> +                       }
> +               }
> +       }
> +
> +       /* Check if all secondary tiles enter PG state */
> +       sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
> +               target = sbi_hartindex_to_hartid(i);
> +               if (target != current_hartid() &&
> +                   !sifive_tmc0_is_pg(target)) {
> +                       sbi_printf("Hart %d not in the PG state\n", target);
> +                       goto fail;
> +               }
> +       }
> +
> +       rc = sifive_smc0_set_pgprep_enareq();
> +       if (rc) {
> +               sbi_printf("SMC0 error: abort code: 0x%x\n", rc);
> +               goto fail;
> +       }
> +
> +       rc = sifive_smc0_get_pgprep_enarsp();
> +       if (rc) {
> +               sifive_smc0_set_pgprep_disreq();
> +               sbi_printf("SMC0 error: error response code: 0x%x\n", rc);
> +               goto fail;
> +       }
> +
> +       sifive_smc0_set_resumepc(scratch->warmboot_addr);
> +       return SBI_OK;
> +fail:
> +       sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
> +               target = sbi_hartindex_to_hartid(i);
> +               if (target != current_hartid())
> +                       sifive_tmc0_set_wakemask_disreq(target);
> +       }
> +
> +       return SBI_EFAIL;
> +}
> +
> +static int sifive_smc0_enter(void)
> +{
> +       const struct sbi_domain *dom = &root;
> +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> +       unsigned long i;
> +       u32 target, rc;
> +
> +       /* Flush cache and check if there is wake detect or bus error */
> +       if (fdt_cmo_llc_flush_all() &&
> +           sbi_hart_has_extension(scratch, SBI_HART_EXT_XSF_CFLUSH_D_L1))
> +               sifive_cflush();
> +
> +       rc = sifive_smc0_get_pgprep_enarsp();
> +       if (rc) {
> +               sbi_printf("SMC0 error: error response code: 0x%x\n", rc);
> +               rc = SBI_EFAIL;
> +               goto fail;
> +       }
> +
> +       if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XSF_CEASE)) {
> +               sifive_smc0_set_pg_enareq();
> +               while (1)
> +                       sifive_cease();
> +       }
> +
> +       rc = SBI_ENOTSUPP;
> +fail:
> +       sifive_smc0_set_pgprep_disreq();
> +       sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
> +               target = sbi_hartindex_to_hartid(i);
> +               if (target != current_hartid())
> +                       sifive_tmc0_set_wakemask_disreq(target);
> +       }
> +       return rc;
> +}
> +
> +static int sifive_smc0_pg(void)
> +{
> +       int rc;
> +
> +       rc = sifive_smc0_prep();
> +       if (rc)
> +               return rc;
> +
> +       return sifive_smc0_enter();
> +}
> +
> +static int sifive_smc0_system_suspend(u32 sleep_type, unsigned long addr)
> +{
> +       /* Disable the timer interrupt */
> +       sbi_timer_exit(sbi_scratch_thishart_ptr());
> +
> +       return sifive_smc0_pg();
> +}
> +
> +static int sifive_smc0_system_suspend_check(u32 sleep_type)
> +{
> +       return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? SBI_OK : SBI_EINVAL;
> +}
> +
> +static struct sbi_system_suspend_device smc0_sys_susp = {
> +       .name = "Sifive SMC0",
> +       .system_suspend_check = sifive_smc0_system_suspend_check,
> +       .system_suspend = sifive_smc0_system_suspend,
> +};
> +
> +void sifive_smc0_mtime_update(void)
> +{
> +       struct aclint_mtimer_data *mt = aclint_get_mtimer_data();
> +
> +       aclint_mtimer_update(mt, &smc_sync_timer);
> +}
> +
> +static int sifive_smc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
> +{
> +       int rc;
> +       u64 addr;
> +
> +       rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
> +       if (rc)
> +               return rc;
> +
> +       smc0_base = (unsigned long)addr;
> +       smc_sync_timer.time_rd = sifive_smc0_time_read;
> +       smc_sync_timer.mtime_addr = smc0_base + SIFIVE_SMC_CYCLECOUNT_LO_OFF;
> +
> +       sbi_system_suspend_set_device(&smc0_sys_susp);
> +       sifive_smc0_set_cg(true);
> +
> +       return SBI_OK;
> +}
> +
> +static const struct fdt_match sifive_smc0_match[] = {
> +       { .compatible = "sifive,smc0" },
> +       { },
> +};
> +
> +const struct fdt_driver fdt_sifive_smc0 = {
> +       .match_table = sifive_smc0_match,
> +       .init = sifive_smc0_probe,
> +};
> diff --git a/platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_tmc0.c b/platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_tmc0.c
> index 70d02b33..359c0be7 100644
> --- a/platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_tmc0.c
> +++ b/platform/generic/sifive/pmdomain/fdt_pmdomain_sifive_tmc0.c
> @@ -18,7 +18,9 @@
>  #include <sbi_utils/fdt/fdt_driver.h>
>  #include <sbi_utils/fdt/fdt_helper.h>
>  #include <sbi_utils/ipi/aclint_mswi.h>
> +#include <sbi_utils/irqchip/aplic.h>
>  #include <sifive/sifive_inst.h>
> +#include <sifive/sifive_smc0.h>
>  #include <sifive/sifive_tmc0.h>
>
>  struct sifive_tmc0 {
> @@ -79,6 +81,73 @@ static unsigned long tmc0_offset;
>  #define SIFIVE_TMC_WAKE_MASK_WREQ              BIT(31)
>  #define SIFIVE_TMC_WAKE_MASK_ACK               BIT(30)
>
> +int sifive_tmc0_set_wakemask_enareq(u32 hartid)
> +{
> +       struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
> +       unsigned long addr;
> +       u32 v;
> +
> +       if (!tmc0)
> +               return SBI_ENODEV;
> +
> +       addr = tmc0->reg + SIFIVE_TMC_WAKE_MASK_OFF;
> +       v = readl((void *)addr);
> +       writel(v | SIFIVE_TMC_WAKE_MASK_WREQ, (void *)addr);
> +
> +       while (!(readl((void *)addr) & SIFIVE_TMC_WAKE_MASK_ACK));
> +
> +       return SBI_OK;
> +}
> +
> +void sifive_tmc0_set_wakemask_disreq(u32 hartid)
> +{
> +       struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
> +       unsigned long addr;
> +       u32 v;
> +
> +       if (!tmc0)
> +               return;
> +
> +       addr = tmc0->reg + SIFIVE_TMC_WAKE_MASK_OFF;
> +       v = readl((void *)addr);
> +       writel(v & ~SIFIVE_TMC_WAKE_MASK_WREQ, (void *)addr);
> +
> +       while (readl((void *)addr) & SIFIVE_TMC_WAKE_MASK_ACK);
> +}
> +
> +bool sifive_tmc0_is_pg(u32 hartid)
> +{
> +       struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
> +       unsigned long addr;
> +       u32 v;
> +
> +       if (!tmc0)
> +               return false;
> +
> +       addr = tmc0->reg + SIFIVE_TMC_PG_OFF;
> +       v = readl((void *)addr);
> +       if (!(v & SIFIVE_TMC_PG_ENA_ACK) ||
> +           (v & SIFIVE_TMC_PG_ENARSP) ||
> +           (v & SIFIVE_TMC_PG_DIS_REQ))
> +               return false;
> +
> +       return true;
> +}
> +
> +static bool sifive_tmc0_check_warm_reset(void)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +       unsigned long addr = tmc0->reg + SIFIVE_TMC_PG_OFF;
> +
> +       if (!tmc0)
> +               return false;
> +
> +       return readl((void *)addr) & SIFIVE_TMC_PG_WARM_RESET ? true : false;
> +}
> +
>  static void sifive_tmc0_set_resumepc(physical_addr_t addr)
>  {
>         struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> @@ -354,10 +423,29 @@ static int sifive_tmc0_stop(void)
>         return SBI_OK;
>  }
>
> +static void sifive_pg_resume(void)
> +{
> +       /*
> +        * To simplify the implementation, the SW won't clear the warm
> +        * reset bit. If the system woken up from the Core Complex power
> +        * gating, the warm reset bit of the TMC0 will be clear. Therefore
> +        * we need to check the warm reset bit of the TMC0 first as the
> +        * Tile power gating won't clear the warm reset bit of the SMC0.
> +        */
> +       if (sifive_tmc0_check_warm_reset())
> +               return;
> +
> +       if (sifive_smc0_check_warm_reset()) {
> +               aplic_restore();
> +               sifive_smc0_mtime_update();
> +       }
> +}
> +
>  static struct sbi_hsm_device tmc0_hsm_dev = {
>         .name = "SiFive TMC0",
>         .hart_start = sifive_tmc0_start,
>         .hart_stop = sifive_tmc0_stop,
> +       .hart_resume = sifive_pg_resume,
>  };
>
>  int sifive_tmc0_cold_init(void)
> --
> 2.17.1
>


From wu.fei9 at sanechips.com.cn  Tue Aug  5 17:41:23 2025
From: wu.fei9 at sanechips.com.cn (wu.fei9 at sanechips.com.cn)
Date: Wed, 6 Aug 2025 08:41:23 +0800 (CST)
Subject: =?UTF-8?B?W1BBVENIIDAvM10gU3VwcG9ydCAxMDI0IGhhcnRz?=
Message-ID: <202508060049.5760ns6g081356@mse-fl2.zte.com.cn>

It is expected to have riscv server boards with many harts very soon,
lift the maximum hart number from 128 to 1024. Also, more heap memory is
added for housekeeping metadata or memory allocation cannot be satisfied
at the end.

Wu Fei (3):
  lib: sbi: Print error message during warm boot
  platform: generic: Extra memory for housekeeping
  include: sbi: Lift the maximum harts to 1024

 include/sbi/sbi_hartmask.h  |  2 +-
 include/sbi/sbi_heap.h      |  3 ++
 lib/sbi/sbi_heap.c          |  5 +++
 lib/sbi/sbi_init.c          | 65 +++++++++++++++++++++++++++++--------
 platform/generic/platform.c |  1 +
 5 files changed, 62 insertions(+), 14 deletions(-)

--
2.43.0


From wu.fei9 at sanechips.com.cn  Tue Aug  5 18:00:58 2025
From: wu.fei9 at sanechips.com.cn (wu.fei9 at sanechips.com.cn)
Date: Wed, 6 Aug 2025 09:00:58 +0800 (CST)
Subject: =?UTF-8?B?W1BBVENIIDEvM10gbGliOiBzYmk6IFByaW50IGVycm9yIG1lc3NhZ2UgZHVyaW5nIHdhcm0gYm9vdA==?=
In-Reply-To: <20250806084123476SCLxg-qQRa8CRuhuY-dwE@zte.com.cn>
References: 20250806084123476SCLxg-qQRa8CRuhuY-dwE@zte.com.cn
Message-ID: <202508060106.57616SIn072462@mse-db.zte.com.cn>

It's helpful to print error messages for debugging, here add them in
warm boot path just as those in the cold boot path.

Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>
---
 lib/sbi/sbi_init.c | 65 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 52 insertions(+), 13 deletions(-)

diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
index 84a6374..2e1ca66 100644
--- a/lib/sbi/sbi_init.c
+++ b/lib/sbi/sbi_init.c
@@ -415,60 +415,99 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,

        /* Note: This has to be first thing in warmboot init sequence */
        rc = sbi_hsm_init(scratch, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d hsm init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        rc = sbi_platform_early_init(plat, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d platform early init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        rc = sbi_hart_init(scratch, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d hart init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        rc = sbi_pmu_init(scratch, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d pmu init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        rc = sbi_dbtr_init(scratch, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d dbtr init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        rc = sbi_irqchip_init(scratch, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d irqchip init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        rc = sbi_ipi_init(scratch, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d ipi init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        rc = sbi_tlb_init(scratch, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d tlb init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        rc = sbi_timer_init(scratch, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d timer init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        rc = sbi_fwft_init(scratch, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d fwft init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        rc = sbi_platform_final_init(plat, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d platform final init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        rc = sbi_sse_init(scratch, false);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d sse init failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        /*
         * Configure PMP at last because if SMEPMP is detected,
         * M-mode access to the S/U space will be rescinded.
         */
        rc = sbi_hart_pmp_configure(scratch);
-       if (rc)
+       if (rc) {
+               sbi_printf("%s: hart %d PMP configure failed (error %d)\n",
+                          __func__, hartid, rc);
                sbi_hart_hang();
+       }

        count = sbi_scratch_offset_ptr(scratch, init_count_offset);
        (*count)++;
--
2.43.0


From wu.fei9 at sanechips.com.cn  Tue Aug  5 18:02:57 2025
From: wu.fei9 at sanechips.com.cn (wu.fei9 at sanechips.com.cn)
Date: Wed, 6 Aug 2025 09:02:57 +0800 (CST)
Subject: =?UTF-8?B?W1BBVENIIDIvM10gcGxhdGZvcm06IGdlbmVyaWM6IEV4dHJhIG1lbW9yeSBmb3IgaG91c2VrZWVwaW5n?=
In-Reply-To: <20250806084123476SCLxg-qQRa8CRuhuY-dwE@zte.com.cn>
References: 20250806084123476SCLxg-qQRa8CRuhuY-dwE@zte.com.cn
Message-ID: <202508060106.57616bhq072530@mse-db.zte.com.cn>

Allocate the extra housekeeping metadata for heap or the expected free
memory size cannot be achieved.

Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>
---
 include/sbi/sbi_heap.h      | 3 +++
 lib/sbi/sbi_heap.c          | 5 +++++
 platform/generic/platform.c | 1 +
 3 files changed, 9 insertions(+)

diff --git a/include/sbi/sbi_heap.h b/include/sbi/sbi_heap.h
index a4b3f0c..3d3feee 100644
--- a/include/sbi/sbi_heap.h
+++ b/include/sbi/sbi_heap.h
@@ -98,4 +98,7 @@ int sbi_heap_init_new(struct sbi_heap_control *hpctrl, unsigned long base,
                       unsigned long size);
 int sbi_heap_alloc_new(struct sbi_heap_control **hpctrl);

+/** Return the total heap size with housekeeping **/
+unsigned long sbi_heap_total_size(unsigned long usable_size);
+
 #endif
diff --git a/lib/sbi/sbi_heap.c b/lib/sbi/sbi_heap.c
index 646c2e0..7aa27b1 100644
--- a/lib/sbi/sbi_heap.c
+++ b/lib/sbi/sbi_heap.c
@@ -279,3 +279,8 @@ int sbi_heap_alloc_new(struct sbi_heap_control **hpctrl)
        *hpctrl = sbi_calloc(1, sizeof(struct sbi_heap_control));
        return 0;
 }
+
+unsigned long sbi_heap_total_size(unsigned long usable_size)
+{
+       return usable_size + usable_size / (HEAP_HOUSEKEEPING_FACTOR - 1);
+}
diff --git a/platform/generic/platform.c b/platform/generic/platform.c
index 47e771a..442f7d5 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -41,6 +41,7 @@ static u32 fw_platform_calculate_heap_size(u32 hart_count)

        /* For TLB fifo */
        heap_size += SBI_TLB_INFO_SIZE * (hart_count) * (hart_count);
+       heap_size = sbi_heap_total_size(heap_size);

        return BIT_ALIGN(heap_size, HEAP_BASE_ALIGN);
 }
--
2.43.0


From wu.fei9 at sanechips.com.cn  Tue Aug  5 18:04:36 2025
From: wu.fei9 at sanechips.com.cn (wu.fei9 at sanechips.com.cn)
Date: Wed, 6 Aug 2025 09:04:36 +0800 (CST)
Subject: =?UTF-8?B?W1BBVENIIDMvM10gaW5jbHVkZTogc2JpOiBMaWZ0IHRoZSBtYXhpbXVtIGhhcnRzIHRvIDEwMjQ=?=
In-Reply-To: <20250806084123476SCLxg-qQRa8CRuhuY-dwE@zte.com.cn>
References: 20250806084123476SCLxg-qQRa8CRuhuY-dwE@zte.com.cn
Message-ID: <202508060106.57616maD072614@mse-db.zte.com.cn>

It is expected to have riscv server boards with many cores very soon.

Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>
---
 include/sbi/sbi_hartmask.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/sbi/sbi_hartmask.h b/include/sbi/sbi_hartmask.h
index 200ab6e..2f94f39 100644
--- a/include/sbi/sbi_hartmask.h
+++ b/include/sbi/sbi_hartmask.h
@@ -20,7 +20,7 @@
  * also represents the maximum number of HART ids generic OpenSBI
  * can handle.
  */
-#define SBI_HARTMASK_MAX_BITS          128
+#define SBI_HARTMASK_MAX_BITS          1024

 /** Representation of hartmask */
 struct sbi_hartmask {
--
2.43.0


From wxjstz at 126.com  Tue Aug  5 18:37:21 2025
From: wxjstz at 126.com (Xiang W)
Date: Wed, 06 Aug 2025 09:37:21 +0800
Subject: [PATCH 2/3] platform: generic: Extra memory for housekeeping
In-Reply-To: <202508060106.57616bhq072530@mse-db.zte.com.cn>
References: 20250806084123476SCLxg-qQRa8CRuhuY-dwE@zte.com.cn <202508060106.57616bhq072530@mse-db.zte.com.cn>
Message-ID: <0d619f92fb64e6d36e5fa8ae64ec5cc472f9da98.camel@126.com>

? 2025-08-06?? 09:02 +0800?wu.fei9 at sanechips.com.cn???
> Allocate the extra housekeeping metadata for heap or the expected free
> memory size cannot be achieved.
> 
> Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>
> ---
> ?include/sbi/sbi_heap.h????? | 3 +++
> ?lib/sbi/sbi_heap.c????????? | 5 +++++
> ?platform/generic/platform.c | 1 +
> ?3 files changed, 9 insertions(+)
> 
> diff --git a/include/sbi/sbi_heap.h b/include/sbi/sbi_heap.h
> index a4b3f0c..3d3feee 100644
> --- a/include/sbi/sbi_heap.h
> +++ b/include/sbi/sbi_heap.h
> @@ -98,4 +98,7 @@ int sbi_heap_init_new(struct sbi_heap_control *hpctrl, unsigned long base,
> ?????????????????????? unsigned long size);
> ?int sbi_heap_alloc_new(struct sbi_heap_control **hpctrl);
> 
> +/** Return the total heap size with housekeeping **/
> +unsigned long sbi_heap_total_size(unsigned long usable_size);
> +
> ?#endif
> diff --git a/lib/sbi/sbi_heap.c b/lib/sbi/sbi_heap.c
> index 646c2e0..7aa27b1 100644
> --- a/lib/sbi/sbi_heap.c
> +++ b/lib/sbi/sbi_heap.c
> @@ -279,3 +279,8 @@ int sbi_heap_alloc_new(struct sbi_heap_control **hpctrl)
> ??????? *hpctrl = sbi_calloc(1, sizeof(struct sbi_heap_control));
> ??????? return 0;
> ?}
> +
> +unsigned long sbi_heap_total_size(unsigned long usable_size)
> +{
> +?????? return usable_size + usable_size / (HEAP_HOUSEKEEPING_FACTOR - 1);
This patch will conflict with the patch?
https://patchwork.ozlabs.org/project/opensbi/patch/20250617032306.1494528-3-samuel.holland at sifive.com/.?
If more memory is needed, it is recommended to implement it through other means.

Regards,
Xiang W
> +}
> diff --git a/platform/generic/platform.c b/platform/generic/platform.c
> index 47e771a..442f7d5 100644
> --- a/platform/generic/platform.c
> +++ b/platform/generic/platform.c
> @@ -41,6 +41,7 @@ static u32 fw_platform_calculate_heap_size(u32 hart_count)
> 
> ??????? /* For TLB fifo */
> ??????? heap_size += SBI_TLB_INFO_SIZE * (hart_count) * (hart_count);
> +?????? heap_size = sbi_heap_total_size(heap_size);
> 
> ??????? return BIT_ALIGN(heap_size, HEAP_BASE_ALIGN);
> ?}
> --
> 2.43.0



From wxjstz at 126.com  Tue Aug  5 18:38:14 2025
From: wxjstz at 126.com (Xiang W)
Date: Wed, 06 Aug 2025 09:38:14 +0800
Subject: [PATCH 3/3] include: sbi: Lift the maximum harts to 1024
In-Reply-To: <202508060106.57616maD072614@mse-db.zte.com.cn>
References: 20250806084123476SCLxg-qQRa8CRuhuY-dwE@zte.com.cn <202508060106.57616maD072614@mse-db.zte.com.cn>
Message-ID: <1907533a372fa53fe08120c9e91e986c8d134117.camel@126.com>

? 2025-08-06?? 09:04 +0800?wu.fei9 at sanechips.com.cn???
> It is expected to have riscv server boards with many cores very soon.
> 
> Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>
> ---
> ?include/sbi/sbi_hartmask.h | 2 +-
> ?1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/sbi/sbi_hartmask.h b/include/sbi/sbi_hartmask.h
> index 200ab6e..2f94f39 100644
> --- a/include/sbi/sbi_hartmask.h
> +++ b/include/sbi/sbi_hartmask.h
> @@ -20,7 +20,7 @@
> ? * also represents the maximum number of HART ids generic OpenSBI
> ? * can handle.
> ? */
> -#define SBI_HARTMASK_MAX_BITS????????? 128
> +#define SBI_HARTMASK_MAX_BITS????????? 1024
128 is suitable for most cases. Adding this macro will increase?
the memory consumption of most platforms. It is recommended to?
add a custom option in Kconfig

Regards,
Xiang W
> 
> ?/** Representation of hartmask */
> ?struct sbi_hartmask {
> --
> 2.43.0



From z_bajeer at yeah.net  Tue Aug  5 20:29:24 2025
From: z_bajeer at yeah.net (Yang Jialong)
Date: Wed,  6 Aug 2025 11:29:24 +0800
Subject: [PATCH] aplic: fix lock machanism in xmsiaddrcfg(h)
Message-ID: <20250806032924.3532975-1-z_bajeer@yeah.net>

4.5.4. Supervisor MSI address configuration (smsiaddrcfg and smsiaddrcfgh)
If register mmsiaddrcfgh of the domain has bit L set to one, then
smsiaddrcfg and smsiaddrcfgh are locked as read-only alongside
mmsiaddrcfg and mmsiaddrcfgh.

Signed-off-by: Yang Jialong <z_bajeer at yeah.net>
---
 lib/utils/irqchip/aplic.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
index 72906d5..e4a29ae 100644
--- a/lib/utils/irqchip/aplic.c
+++ b/lib/utils/irqchip/aplic.c
@@ -121,10 +121,6 @@ static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
 	u32 val;
 	unsigned long base_ppn;
 
-	/* Check if MSI config is already locked */
-	if (readl(msicfgaddrH) & APLIC_xMSICFGADDRH_L)
-		return;
-
 	/* Compute the MSI base PPN */
 	base_ppn = msicfg->base_addr >> APLIC_xMSICFGADDR_PPN_SHIFT;
 	base_ppn &= ~APLIC_xMSICFGADDR_PPN_HART(msicfg->lhxs);
@@ -167,7 +163,7 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
 
 int aplic_cold_irqchip_init(struct aplic_data *aplic)
 {
-	int rc;
+	int rc, locked;
 	u32 i, j, tmp;
 	struct aplic_delegate_data *deleg;
 	u32 first_deleg_irq, last_deleg_irq;
@@ -247,12 +243,13 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
 	}
 
 	/* MSI configuration */
-	if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
+	locked = readl((void *)(aplic->addr + APLIC_MMSICFGADDRH)) & APLIC_xMSICFGADDRH_L;
+	if (aplic->targets_mmode && aplic->has_msicfg_mmode && !locked) {
 		aplic_writel_msicfg(&aplic->msicfg_mmode,
 				(void *)(aplic->addr + APLIC_MMSICFGADDR),
 				(void *)(aplic->addr + APLIC_MMSICFGADDRH));
 	}
-	if (aplic->targets_mmode && aplic->has_msicfg_smode) {
+	if (aplic->targets_mmode && aplic->has_msicfg_smode && !locked) {
 		aplic_writel_msicfg(&aplic->msicfg_smode,
 				(void *)(aplic->addr + APLIC_SMSICFGADDR),
 				(void *)(aplic->addr + APLIC_SMSICFGADDRH));
-- 
2.34.1



From z_bajeer at yeah.net  Tue Aug  5 23:15:59 2025
From: z_bajeer at yeah.net (z_bajeer at yeah.net)
Date: Wed, 6 Aug 2025 06:15:59 +0000
Subject: =?utf-8?B?5Zue5aSNOiBbUEFUQ0hdIGFwbGljOiBmaXggbG9jayBtYWNoYW5pc20gaW4g?=
 =?utf-8?Q?xmsiaddrcfg(h)?=
In-Reply-To: <20250806032924.3532975-1-z_bajeer@yeah.net>
References: <20250806032924.3532975-1-z_bajeer@yeah.net>
Message-ID: <OS3PR01MB7756B0E03E020CFEB54FCF7EF52DA@OS3PR01MB7756.jpnprd01.prod.outlook.com>

And there is no field L in smsiaddrcfgh. We should use the L field in mmsiaddrcfgh for all xmsiaddrcfg(h).


________________________________________
???: Yang Jialong <z_bajeer at yeah.net>
???: 2025 ? 8 ? 06 ? ??? 11:29
???: opensbi at lists.infradead.org <opensbi at lists.infradead.org>
??: yangjialong at rvcore.com <yangjialong at rvcore.com>; Yang Jialong <z_bajeer at yeah.net>
??: [PATCH] aplic: fix lock machanism in xmsiaddrcfg(h)


4.5.4. Supervisor MSI address configuration (smsiaddrcfg and smsiaddrcfgh)
If register mmsiaddrcfgh of the domain has bit L set to one, then
smsiaddrcfg and smsiaddrcfgh are locked as read-only alongside
mmsiaddrcfg and mmsiaddrcfgh.

Signed-off-by: Yang Jialong <z_bajeer at yeah.net>
---
?lib/utils/irqchip/aplic.c | 11 ++++-------
?1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
index 72906d5..e4a29ae 100644
--- a/lib/utils/irqchip/aplic.c
+++ b/lib/utils/irqchip/aplic.c
@@ -121,10 +121,6 @@ static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
???????? u32 val;
???????? unsigned long base_ppn;
?
-?????? /* Check if MSI config is already locked */
-?????? if (readl(msicfgaddrH) & APLIC_xMSICFGADDRH_L)
-?????????????? return;
-
???????? /* Compute the MSI base PPN */
???????? base_ppn = msicfg->base_addr >> APLIC_xMSICFGADDR_PPN_SHIFT;
???????? base_ppn &= ~APLIC_xMSICFGADDR_PPN_HART(msicfg->lhxs);
@@ -167,7 +163,7 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
?
?int aplic_cold_irqchip_init(struct aplic_data *aplic)
?{
-?????? int rc;
+?????? int rc, locked;
???????? u32 i, j, tmp;
???????? struct aplic_delegate_data *deleg;
???????? u32 first_deleg_irq, last_deleg_irq;
@@ -247,12 +243,13 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
???????? }
?
???????? /* MSI configuration */
-?????? if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
+?????? locked = readl((void *)(aplic->addr + APLIC_MMSICFGADDRH)) & APLIC_xMSICFGADDRH_L;
+?????? if (aplic->targets_mmode && aplic->has_msicfg_mmode && !locked) {
???????????????? aplic_writel_msicfg(&aplic->msicfg_mmode,
???????????????????????????????? (void *)(aplic->addr + APLIC_MMSICFGADDR),
???????????????????????????????? (void *)(aplic->addr + APLIC_MMSICFGADDRH));
???????? }
-?????? if (aplic->targets_mmode && aplic->has_msicfg_smode) {
+?????? if (aplic->targets_mmode && aplic->has_msicfg_smode && !locked) {
???????????????? aplic_writel_msicfg(&aplic->msicfg_smode,
???????????????????????????????? (void *)(aplic->addr + APLIC_SMSICFGADDR),
???????????????????????????????? (void *)(aplic->addr + APLIC_SMSICFGADDRH));
-- 
2.34.1



From jesse at rivosinc.com  Wed Aug  6 10:10:41 2025
From: jesse at rivosinc.com (Jesse Taube)
Date: Wed,  6 Aug 2025 10:10:41 -0700
Subject: [PATCH] dbtr: Fix sbi_dbtr_read_trig to read from CSRs
Message-ID: <20250806171041.810270-1-jesse@rivosinc.com>

sbi_dbtr_read_trig returned the saved state of tdata{1-3}, when it
should have returned the updated state read from CSRs.

Update sbi_dbtr_read_trig to return updated state read from CSRs.

Signed-off-by: Jesse Taube <jesse at rivosinc.com>
---
 lib/sbi/sbi_dbtr.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/sbi/sbi_dbtr.c b/lib/sbi/sbi_dbtr.c
index a832c7f1..a39c3164 100644
--- a/lib/sbi/sbi_dbtr.c
+++ b/lib/sbi/sbi_dbtr.c
@@ -529,9 +529,9 @@ int sbi_dbtr_read_trig(unsigned long smode,
 		xmit = &entry->data;
 		trig = INDEX_TO_TRIGGER((_idx + trig_idx_base));
 		xmit->tstate = cpu_to_lle(trig->state);
-		xmit->tdata1 = cpu_to_lle(trig->tdata1);
-		xmit->tdata2 = cpu_to_lle(trig->tdata2);
-		xmit->tdata3 = cpu_to_lle(trig->tdata3);
+		xmit->tdata1 = csr_read(CSR_TDATA1);
+		xmit->tdata2 = csr_read(CSR_TDATA2);
+		xmit->tdata3 = csr_read(CSR_TDATA1);
 	}
 	sbi_hart_unmap_saddr();
 
-- 
2.43.0



From wxjstz at 126.com  Wed Aug  6 17:14:31 2025
From: wxjstz at 126.com (Xiang W)
Date: Thu, 07 Aug 2025 08:14:31 +0800
Subject: [PATCH] dbtr: Fix sbi_dbtr_read_trig to read from CSRs
In-Reply-To: <20250806171041.810270-1-jesse@rivosinc.com>
References: <20250806171041.810270-1-jesse@rivosinc.com>
Message-ID: <332ca1a6955e1b1be1b7157180757cfa9acbda44.camel@126.com>

? 2025-08-06?? 10:10 -0700?Jesse Taube???
> sbi_dbtr_read_trig returned the saved state of tdata{1-3}, when it
> should have returned the updated state read from CSRs.
> 
> Update sbi_dbtr_read_trig to return updated state read from CSRs.
> 
> Signed-off-by: Jesse Taube <jesse at rivosinc.com>
> ---
> ?lib/sbi/sbi_dbtr.c | 6 +++---
> ?1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/sbi/sbi_dbtr.c b/lib/sbi/sbi_dbtr.c
> index a832c7f1..a39c3164 100644
> --- a/lib/sbi/sbi_dbtr.c
> +++ b/lib/sbi/sbi_dbtr.c
> @@ -529,9 +529,9 @@ int sbi_dbtr_read_trig(unsigned long smode,
> ?		xmit = &entry->data;
> ?		trig = INDEX_TO_TRIGGER((_idx + trig_idx_base));
> ?		xmit->tstate = cpu_to_lle(trig->state);
> -		xmit->tdata1 = cpu_to_lle(trig->tdata1);
> -		xmit->tdata2 = cpu_to_lle(trig->tdata2);
> -		xmit->tdata3 = cpu_to_lle(trig->tdata3);
> +		xmit->tdata1 = csr_read(CSR_TDATA1);
> +		xmit->tdata2 = csr_read(CSR_TDATA2);
> +		xmit->tdata3 = csr_read(CSR_TDATA1);

the debug trigger state and configuration consisting of four XLEN-bit?
words are written in little-endian format

Do not remove cpu_to_lle.

Regards,
Xiang W
> ?	}
> ?	sbi_hart_unmap_saddr();
> ?
> -- 
> 2.43.0
> 



From wu.fei9 at sanechips.com.cn  Thu Aug  7 03:18:44 2025
From: wu.fei9 at sanechips.com.cn (wu.fei9 at sanechips.com.cn)
Date: Thu, 7 Aug 2025 18:18:44 +0800 (CST)
Subject: =?UTF-8?B?UmU6IFtQQVRDSCAyLzNdIHBsYXRmb3JtOiBnZW5lcmljOiBFeHRyYSBtZW1vcnkgZm9yIGhvdXNla2VlcGluZw==?=
In-Reply-To: <0d619f92fb64e6d36e5fa8ae64ec5cc472f9da98.camel@126.com>
References: 20250806084123476SCLxg-qQRa8CRuhuY-dwE@zte.com.cn,202508060106.57616bhq072530@mse-db.zte.com.cn,0d619f92fb64e6d36e5fa8ae64ec5cc472f9da98.camel@126.com
Message-ID: <202508071041.577AfcFt026811@mse-fl1.zte.com.cn>

> > diff --git a/lib/sbi/sbi_heap.c b/lib/sbi/sbi_heap.c
> > index 646c2e0..7aa27b1 100644
> > --- a/lib/sbi/sbi_heap.c
> > +++ b/lib/sbi/sbi_heap.c
> > @@ -279,3 +279,8 @@ int sbi_heap_alloc_new(struct sbi_heap_control **hpctrl)
> > *hpctrl = sbi_calloc(1, sizeof(struct sbi_heap_control));
> > return 0;
> > }
> > +
> > +unsigned long sbi_heap_total_size(unsigned long usable_size)
> > +{
> > + return usable_size + usable_size / (HEAP_HOUSEKEEPING_FACTOR - 1);
> This patch will conflict with the patch
> https://patchwork.ozlabs.org/project/opensbi/patch/20250617032306.1494528-3-samuel.holland at sifive.com/.

Thank you for pointing it out. Is this patch queued to upstream? Where can I
find this kind of patches?

> If more memory is needed, it is recommended to implement it through other means.

Yes, the housekeeping metadata is still needed. Let me try another version.

Thanks,
Fei.

> Regards,
> Xiang W


From wxjstz at 126.com  Fri Aug  8 02:16:27 2025
From: wxjstz at 126.com (Xiang W)
Date: Fri, 08 Aug 2025 17:16:27 +0800
Subject: [PATCH 2/3] platform: generic: Extra memory for housekeeping
In-Reply-To: <202508071041.577AfcFt026811@mse-fl1.zte.com.cn>
References: 20250806084123476SCLxg-qQRa8CRuhuY-dwE@zte.com.cn,202508060106.57616bhq072530@mse-db.zte.com.cn,0d619f92fb64e6d36e5fa8ae64ec5cc472f9da98.camel@126.com <202508071041.577AfcFt026811@mse-fl1.zte.com.cn>
Message-ID: <dab816b55e9dd48ae33aefe006febe02451f8b02.camel@126.com>

? 2025-08-07?? 18:18 +0800?wu.fei9 at sanechips.com.cn???
> > > diff --git a/lib/sbi/sbi_heap.c b/lib/sbi/sbi_heap.c
> > > index 646c2e0..7aa27b1 100644
> > > --- a/lib/sbi/sbi_heap.c
> > > +++ b/lib/sbi/sbi_heap.c
> > > @@ -279,3 +279,8 @@ int sbi_heap_alloc_new(struct sbi_heap_control **hpctrl)
> > > *hpctrl = sbi_calloc(1, sizeof(struct sbi_heap_control));
> > > return 0;
> > > }
> > > +
> > > +unsigned long sbi_heap_total_size(unsigned long usable_size)
> > > +{
> > > + return usable_size + usable_size / (HEAP_HOUSEKEEPING_FACTOR - 1);
> > This patch will conflict with the patch
> > https://patchwork.ozlabs.org/project/opensbi/patch/20250617032306.1494528-3-samuel.holland at sifive.com/.
> 
> Thank you for pointing it out. Is this patch queued to upstream? Where can I
> find this kind of patches?

This patch is awaiting review. You can find patches awaiting review at?
https://patchwork.ozlabs.org/project/opensbi/list/

Regards,
Xiang W
> 
> > If more memory is needed, it is recommended to implement it through other means.
> 
> Yes, the housekeeping metadata is still needed. Let me try another version.
> 
> Thanks,
> Fei.
> 
> > Regards,
> > Xiang W



From jimmy.lerhun at thalesgroup.com  Fri Aug  8 06:35:43 2025
From: jimmy.lerhun at thalesgroup.com (LE RHUN Jimmy)
Date: Fri, 8 Aug 2025 13:35:43 +0000
Subject: platform: add CVA6 platform and support for PMU.
Message-ID: <1aadc5594074447a8c38da0ac33b5235@thalesgroup.com>

Classified as: {OPEN}


Add a new platform called CVA6 (https://github.com/openhwgroup/cva6).
Add support for Performance Monitoring Unit for this platform.
This development starts from tag v1.5.

Signed-off-by: Jimmy Le Rhun <jimmy.lerhun at thalesgroup.com> 

{OPEN}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenSBI_1.5_add_CVA6_PMU.patch
Type: application/octet-stream
Size: 9025 bytes
Desc: OpenSBI_1.5_add_CVA6_PMU.patch
URL: <http://lists.infradead.org/pipermail/opensbi/attachments/20250808/96521361/attachment.obj>

From jrtc27 at jrtc27.com  Fri Aug  8 06:41:31 2025
From: jrtc27 at jrtc27.com (Jessica Clarke)
Date: Fri, 8 Aug 2025 14:41:31 +0100
Subject: platform: add CVA6 platform and support for PMU.
In-Reply-To: <1aadc5594074447a8c38da0ac33b5235@thalesgroup.com>
References: <1aadc5594074447a8c38da0ac33b5235@thalesgroup.com>
Message-ID: <1FC085FD-22F6-4FFF-854F-8E1186C46FD8@jrtc27.com>

On 8 Aug 2025, at 14:35, LE RHUN Jimmy <jimmy.lerhun at thalesgroup.com> wrote:
> 
> Classified as: {OPEN}
> 
> 
> Add a new platform called CVA6 (https://github.com/openhwgroup/cva6).
> Add support for Performance Monitoring Unit for this platform.
> This development starts from tag v1.5.

Does generic not work for it? My understanding was it did, and if
support for anything is missing in generic it should be added to
generic.

Jessica

> Signed-off-by: Jimmy Le Rhun <jimmy.lerhun at thalesgroup.com> 
> 
> {OPEN}
> <OpenSBI_1.5_add_CVA6_PMU.patch>-- 
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi



From jimmy.lerhun at thalesgroup.com  Fri Aug  8 07:56:09 2025
From: jimmy.lerhun at thalesgroup.com (LE RHUN Jimmy)
Date: Fri, 8 Aug 2025 14:56:09 +0000
Subject: platform: add CVA6 platform and support for PMU.
In-Reply-To: <1FC085FD-22F6-4FFF-854F-8E1186C46FD8@jrtc27.com>
References: <1aadc5594074447a8c38da0ac33b5235@thalesgroup.com>
 <1FC085FD-22F6-4FFF-854F-8E1186C46FD8@jrtc27.com>
Message-ID: <e8a80f721c3a42eabc7338307234af09@thalesgroup.com>

Classified as: {OPEN}

Vendredi 8 ao?t 2025 15:42, Jessica Clarke <jrtc27 at jrtc27.com> a ?crit :
>On 8 Aug 2025, at 14:35, LE RHUN Jimmy <jimmy.lerhun at thalesgroup.com> wrote:
>> 
>> Add a new platform called CVA6 (https://github.com/openhwgroup/cva6).
>> Add support for Performance Monitoring Unit for this platform.
>> This development starts from tag v1.5.
>
>Does generic not work for it? My understanding was it did, and if support for anything is missing in generic it should be added to generic.
>
>Jessica

Thanks for your quick answer. I'm using the standard Yocto distribution for this core :
https://github.com/openhwgroup/meta-cva6-yocto and it has a specific configuration for OpenSBI that was not submitted here and that lacked PMU support. 
I had to define hardware-specific information about performance counters. 
Actually CVA6 is an evolution of Ariane (that exists in platform/fpga/ariane).

Kind regards,
Jimmy

>> Signed-off-by: Jimmy Le Rhun <jimmy.lerhun at thalesgroup.com>
>> 
>> <OpenSBI_1.5_add_CVA6_PMU.patch>--
>> opensbi mailing list
>> opensbi at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/opensbi


{OPEN}


From nick.hu at sifive.com  Sun Aug 10 19:16:16 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Mon, 11 Aug 2025 10:16:16 +0800
Subject: [PATCH v3 05/12] platform: generic: Add SiFive development platform
In-Reply-To: <CAAhSdy2+zx8NWFQ8O7-qPNpkb7Xu_8VrNha7+JaBskU1L-woDw@mail.gmail.com>
References: <20250708074940.10904-1-nick.hu@sifive.com> <20250708074940.10904-6-nick.hu@sifive.com>
 <CAAhSdy2+zx8NWFQ8O7-qPNpkb7Xu_8VrNha7+JaBskU1L-woDw@mail.gmail.com>
Message-ID: <CAKddAkCYGg=kPFajBvckC4PTYeJQxHzbK7herqxynqGjyj2QHA@mail.gmail.com>

On Mon, Aug 4, 2025 at 4:37?PM Anup Patel <anup at brainfault.org> wrote:
>
> On Tue, Jul 8, 2025 at 1:20?PM Nick Hu <nick.hu at sifive.com> wrote:
> >
> > From: Vincent Chen <vincent.chen at sifive.com>
> >
> > The sifive_dev_platform is a new platform which is compatible to the
> > generic platform to place some features which are only for the SiFive
> > development machine.
> >
> > Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
> > Co-developed-by: Nick Hu <nick.hu at sifive.com>
> > Signed-off-by: Nick Hu <nick.hu at sifive.com>
> > ---
> >  platform/generic/Kconfig                      |  5 +++
> >  platform/generic/configs/defconfig            |  1 +
> >  platform/generic/sifive/objects.mk            |  3 ++
> >  platform/generic/sifive/sifive_dev_platform.c | 41 +++++++++++++++++++
> >  4 files changed, 50 insertions(+)
> >  create mode 100644 platform/generic/sifive/sifive_dev_platform.c
> >
> > diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
> > index a24d6ab2..20c25a83 100644
> > --- a/platform/generic/Kconfig
> > +++ b/platform/generic/Kconfig
> > @@ -43,6 +43,11 @@ config PLATFORM_RENESAS_RZFIVE
> >         select ANDES_PMU
> >         default n
> >
> > +config PLATFORM_SIFIVE_DEV
> > +       bool "SiFive development platform support"
> > +       depends on FDT_CACHE
> > +       default n
> > +
> >  config PLATFORM_SIFIVE_FU540
> >         bool "SiFive FU540 support"
> >         default n
> > diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> > index 6b219cfb..42e7ef75 100644
> > --- a/platform/generic/configs/defconfig
> > +++ b/platform/generic/configs/defconfig
> > @@ -1,6 +1,7 @@
> >  CONFIG_PLATFORM_ALLWINNER_D1=y
> >  CONFIG_PLATFORM_ANDES_AE350=y
> >  CONFIG_PLATFORM_RENESAS_RZFIVE=y
> > +CONFIG_PLATFORM_SIFIVE_DEV=y
> >  CONFIG_PLATFORM_SIFIVE_FU540=y
> >  CONFIG_PLATFORM_SIFIVE_FU740=y
> >  CONFIG_PLATFORM_SOPHGO_SG2042=y
> > diff --git a/platform/generic/sifive/objects.mk b/platform/generic/sifive/objects.mk
> > index d75e444a..d32e1273 100644
> > --- a/platform/generic/sifive/objects.mk
> > +++ b/platform/generic/sifive/objects.mk
> > @@ -2,6 +2,9 @@
> >  # SPDX-License-Identifier: BSD-2-Clause
> >  #
> >
> > +carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_DEV) += sifive_dev_platform
> > +platform-objs-$(CONFIG_PLATFORM_SIFIVE_DEV) += sifive/sifive_dev_platform.o
> > +
> >  carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive_fu540
> >  platform-objs-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive/fu540.o
> >
> > diff --git a/platform/generic/sifive/sifive_dev_platform.c b/platform/generic/sifive/sifive_dev_platform.c
> > new file mode 100644
> > index 00000000..ac659868
> > --- /dev/null
> > +++ b/platform/generic/sifive/sifive_dev_platform.c
> > @@ -0,0 +1,41 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2025 SiFive Inc.
> > + */
> > +
> > +#include <platform_override.h>
> > +#include <sbi_utils/cache/fdt_cmo_helper.h>
> > +
> > +static int sifive_early_init(bool cold_boot)
> > +{
> > +       int rc;
> > +
> > +       rc = generic_early_init(cold_boot);
> > +       if (rc)
> > +               return rc;
> > +
> > +       rc = fdt_cmo_init(cold_boot);
> > +       if (rc)
> > +               return rc;
>
> Why not call fdt_cmo_init() directly as part of generic_early_init() ?
>
Good point! I'll move it to the generic_early_init().

> > +
> > +       return 0;
> > +}
> > +
> > +static int sifive_platform_init(const void *fdt, int nodeoff,
> > +                               const struct fdt_match *match)
> > +{
> > +       generic_platform_ops.early_init = sifive_early_init;
> > +
> > +       return 0;
> > +}
> > +
> > +static const struct fdt_match sifive_dev_platform_match[] = {
> > +       { .compatible = "sifive-dev" },
> > +       { },
> > +};
> > +
> > +const struct fdt_driver sifive_dev_platform = {
> > +       .match_table = sifive_dev_platform_match,
> > +       .init = sifive_platform_init,
> > +};
> > --
> > 2.17.1
> >
>
> Regards,
> Anup


From jesse at rivosinc.com  Mon Aug 11 08:29:47 2025
From: jesse at rivosinc.com (Jesse Taube)
Date: Mon, 11 Aug 2025 08:29:47 -0700
Subject: [PATCH v2] dbtr: Fix sbi_dbtr_read_trig to read from CSRs
Message-ID: <20250811152947.851208-1-jesse@rivosinc.com>

sbi_dbtr_read_trig returned the saved state of tdata{1-3}, when it
should have returned the updated state read from CSRs.

Update sbi_dbtr_read_trig to return updated state read from CSRs.

Signed-off-by: Jesse Taube <jesse at rivosinc.com>
---
V1 -> V2:
 - Add back missing cpu_to_lle
---
 lib/sbi/sbi_dbtr.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/sbi/sbi_dbtr.c b/lib/sbi/sbi_dbtr.c
index a832c7f1..c6b04aab 100644
--- a/lib/sbi/sbi_dbtr.c
+++ b/lib/sbi/sbi_dbtr.c
@@ -529,9 +529,9 @@ int sbi_dbtr_read_trig(unsigned long smode,
 		xmit = &entry->data;
 		trig = INDEX_TO_TRIGGER((_idx + trig_idx_base));
 		xmit->tstate = cpu_to_lle(trig->state);
-		xmit->tdata1 = cpu_to_lle(trig->tdata1);
-		xmit->tdata2 = cpu_to_lle(trig->tdata2);
-		xmit->tdata3 = cpu_to_lle(trig->tdata3);
+		xmit->tdata1 = cpu_to_lle(csr_read(CSR_TDATA1));
+		xmit->tdata2 = cpu_to_lle(csr_read(CSR_TDATA2));
+		xmit->tdata3 = cpu_to_lle(csr_read(CSR_TDATA1));
 	}
 	sbi_hart_unmap_saddr();
 
-- 
2.43.0



From maherme.dev at gmail.com  Mon Aug 11 08:48:01 2025
From: maherme.dev at gmail.com (=?UTF-8?Q?Manuel_Hern=C3=A1ndez_M=C3=A9ndez?=)
Date: Mon, 11 Aug 2025 17:48:01 +0200
Subject: platform: add CVA6 platform and support for PMU.
In-Reply-To: <e8a80f721c3a42eabc7338307234af09@thalesgroup.com>
References: <1aadc5594074447a8c38da0ac33b5235@thalesgroup.com>
 <1FC085FD-22F6-4FFF-854F-8E1186C46FD8@jrtc27.com> <e8a80f721c3a42eabc7338307234af09@thalesgroup.com>
Message-ID: <CACwcpNuASn_YQsMuHK568gGqr+hB0KEc=p_EVzKqkjBPuRuQ_A@mail.gmail.com>

Hi,

I sent a patch to add PMU to Openpiton platform
(https://lists.infradead.org/pipermail/opensbi/2025-July/008681.html).
This should work for Ariane and CVA6 as well. Following Samuel's
recommendation, I am working on porting the Openpiton platform from
fpga to generic. My plan is also to port the Ariane core later.

Regards,
Manuel.


On Fri, Aug 8, 2025 at 4:56?PM LE RHUN Jimmy
<jimmy.lerhun at thalesgroup.com> wrote:
>
> Classified as: {OPEN}
>
> Vendredi 8 ao?t 2025 15:42, Jessica Clarke <jrtc27 at jrtc27.com> a ?crit :
> >On 8 Aug 2025, at 14:35, LE RHUN Jimmy <jimmy.lerhun at thalesgroup.com> wrote:
> >>
> >> Add a new platform called CVA6 (https://github.com/openhwgroup/cva6).
> >> Add support for Performance Monitoring Unit for this platform.
> >> This development starts from tag v1.5.
> >
> >Does generic not work for it? My understanding was it did, and if support for anything is missing in generic it should be added to generic.
> >
> >Jessica
>
> Thanks for your quick answer. I'm using the standard Yocto distribution for this core :
> https://github.com/openhwgroup/meta-cva6-yocto and it has a specific configuration for OpenSBI that was not submitted here and that lacked PMU support.
> I had to define hardware-specific information about performance counters.
> Actually CVA6 is an evolution of Ariane (that exists in platform/fpga/ariane).
>
> Kind regards,
> Jimmy
>
> >> Signed-off-by: Jimmy Le Rhun <jimmy.lerhun at thalesgroup.com>
> >>
> >> <OpenSBI_1.5_add_CVA6_PMU.patch>--
> >> opensbi mailing list
> >> opensbi at lists.infradead.org
> >> http://lists.infradead.org/mailman/listinfo/opensbi
>
>
> {OPEN}
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi


From maherme.dev at gmail.com  Wed Aug 13 03:42:00 2025
From: maherme.dev at gmail.com (=?UTF-8?q?Manuel=20Hern=C3=A1ndez=20M=C3=A9ndez?=)
Date: Wed, 13 Aug 2025 12:42:00 +0200
Subject: [PATCH] platform: openpiton: Move openpiton platform from fpga to generic
In-Reply-To: <42fb18cc-d579-490f-b7db-89cb8d228ee8@sifive.com>
References: <42fb18cc-d579-490f-b7db-89cb8d228ee8@sifive.com>
Message-ID: <20250813104200.33028-1-maherme.dev@gmail.com>

The OpenPiton framework has a generic PMU that is not used by OpenSBI.
Due to OpenSBI?s build system we cannot directly reuse the generic
platform functions, so move the OpenPiton platform to generic. Also due
to the generic platform is where new features are added.

Signed-off-by: Manuel Hern?ndez M?ndez <maherme.dev at gmail.com>
---
 platform/fpga/openpiton/Kconfig               | 10 ----
 platform/fpga/openpiton/configs/defconfig     |  0
 platform/fpga/openpiton/objects.mk            | 41 ----------------
 platform/generic/Kconfig                      |  4 ++
 platform/generic/configs/defconfig            |  1 +
 platform/generic/openhwgroup/objects.mk       |  8 ++++
 .../openhwgroup/openpiton.c}                  | 48 +++++++++----------
 7 files changed, 36 insertions(+), 76 deletions(-)
 delete mode 100644 platform/fpga/openpiton/Kconfig
 delete mode 100644 platform/fpga/openpiton/configs/defconfig
 delete mode 100644 platform/fpga/openpiton/objects.mk
 create mode 100644 platform/generic/openhwgroup/objects.mk
 rename platform/{fpga/openpiton/platform.c => generic/openhwgroup/openpiton.c} (82%)

diff --git a/platform/fpga/openpiton/Kconfig b/platform/fpga/openpiton/Kconfig
deleted file mode 100644
index bc9c86ee..00000000
--- a/platform/fpga/openpiton/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: BSD-2-Clause
-
-config PLATFORM_OPENPITON_FPGA
-	bool
-	select FDT
-	select IPI_MSWI
-	select IRQCHIP_PLIC
-	select SERIAL_UART8250
-	select TIMER_MTIMER
-	default y
diff --git a/platform/fpga/openpiton/configs/defconfig b/platform/fpga/openpiton/configs/defconfig
deleted file mode 100644
index e69de29b..00000000
diff --git a/platform/fpga/openpiton/objects.mk b/platform/fpga/openpiton/objects.mk
deleted file mode 100644
index 1a0ce0c7..00000000
--- a/platform/fpga/openpiton/objects.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# SPDX-License-Identifier: BSD-2-Clause
-#
-# Copyright (c) 2020 Western Digital Corporation or its affiliates.
-#
-
-# Compiler flags
-platform-cppflags-y =
-platform-cflags-y =
-platform-asflags-y =
-platform-ldflags-y =
-
-# Objects to build
-platform-objs-y += platform.o
-
-PLATFORM_RISCV_XLEN = 64
-
-# Blobs to build
-FW_JUMP=n
-
-ifeq ($(PLATFORM_RISCV_XLEN), 32)
- # This needs to be 4MB aligned for 32-bit support
- FW_JUMP_ADDR=0x80400000
- else
- # This needs to be 2MB aligned for 64-bit support
- FW_JUMP_ADDR=0x80200000
- endif
-FW_JUMP_FDT_ADDR=0x82200000
-
-# Firmware with payload configuration.
-FW_PAYLOAD=y
-
-ifeq ($(PLATFORM_RISCV_XLEN), 32)
-# This needs to be 4MB aligned for 32-bit support
-  FW_PAYLOAD_OFFSET=0x400000
-else
-# This needs to be 2MB aligned for 64-bit support
-  FW_PAYLOAD_OFFSET=0x200000
-endif
-FW_PAYLOAD_FDT_ADDR=0x82200000
-FW_PAYLOAD_ALIGN=0x1000
diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
index a24d6ab2..7559a4bd 100644
--- a/platform/generic/Kconfig
+++ b/platform/generic/Kconfig
@@ -36,6 +36,10 @@ config PLATFORM_ANDES_AE350
 	select ANDES_PMA
 	default n
 
+config PLATFORM_OPENHWGROUP_OPENPITON
+	bool "OpenHWGroup Openpiton support"
+	default n
+
 config PLATFORM_RENESAS_RZFIVE
 	bool "Renesas RZ/Five support"
 	select ANDES_PMA
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index c7a6531e..4b93d0bc 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -7,6 +7,7 @@ CONFIG_PLATFORM_SOPHGO_SG2042=y
 CONFIG_PLATFORM_STARFIVE_JH7110=y
 CONFIG_PLATFORM_THEAD=y
 CONFIG_PLATFORM_MIPS_P8700=y
+CONFIG_PLATFORM_OPENHWGROUP_OPENPITON=y
 CONFIG_FDT_CPPC=y
 CONFIG_FDT_CPPC_RPMI=y
 CONFIG_FDT_GPIO=y
diff --git a/platform/generic/openhwgroup/objects.mk b/platform/generic/openhwgroup/objects.mk
new file mode 100644
index 00000000..ab6ca79d
--- /dev/null
+++ b/platform/generic/openhwgroup/objects.mk
@@ -0,0 +1,8 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+
+carray-platform_override_modules-$(CONFIG_PLATFORM_OPENHWGROUP_OPENPITON) += openhwgroup_openpiton
+platform-objs-$(CONFIG_PLATFORM_OPENHWGROUP_OPENPITON) += openhwgroup/openpiton.o
diff --git a/platform/fpga/openpiton/platform.c b/platform/generic/openhwgroup/openpiton.c
similarity index 82%
rename from platform/fpga/openpiton/platform.c
rename to platform/generic/openhwgroup/openpiton.c
index faa299ce..6417f130 100644
--- a/platform/fpga/openpiton/platform.c
+++ b/platform/generic/openhwgroup/openpiton.c
@@ -3,12 +3,12 @@
  * Copyright (c) 2020 Western Digital Corporation or its affiliates.
  */
 
-#include <sbi/riscv_asm.h>
-#include <sbi/riscv_encoding.h>
-#include <sbi/riscv_io.h>
-#include <sbi/sbi_const.h>
-#include <sbi/sbi_hart.h>
-#include <sbi/sbi_platform.h>
+#include <platform_override.h>
+//#include <sbi/riscv_asm.h>
+//#include <sbi/riscv_encoding.h>
+//#include <sbi/riscv_io.h>
+//#include <sbi/sbi_const.h>
+//#include <sbi/sbi_hart.h>
 #include <sbi_utils/fdt/fdt_helper.h>
 #include <sbi_utils/fdt/fdt_fixup.h>
 #include <sbi_utils/ipi/aclint_mswi.h>
@@ -156,25 +156,23 @@ static int openpiton_timer_init(void)
 	return aclint_mtimer_cold_init(&mtimer, NULL);
 }
 
-/*
- * Platform descriptor.
- */
-const struct sbi_platform_operations platform_ops = {
-	.early_init = openpiton_early_init,
-	.final_init = openpiton_final_init,
-	.irqchip_init = openpiton_irqchip_init,
-	.ipi_init = openpiton_ipi_init,
-	.timer_init = openpiton_timer_init,
+static int openhwgroup_openpiton_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match)
+{
+	generic_platform_ops.early_init = openpiton_early_init;
+	generic_platform_ops.timer_init = openpiton_timer_init;
+	generic_platform_ops.ipi_init = openpiton_ipi_init;
+	generic_platform_ops.irqchip_init = openpiton_irqchip_init;
+	generic_platform_ops.final_init = openpiton_final_init;
+
+	return 0;
+}
+
+static const struct fdt_match openhwgroup_openpiton_match[] = {
+	{ .compatible = "openpiton,cva6platform" },
+	{ },
 };
 
-const struct sbi_platform platform = {
-	.opensbi_version = OPENSBI_VERSION,
-	.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
-	.name = "OPENPITON RISC-V",
-	.features = SBI_PLATFORM_DEFAULT_FEATURES,
-	.hart_count = OPENPITON_DEFAULT_HART_COUNT,
-	.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
-	.heap_size =
-		SBI_PLATFORM_DEFAULT_HEAP_SIZE(OPENPITON_DEFAULT_HART_COUNT),
-	.platform_ops_addr = (unsigned long)&platform_ops
+const struct fdt_driver openhwgroup_openpiton = {
+	.match_table = openhwgroup_openpiton_match,
+	.init = openhwgroup_openpiton_platform_init,
 };
-- 
2.34.1



From maherme.dev at gmail.com  Wed Aug 13 03:47:59 2025
From: maherme.dev at gmail.com (=?UTF-8?q?Manuel=20Hern=C3=A1ndez=20M=C3=A9ndez?=)
Date: Wed, 13 Aug 2025 12:47:59 +0200
Subject: [PATCH v2] platform: openpiton: Move openpiton platform from fpga to generic
In-Reply-To: <42fb18cc-d579-490f-b7db-89cb8d228ee8@sifive.com>
References: <42fb18cc-d579-490f-b7db-89cb8d228ee8@sifive.com>
Message-ID: <20250813104759.33276-1-maherme.dev@gmail.com>

The OpenPiton framework has a generic PMU that is not used by OpenSBI.
Due to OpenSBI?s build system we cannot directly reuse the generic
platform functions, so move the OpenPiton platform to generic. Also due
to the generic platform is where new features are added.

Signed-off-by: Manuel Hern?ndez M?ndez <maherme.dev at gmail.com>
---
 platform/fpga/openpiton/Kconfig               | 10 -----
 platform/fpga/openpiton/configs/defconfig     |  0
 platform/fpga/openpiton/objects.mk            | 41 ------------------
 platform/generic/Kconfig                      |  4 ++
 platform/generic/configs/defconfig            |  1 +
 platform/generic/openhwgroup/objects.mk       |  8 ++++
 .../openhwgroup/openpiton.c}                  | 43 ++++++++-----------
 7 files changed, 31 insertions(+), 76 deletions(-)
 delete mode 100644 platform/fpga/openpiton/Kconfig
 delete mode 100644 platform/fpga/openpiton/configs/defconfig
 delete mode 100644 platform/fpga/openpiton/objects.mk
 create mode 100644 platform/generic/openhwgroup/objects.mk
 rename platform/{fpga/openpiton/platform.c => generic/openhwgroup/openpiton.c} (82%)

diff --git a/platform/fpga/openpiton/Kconfig b/platform/fpga/openpiton/Kconfig
deleted file mode 100644
index bc9c86ee..00000000
--- a/platform/fpga/openpiton/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: BSD-2-Clause
-
-config PLATFORM_OPENPITON_FPGA
-	bool
-	select FDT
-	select IPI_MSWI
-	select IRQCHIP_PLIC
-	select SERIAL_UART8250
-	select TIMER_MTIMER
-	default y
diff --git a/platform/fpga/openpiton/configs/defconfig b/platform/fpga/openpiton/configs/defconfig
deleted file mode 100644
index e69de29b..00000000
diff --git a/platform/fpga/openpiton/objects.mk b/platform/fpga/openpiton/objects.mk
deleted file mode 100644
index 1a0ce0c7..00000000
--- a/platform/fpga/openpiton/objects.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# SPDX-License-Identifier: BSD-2-Clause
-#
-# Copyright (c) 2020 Western Digital Corporation or its affiliates.
-#
-
-# Compiler flags
-platform-cppflags-y =
-platform-cflags-y =
-platform-asflags-y =
-platform-ldflags-y =
-
-# Objects to build
-platform-objs-y += platform.o
-
-PLATFORM_RISCV_XLEN = 64
-
-# Blobs to build
-FW_JUMP=n
-
-ifeq ($(PLATFORM_RISCV_XLEN), 32)
- # This needs to be 4MB aligned for 32-bit support
- FW_JUMP_ADDR=0x80400000
- else
- # This needs to be 2MB aligned for 64-bit support
- FW_JUMP_ADDR=0x80200000
- endif
-FW_JUMP_FDT_ADDR=0x82200000
-
-# Firmware with payload configuration.
-FW_PAYLOAD=y
-
-ifeq ($(PLATFORM_RISCV_XLEN), 32)
-# This needs to be 4MB aligned for 32-bit support
-  FW_PAYLOAD_OFFSET=0x400000
-else
-# This needs to be 2MB aligned for 64-bit support
-  FW_PAYLOAD_OFFSET=0x200000
-endif
-FW_PAYLOAD_FDT_ADDR=0x82200000
-FW_PAYLOAD_ALIGN=0x1000
diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
index a24d6ab2..7559a4bd 100644
--- a/platform/generic/Kconfig
+++ b/platform/generic/Kconfig
@@ -36,6 +36,10 @@ config PLATFORM_ANDES_AE350
 	select ANDES_PMA
 	default n
 
+config PLATFORM_OPENHWGROUP_OPENPITON
+	bool "OpenHWGroup Openpiton support"
+	default n
+
 config PLATFORM_RENESAS_RZFIVE
 	bool "Renesas RZ/Five support"
 	select ANDES_PMA
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index c7a6531e..4b93d0bc 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -7,6 +7,7 @@ CONFIG_PLATFORM_SOPHGO_SG2042=y
 CONFIG_PLATFORM_STARFIVE_JH7110=y
 CONFIG_PLATFORM_THEAD=y
 CONFIG_PLATFORM_MIPS_P8700=y
+CONFIG_PLATFORM_OPENHWGROUP_OPENPITON=y
 CONFIG_FDT_CPPC=y
 CONFIG_FDT_CPPC_RPMI=y
 CONFIG_FDT_GPIO=y
diff --git a/platform/generic/openhwgroup/objects.mk b/platform/generic/openhwgroup/objects.mk
new file mode 100644
index 00000000..ab6ca79d
--- /dev/null
+++ b/platform/generic/openhwgroup/objects.mk
@@ -0,0 +1,8 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Western Digital Corporation or its affiliates.
+#
+
+carray-platform_override_modules-$(CONFIG_PLATFORM_OPENHWGROUP_OPENPITON) += openhwgroup_openpiton
+platform-objs-$(CONFIG_PLATFORM_OPENHWGROUP_OPENPITON) += openhwgroup/openpiton.o
diff --git a/platform/fpga/openpiton/platform.c b/platform/generic/openhwgroup/openpiton.c
similarity index 82%
rename from platform/fpga/openpiton/platform.c
rename to platform/generic/openhwgroup/openpiton.c
index faa299ce..94567abb 100644
--- a/platform/fpga/openpiton/platform.c
+++ b/platform/generic/openhwgroup/openpiton.c
@@ -3,12 +3,7 @@
  * Copyright (c) 2020 Western Digital Corporation or its affiliates.
  */
 
-#include <sbi/riscv_asm.h>
-#include <sbi/riscv_encoding.h>
-#include <sbi/riscv_io.h>
-#include <sbi/sbi_const.h>
-#include <sbi/sbi_hart.h>
-#include <sbi/sbi_platform.h>
+#include <platform_override.h>
 #include <sbi_utils/fdt/fdt_helper.h>
 #include <sbi_utils/fdt/fdt_fixup.h>
 #include <sbi_utils/ipi/aclint_mswi.h>
@@ -156,25 +151,23 @@ static int openpiton_timer_init(void)
 	return aclint_mtimer_cold_init(&mtimer, NULL);
 }
 
-/*
- * Platform descriptor.
- */
-const struct sbi_platform_operations platform_ops = {
-	.early_init = openpiton_early_init,
-	.final_init = openpiton_final_init,
-	.irqchip_init = openpiton_irqchip_init,
-	.ipi_init = openpiton_ipi_init,
-	.timer_init = openpiton_timer_init,
+static int openhwgroup_openpiton_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match)
+{
+	generic_platform_ops.early_init = openpiton_early_init;
+	generic_platform_ops.timer_init = openpiton_timer_init;
+	generic_platform_ops.ipi_init = openpiton_ipi_init;
+	generic_platform_ops.irqchip_init = openpiton_irqchip_init;
+	generic_platform_ops.final_init = openpiton_final_init;
+
+	return 0;
+}
+
+static const struct fdt_match openhwgroup_openpiton_match[] = {
+	{ .compatible = "openpiton,cva6platform" },
+	{ },
 };
 
-const struct sbi_platform platform = {
-	.opensbi_version = OPENSBI_VERSION,
-	.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
-	.name = "OPENPITON RISC-V",
-	.features = SBI_PLATFORM_DEFAULT_FEATURES,
-	.hart_count = OPENPITON_DEFAULT_HART_COUNT,
-	.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
-	.heap_size =
-		SBI_PLATFORM_DEFAULT_HEAP_SIZE(OPENPITON_DEFAULT_HART_COUNT),
-	.platform_ops_addr = (unsigned long)&platform_ops
+const struct fdt_driver openhwgroup_openpiton = {
+	.match_table = openhwgroup_openpiton_match,
+	.init = openhwgroup_openpiton_platform_init,
 };
-- 
2.34.1



From ben717 at andestech.com  Thu Aug 14 03:40:24 2025
From: ben717 at andestech.com (Ben Zong-You Xie)
Date: Thu, 14 Aug 2025 18:40:24 +0800
Subject: [PATCH] platform: generic: andes: add QiLai SoC
Message-ID: <20250814104024.3374698-1-ben717@andestech.com>

Extend generic platform to support Andes QiLai SoC

Signed-off-by: Ben Zong-You Xie <ben717 at andestech.com>
---
 platform/generic/Kconfig                   |  7 +++
 platform/generic/andes/objects.mk          |  2 +
 platform/generic/andes/qilai.c             | 66 ++++++++++++++++++++++
 platform/generic/configs/defconfig         |  1 +
 platform/generic/include/andes/andes_pma.h |  1 +
 platform/generic/include/andes/qilai.h     | 18 ++++++
 6 files changed, 95 insertions(+)
 create mode 100644 platform/generic/andes/qilai.c
 create mode 100644 platform/generic/include/andes/qilai.h

diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
index a24d6ab2fe46..e1d6be563aa7 100644
--- a/platform/generic/Kconfig
+++ b/platform/generic/Kconfig
@@ -36,6 +36,13 @@ config PLATFORM_ANDES_AE350
 	select ANDES_PMA
 	default n
 
+config PLATFORM_ANDES_QILAI
+	bool "Andes QiLai support"
+	select ANDES_PMU
+	select ANDES_PMA
+	select ANDES_SBI
+	default n
+
 config PLATFORM_RENESAS_RZFIVE
 	bool "Renesas RZ/Five support"
 	select ANDES_PMA
diff --git a/platform/generic/andes/objects.mk b/platform/generic/andes/objects.mk
index 15e618529c44..132e20f2f16f 100644
--- a/platform/generic/andes/objects.mk
+++ b/platform/generic/andes/objects.mk
@@ -3,7 +3,9 @@
 #
 
 carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_AE350) += andes_ae350
+carray-platform_override_modules-$(CONFIG_PLATFORM_ANDES_QILAI) += andes_qilai
 platform-objs-$(CONFIG_PLATFORM_ANDES_AE350) += andes/ae350.o andes/sleep.o
+platform-objs-$(CONFIG_PLATFORM_ANDES_QILAI) += andes/qilai.o
 
 platform-objs-$(CONFIG_ANDES_PMA) += andes/andes_pma.o
 platform-objs-$(CONFIG_ANDES_SBI) += andes/andes_sbi.o
diff --git a/platform/generic/andes/qilai.c b/platform/generic/andes/qilai.c
new file mode 100644
index 000000000000..a73ba993215e
--- /dev/null
+++ b/platform/generic/andes/qilai.c
@@ -0,0 +1,66 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Andes Technology Corporation
+ *
+ */
+
+#include <andes/andes_pma.h>
+#include <andes/andes_pmu.h>
+#include <andes/andes_sbi.h>
+#include <andes/qilai.h>
+#include <platform_override.h>
+#include <sbi/sbi_domain.h>
+#include <sbi_utils/fdt/fdt_driver.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+
+static int andes_qilai_final_init(bool cold_boot)
+{
+
+	int rc;
+
+	/*
+	 * Set the memory attribute for 3 PCIE endpoint regions,
+	 * and they are all non-idempotent and non-bufferable.
+	 */
+	rc = andes_sbi_set_pma(PCIE0_BASE, PCIE0_SIZE,
+			       ANDES_PMACFG_ETYP_NAPOT |
+			       ANDES_PMACFG_MTYP_DEV_NOBUF);
+	if (rc)
+		return rc;
+
+	rc = andes_sbi_set_pma(PCIE1_BASE, PCIE1_SIZE,
+			       ANDES_PMACFG_ETYP_NAPOT |
+			       ANDES_PMACFG_MTYP_DEV_NOBUF);
+	if (rc)
+		return rc;
+
+	rc = andes_sbi_set_pma(PCIE2_BASE, PCIE2_SIZE,
+			       ANDES_PMACFG_ETYP_NAPOT |
+			       ANDES_PMACFG_MTYP_DEV_NOBUF);
+	if (rc)
+		return rc;
+
+	return generic_final_init(cold_boot);
+}
+
+static int andes_qilai_platform_init(const void *fdt, int nodeoff,
+				     const struct fdt_match *match)
+{
+	generic_platform_ops.final_init	     = andes_qilai_final_init;
+	generic_platform_ops.extensions_init = andes_pmu_extensions_init;
+	generic_platform_ops.pmu_init	     = andes_pmu_init;
+	generic_platform_ops.vendor_ext_provider =
+		andes_sbi_vendor_ext_provider;
+	return 0;
+}
+
+static const struct fdt_match andes_qilai_match[] = {
+	{ .compatible = "andestech,qilai" },
+	{},
+};
+
+const struct fdt_driver andes_qilai = {
+	.match_table = andes_qilai_match,
+	.init	     = andes_qilai_platform_init,
+};
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index c7a6531e04bc..fc09edef8238 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -1,5 +1,6 @@
 CONFIG_PLATFORM_ALLWINNER_D1=y
 CONFIG_PLATFORM_ANDES_AE350=y
+CONFIG_PLATFORM_ANDES_QILAI=y
 CONFIG_PLATFORM_RENESAS_RZFIVE=y
 CONFIG_PLATFORM_SIFIVE_FU540=y
 CONFIG_PLATFORM_SIFIVE_FU740=y
diff --git a/platform/generic/include/andes/andes_pma.h b/platform/generic/include/andes/andes_pma.h
index be6149640c04..5b0ed0acfda8 100644
--- a/platform/generic/include/andes/andes_pma.h
+++ b/platform/generic/include/andes/andes_pma.h
@@ -19,6 +19,7 @@
 #define ANDES_PMACFG_ETYP_NAPOT			(3 << ANDES_PMACFG_ETYP_OFFSET)
 
 #define ANDES_PMACFG_MTYP_OFFSET		2
+#define ANDES_PMACFG_MTYP_DEV_NOBUF		(0 << ANDES_PMACFG_MTYP_OFFSET)
 /* Memory, Non-cacheable, Bufferable */
 #define ANDES_PMACFG_MTYP_MEM_NON_CACHE_BUF	(3 << ANDES_PMACFG_MTYP_OFFSET)
 
diff --git a/platform/generic/include/andes/qilai.h b/platform/generic/include/andes/qilai.h
new file mode 100644
index 000000000000..dfb0477fcb66
--- /dev/null
+++ b/platform/generic/include/andes/qilai.h
@@ -0,0 +1,18 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Andes Technology Corporation
+ *
+ */
+
+#ifndef __QILAI_H__
+#define __QILAI_H__
+
+#define PCIE0_BASE 0x1000000000
+#define PCIE0_SIZE 0x800000000
+#define PCIE1_BASE 0x1800000000
+#define PCIE1_SIZE 0x800000000
+#define PCIE2_BASE 0x2000000000
+#define PCIE2_SIZE 0x2000000000
+
+#endif
-- 
2.34.1



From peter.lin at sifive.com  Thu Aug 14 04:05:14 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Thu, 14 Aug 2025 19:05:14 +0800
Subject: [PATCH 0/8] SmePMP bugfixes and improvement
Message-ID: <20250814110522.18809-1-peter.lin@sifive.com>

This series improves SmePMP related functions and fixes
the access fault during domain context switch when SmePMP
is enabled.

Yu-Chien Peter Lin (8):
  lib: sbi_hart: move sbi_hart_get_smepmp_flags() to sbi_domain
  lib: sbi_domain: allow specifying inaccessible region
  lib: sbi_domain: print unsupported SmePMP permissions
  lib: sbi_hart: add error message for insufficient PMP entries
  lib: sbi_domain_context: skip the reserved entry during domain context
    switch
  lib: sbi_domain: add SBI_DOMAIN_MEMREGION_FW memregion flag
  lib: sbi_domain: ensure consistent firmware PMP entries
  lib: sbi_domain_context: preserve firmware PMP entries during domain
    context switch

 include/sbi/sbi_domain.h     | 11 ++++
 lib/sbi/sbi_domain.c         | 99 +++++++++++++++++++++++++++++++++++-
 lib/sbi/sbi_domain_context.c | 48 +++++++++++++++++
 lib/sbi/sbi_hart.c           | 86 +++++--------------------------
 4 files changed, 170 insertions(+), 74 deletions(-)

-- 
2.39.3



From peter.lin at sifive.com  Thu Aug 14 04:05:15 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Thu, 14 Aug 2025 19:05:15 +0800
Subject: [PATCH 1/8] lib: sbi_hart: move sbi_hart_get_smepmp_flags() to sbi_domain
In-Reply-To: <20250814110522.18809-1-peter.lin@sifive.com>
References: <20250814110522.18809-1-peter.lin@sifive.com>
Message-ID: <20250814110522.18809-2-peter.lin@sifive.com>

Move sbi_hart_get_smepmp_flags() from sbi_hart.c to sbi_domain.c and
rename it to sbi_domain_get_smepmp_flags() to better reflect its
purpose of converting domain memory region flags to PMP configuration.

The function's original parameters (scratch and dom) were unused, so
this refactoring also makes the function cleaner.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 include/sbi/sbi_domain.h |  7 +++++
 lib/sbi/sbi_domain.c     | 58 ++++++++++++++++++++++++++++++++++
 lib/sbi/sbi_hart.c       | 67 ++--------------------------------------
 3 files changed, 67 insertions(+), 65 deletions(-)

diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
index e9cff0b1..8a51f289 100644
--- a/include/sbi/sbi_domain.h
+++ b/include/sbi/sbi_domain.h
@@ -249,6 +249,13 @@ void sbi_domain_memregion_init(unsigned long addr,
 				unsigned long flags,
 				struct sbi_domain_memregion *reg);
 
+/*
+ * Returns Smepmp pmpcfg.LRWX encoding for a given region flag.
+ *
+ * @param reg pointer to memory region with flags encoded with permissions
+ */
+unsigned int sbi_domain_get_smepmp_flags(struct sbi_domain_memregion *reg);
+
 /**
  * Check whether we can access specified address for given mode and
  * memory region flags under a domain
diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index 461c7e53..1fa56b6a 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -122,6 +122,64 @@ void sbi_domain_memregion_init(unsigned long addr,
 	}
 }
 
+unsigned int sbi_domain_get_smepmp_flags(struct sbi_domain_memregion *reg)
+{
+	unsigned int pmp_flags = 0;
+
+	if (SBI_DOMAIN_MEMREGION_IS_SHARED(reg->flags)) {
+		/* Read only for both M and SU modes */
+		if (SBI_DOMAIN_MEMREGION_IS_SUR_MR(reg->flags))
+			pmp_flags = (PMP_L | PMP_R | PMP_W | PMP_X);
+
+		/* Execute for SU but Read/Execute for M mode */
+		else if (SBI_DOMAIN_MEMREGION_IS_SUX_MRX(reg->flags))
+			/* locked region */
+			pmp_flags = (PMP_L | PMP_W | PMP_X);
+
+		/* Execute only for both M and SU modes */
+		else if (SBI_DOMAIN_MEMREGION_IS_SUX_MX(reg->flags))
+			pmp_flags = (PMP_L | PMP_W);
+
+		/* Read/Write for both M and SU modes */
+		else if (SBI_DOMAIN_MEMREGION_IS_SURW_MRW(reg->flags))
+			pmp_flags = (PMP_W | PMP_X);
+
+		/* Read only for SU mode but Read/Write for M mode */
+		else if (SBI_DOMAIN_MEMREGION_IS_SUR_MRW(reg->flags))
+			pmp_flags = (PMP_W);
+	} else if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
+		/*
+		 * When smepmp is supported and used, M region cannot have RWX
+		 * permissions on any region.
+		 */
+		if ((reg->flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK)
+		    == SBI_DOMAIN_MEMREGION_M_RWX) {
+			sbi_printf("%s: M-mode only regions cannot have"
+				   "RWX permissions\n", __func__);
+			return 0;
+		}
+
+		/* M-mode only access regions are always locked */
+		pmp_flags |= PMP_L;
+
+		if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
+			pmp_flags |= PMP_R;
+		if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
+			pmp_flags |= PMP_W;
+		if (reg->flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
+			pmp_flags |= PMP_X;
+	} else if (SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(reg->flags)) {
+		if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
+			pmp_flags |= PMP_R;
+		if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
+			pmp_flags |= PMP_W;
+		if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
+			pmp_flags |= PMP_X;
+	}
+
+	return pmp_flags;
+}
+
 bool sbi_domain_check_addr(const struct sbi_domain *dom,
 			   unsigned long addr, unsigned long mode,
 			   unsigned long access_flags)
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 6a2d7d6f..c5c3ecb4 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -301,69 +301,6 @@ unsigned int sbi_hart_mhpm_bits(struct sbi_scratch *scratch)
 	return hfeatures->mhpm_bits;
 }
 
-/*
- * Returns Smepmp flags for a given domain and region based on permissions.
- */
-static unsigned int sbi_hart_get_smepmp_flags(struct sbi_scratch *scratch,
-					      struct sbi_domain *dom,
-					      struct sbi_domain_memregion *reg)
-{
-	unsigned int pmp_flags = 0;
-
-	if (SBI_DOMAIN_MEMREGION_IS_SHARED(reg->flags)) {
-		/* Read only for both M and SU modes */
-		if (SBI_DOMAIN_MEMREGION_IS_SUR_MR(reg->flags))
-			pmp_flags = (PMP_L | PMP_R | PMP_W | PMP_X);
-
-		/* Execute for SU but Read/Execute for M mode */
-		else if (SBI_DOMAIN_MEMREGION_IS_SUX_MRX(reg->flags))
-			/* locked region */
-			pmp_flags = (PMP_L | PMP_W | PMP_X);
-
-		/* Execute only for both M and SU modes */
-		else if (SBI_DOMAIN_MEMREGION_IS_SUX_MX(reg->flags))
-			pmp_flags = (PMP_L | PMP_W);
-
-		/* Read/Write for both M and SU modes */
-		else if (SBI_DOMAIN_MEMREGION_IS_SURW_MRW(reg->flags))
-			pmp_flags = (PMP_W | PMP_X);
-
-		/* Read only for SU mode but Read/Write for M mode */
-		else if (SBI_DOMAIN_MEMREGION_IS_SUR_MRW(reg->flags))
-			pmp_flags = (PMP_W);
-	} else if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
-		/*
-		 * When smepmp is supported and used, M region cannot have RWX
-		 * permissions on any region.
-		 */
-		if ((reg->flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK)
-		    == SBI_DOMAIN_MEMREGION_M_RWX) {
-			sbi_printf("%s: M-mode only regions cannot have"
-				   "RWX permissions\n", __func__);
-			return 0;
-		}
-
-		/* M-mode only access regions are always locked */
-		pmp_flags |= PMP_L;
-
-		if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
-			pmp_flags |= PMP_R;
-		if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
-			pmp_flags |= PMP_W;
-		if (reg->flags & SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
-			pmp_flags |= PMP_X;
-	} else if (SBI_DOMAIN_MEMREGION_SU_ONLY_ACCESS(reg->flags)) {
-		if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE)
-			pmp_flags |= PMP_R;
-		if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE)
-			pmp_flags |= PMP_W;
-		if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
-			pmp_flags |= PMP_X;
-	}
-
-	return pmp_flags;
-}
-
 static void sbi_hart_smepmp_set(struct sbi_scratch *scratch,
 				struct sbi_domain *dom,
 				struct sbi_domain_memregion *reg,
@@ -420,7 +357,7 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
 			continue;
 		}
 
-		pmp_flags = sbi_hart_get_smepmp_flags(scratch, dom, reg);
+		pmp_flags = sbi_domain_get_smepmp_flags(reg);
 		if (!pmp_flags)
 			return 0;
 
@@ -446,7 +383,7 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
 			continue;
 		}
 
-		pmp_flags = sbi_hart_get_smepmp_flags(scratch, dom, reg);
+		pmp_flags = sbi_domain_get_smepmp_flags(reg);
 		if (!pmp_flags)
 			return 0;
 
-- 
2.39.3



From peter.lin at sifive.com  Thu Aug 14 04:05:16 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Thu, 14 Aug 2025 19:05:16 +0800
Subject: [PATCH 2/8] lib: sbi_domain: allow specifying inaccessible region
In-Reply-To: <20250814110522.18809-1-peter.lin@sifive.com>
References: <20250814110522.18809-1-peter.lin@sifive.com>
Message-ID: <20250814110522.18809-3-peter.lin@sifive.com>

According to the RISC?V Privileged Specification, SmePMP
regions that grant no access in any privilege mode are
valid. Allow such regions to be specified.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 lib/sbi/sbi_domain.c | 13 ++++++++++++-
 lib/sbi/sbi_hart.c   |  4 ----
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index 1fa56b6a..e8adf66f 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -126,7 +126,18 @@ unsigned int sbi_domain_get_smepmp_flags(struct sbi_domain_memregion *reg)
 {
 	unsigned int pmp_flags = 0;
 
-	if (SBI_DOMAIN_MEMREGION_IS_SHARED(reg->flags)) {
+	if ((reg->flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == 0) {
+		/*
+		 * Inaccessible region for any modes
+		 *
+		 * Note that SmePMP configuration allows two settings
+		 * for such region:
+		 * - pmpcfg.LRWX = 0000 (Inaccessible region)
+		 * - pmpcfg.LRWX = 1000 (Locked inaccessible region)
+		 * Here we use the first one.
+		 */
+		return 0;
+	} else if (SBI_DOMAIN_MEMREGION_IS_SHARED(reg->flags)) {
 		/* Read only for both M and SU modes */
 		if (SBI_DOMAIN_MEMREGION_IS_SUR_MR(reg->flags))
 			pmp_flags = (PMP_L | PMP_R | PMP_W | PMP_X);
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index c5c3ecb4..eab27f48 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -358,8 +358,6 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
 		}
 
 		pmp_flags = sbi_domain_get_smepmp_flags(reg);
-		if (!pmp_flags)
-			return 0;
 
 		sbi_hart_smepmp_set(scratch, dom, reg, pmp_idx++, pmp_flags,
 				    pmp_log2gran, pmp_addr_max);
@@ -384,8 +382,6 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
 		}
 
 		pmp_flags = sbi_domain_get_smepmp_flags(reg);
-		if (!pmp_flags)
-			return 0;
 
 		sbi_hart_smepmp_set(scratch, dom, reg, pmp_idx++, pmp_flags,
 				    pmp_log2gran, pmp_addr_max);
-- 
2.39.3



From peter.lin at sifive.com  Thu Aug 14 04:05:17 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Thu, 14 Aug 2025 19:05:17 +0800
Subject: [PATCH 3/8] lib: sbi_domain: print unsupported SmePMP permissions
In-Reply-To: <20250814110522.18809-1-peter.lin@sifive.com>
References: <20250814110522.18809-1-peter.lin@sifive.com>
Message-ID: <20250814110522.18809-4-peter.lin@sifive.com>

The reg->flag is encoded with 6 bits to specify RWX
permissions for M-mode and S-/U-mode. However, only 16
of the possible encodings are valid on SmePMP.

Previously, specifying an unsupported encoding could fail
silently. Add a warning log when an unsupported permission
encoding is detected, improving visibility for debugging.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 lib/sbi/sbi_domain.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index e8adf66f..d6566b12 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -125,6 +125,7 @@ void sbi_domain_memregion_init(unsigned long addr,
 unsigned int sbi_domain_get_smepmp_flags(struct sbi_domain_memregion *reg)
 {
 	unsigned int pmp_flags = 0;
+	unsigned long rstart, rend;
 
 	if ((reg->flags & SBI_DOMAIN_MEMREGION_ACCESS_MASK) == 0) {
 		/*
@@ -186,6 +187,13 @@ unsigned int sbi_domain_get_smepmp_flags(struct sbi_domain_memregion *reg)
 			pmp_flags |= PMP_W;
 		if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE)
 			pmp_flags |= PMP_X;
+	} else {
+		rstart = reg->base;
+		rend = (reg->order < __riscv_xlen) ?
+			rstart + ((1UL << reg->order) - 1) : -1UL;
+		sbi_printf("%s: Unsupported Smepmp permissions "
+			   "on region 0x%" PRILX "-0x%" PRILX "\n",
+			   __func__, rstart, rend);
 	}
 
 	return pmp_flags;
-- 
2.39.3



From peter.lin at sifive.com  Thu Aug 14 04:05:18 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Thu, 14 Aug 2025 19:05:18 +0800
Subject: [PATCH 4/8] lib: sbi_hart: add error message for insufficient PMP entries
In-Reply-To: <20250814110522.18809-1-peter.lin@sifive.com>
References: <20250814110522.18809-1-peter.lin@sifive.com>
Message-ID: <20250814110522.18809-5-peter.lin@sifive.com>

Report PMP configuration errors when available PMP entries are
insufficient to adequately protect the system, at least the
security vulnerabilities becomes visible at boot-time.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 lib/sbi/sbi_hart.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index eab27f48..f4932909 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -348,8 +348,11 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
 		/* Skip reserved entry */
 		if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
 			pmp_idx++;
-		if (pmp_count <= pmp_idx)
+		if (pmp_count <= pmp_idx) {
+			sbi_printf("%s: ERR: region %#lx cannot be protected - "
+				   "insufficient PMP entries\n", __func__, reg->base);
 			break;
+		}
 
 		/* Skip shared and SU-only regions */
 		if (!SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
@@ -372,8 +375,11 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
 		/* Skip reserved entry */
 		if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
 			pmp_idx++;
-		if (pmp_count <= pmp_idx)
+		if (pmp_count <= pmp_idx) {
+			sbi_printf("%s: ERR: region %#lx cannot be protected - "
+				   "insufficient PMP entries\n", __func__, reg->base);
 			break;
+		}
 
 		/* Skip M-only regions */
 		if (SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(reg->flags)) {
@@ -407,8 +413,11 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
 	unsigned long pmp_addr;
 
 	sbi_domain_for_each_memregion(dom, reg) {
-		if (pmp_count <= pmp_idx)
+		if (pmp_count <= pmp_idx) {
+			sbi_printf("%s: ERR: region %#lx cannot be protected - "
+				   "insufficient PMP entries\n", __func__, reg->base);
 			break;
+		}
 
 		pmp_flags = 0;
 
-- 
2.39.3



From peter.lin at sifive.com  Thu Aug 14 04:05:19 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Thu, 14 Aug 2025 19:05:19 +0800
Subject: [PATCH 5/8] lib: sbi_domain_context: skip the reserved entry during domain context switch
In-Reply-To: <20250814110522.18809-1-peter.lin@sifive.com>
References: <20250814110522.18809-1-peter.lin@sifive.com>
Message-ID: <20250814110522.18809-6-peter.lin@sifive.com>

The reserved entry is activated to create shared region between M-mode
and S-mode, it should remain unchanged during domain context switch.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 lib/sbi/sbi_domain_context.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/sbi/sbi_domain_context.c b/lib/sbi/sbi_domain_context.c
index fb04d81d..1812c7c9 100644
--- a/lib/sbi/sbi_domain_context.c
+++ b/lib/sbi/sbi_domain_context.c
@@ -116,6 +116,11 @@ static void switch_to_next_domain_context(struct hart_context *ctx,
 
 	/* Reconfigure PMP settings for the new domain */
 	for (int i = 0; i < pmp_count; i++) {
+		/* Skip the reserved entry when SmePMP is enabled */
+		if (sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP) &&
+		    (i == SBI_SMEPMP_RESV_ENTRY)) {
+			continue;
+		}
 		sbi_platform_pmp_disable(sbi_platform_thishart_ptr(), i);
 		pmp_disable(i);
 	}
-- 
2.39.3



From peter.lin at sifive.com  Thu Aug 14 04:05:20 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Thu, 14 Aug 2025 19:05:20 +0800
Subject: [PATCH 6/8] lib: sbi_domain: add SBI_DOMAIN_MEMREGION_FW memregion flag
In-Reply-To: <20250814110522.18809-1-peter.lin@sifive.com>
References: <20250814110522.18809-1-peter.lin@sifive.com>
Message-ID: <20250814110522.18809-7-peter.lin@sifive.com>

Add a new memregion flag, SBI_DOMAIN_MEMREGION_FW and mark the
code and data sections of firmware.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 include/sbi/sbi_domain.h | 1 +
 lib/sbi/sbi_domain.c     | 8 ++++++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
index 8a51f289..d71354c7 100644
--- a/include/sbi/sbi_domain.h
+++ b/include/sbi/sbi_domain.h
@@ -157,6 +157,7 @@ struct sbi_domain_memregion {
 				 SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
 
 #define SBI_DOMAIN_MEMREGION_MMIO		(1UL << 31)
+#define SBI_DOMAIN_MEMREGION_FW			(1UL << 32)
 	unsigned long flags;
 };
 
diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index d6566b12..ccfcc7f0 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -541,6 +541,8 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
 		sbi_printf("M: ");
 		if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
 			sbi_printf("%cI", (k++) ? ',' : '(');
+		if (reg->flags & SBI_DOMAIN_MEMREGION_FW)
+			sbi_printf("%cF", (k++) ? ',' : '(');
 		if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
 			sbi_printf("%cR", (k++) ? ',' : '(');
 		if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
@@ -894,13 +896,15 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
 	/* Root domain firmware memory region */
 	sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
 				  (SBI_DOMAIN_MEMREGION_M_READABLE |
-				   SBI_DOMAIN_MEMREGION_M_EXECUTABLE),
+				   SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
+				   SBI_DOMAIN_MEMREGION_FW),
 				  &root_memregs[root_memregs_count++]);
 
 	sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset),
 				  (scratch->fw_size - scratch->fw_rw_offset),
 				  (SBI_DOMAIN_MEMREGION_M_READABLE |
-				   SBI_DOMAIN_MEMREGION_M_WRITABLE),
+				   SBI_DOMAIN_MEMREGION_M_WRITABLE |
+				   SBI_DOMAIN_MEMREGION_FW),
 				  &root_memregs[root_memregs_count++]);
 
 	root.fw_region_inited = true;
-- 
2.39.3



From peter.lin at sifive.com  Thu Aug 14 04:05:21 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Thu, 14 Aug 2025 19:05:21 +0800
Subject: [PATCH 7/8] lib: sbi_domain: ensure consistent firmware PMP entries
In-Reply-To: <20250814110522.18809-1-peter.lin@sifive.com>
References: <20250814110522.18809-1-peter.lin@sifive.com>
Message-ID: <20250814110522.18809-8-peter.lin@sifive.com>

Currently, during a domain context switch, all PMP entries ? including
those granting RW/RX permissions to firmware data and code are cleared
which will lead to access faults.

To configure firmware PMP entries deterministically across switches,
sort regions so that firmware regions come before others.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 include/sbi/sbi_domain.h |  3 +++
 lib/sbi/sbi_domain.c     | 14 ++++++++++++++
 2 files changed, 17 insertions(+)

diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
index d71354c7..31237401 100644
--- a/include/sbi/sbi_domain.h
+++ b/include/sbi/sbi_domain.h
@@ -121,6 +121,9 @@ struct sbi_domain_memregion {
 		((__flags & SBI_DOMAIN_MEMREGION_SU_ACCESS_MASK)  &&	\
 		 !(__flags & SBI_DOMAIN_MEMREGION_M_ACCESS_MASK))
 
+#define SBI_DOMAIN_MEMREGION_IS_FIRMWARE(__flags)			\
+		((__flags & SBI_DOMAIN_MEMREGION_FW) ? true : false)	\
+
 /** Bit to control if permissions are enforced on all modes */
 #define SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS	(1UL << 6)
 
diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
index ccfcc7f0..9e284f49 100644
--- a/lib/sbi/sbi_domain.c
+++ b/lib/sbi/sbi_domain.c
@@ -295,6 +295,20 @@ static bool is_region_compatible(const struct sbi_domain_memregion *regA,
 static bool is_region_before(const struct sbi_domain_memregion *regA,
 			     const struct sbi_domain_memregion *regB)
 {
+	/*
+	 * Firmware regions are placed before non?firmware
+	 * regions. This ensures firmware code/data remain
+	 * accessible when SmePMP is enabled. Optional for
+	 * regular PMP, but safe to follow consistently.
+	 */
+	if (SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regA->flags) &&
+	   !SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regB->flags))
+		return true;
+	if (!SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regA->flags) &&
+	    SBI_DOMAIN_MEMREGION_IS_FIRMWARE(regB->flags))
+		return false;
+
+
 	if (regA->order < regB->order)
 		return true;
 
-- 
2.39.3



From peter.lin at sifive.com  Thu Aug 14 04:05:22 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Thu, 14 Aug 2025 19:05:22 +0800
Subject: [PATCH 8/8] lib: sbi_domain_context: preserve firmware PMP entries during domain context switch
In-Reply-To: <20250814110522.18809-1-peter.lin@sifive.com>
References: <20250814110522.18809-1-peter.lin@sifive.com>
Message-ID: <20250814110522.18809-9-peter.lin@sifive.com>

When SmePMP is enabled, clearing firmware PMP entries during a domain
context switch can temporarily revoke access to OpenSBI?s own code and
data, leading to faults.

Keep firmware PMP entries enabled across switches so firmware regions
remain accessible and executable.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 lib/sbi/sbi_domain_context.c | 43 ++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/lib/sbi/sbi_domain_context.c b/lib/sbi/sbi_domain_context.c
index 1812c7c9..4ee50ac3 100644
--- a/lib/sbi/sbi_domain_context.c
+++ b/lib/sbi/sbi_domain_context.c
@@ -85,6 +85,45 @@ static void hart_context_set(struct sbi_domain *dom, u32 hartindex,
 	hart_context_get(sbi_domain_thishart_ptr(),			\
 			 current_hartindex())
 
+/**
+ * Determine whether a PMP entry protects firmware memory regions
+ *
+ * @param n PMP entry index
+ * @param dom current domain
+ */
+static bool pmp_is_fw_region(unsigned int n, struct sbi_domain *dom)
+{
+	struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+	unsigned int pmp_count = sbi_hart_pmp_count(scratch);
+	struct sbi_domain_memregion *reg;
+	unsigned long addr, log2len;
+	unsigned long prot, fw_flag;
+	int rc;
+
+	if (!dom || (n >= pmp_count))
+		return false;
+
+	/* Decode the pmpcfg and pmpaddr */
+	rc = pmp_get(n, &prot, &addr, &log2len);
+	if (rc)
+		return false;
+
+	sbi_domain_for_each_memregion(dom, reg) {
+		if ((reg->flags & SBI_DOMAIN_MEMREGION_FW) == 0)
+			continue;
+
+		/* Found a firmware region, assume it is always NAPOT mode */
+		fw_flag = sbi_domain_get_smepmp_flags(reg) | PMP_A_NAPOT;
+		if ((reg->base == addr) &&
+		    (reg->order == log2len) &&
+		    (fw_flag == prot)) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
 /**
  * Switches the HART context from the current domain to the target domain.
  * This includes changing domain assignments and reconfiguring PMP, as well
@@ -121,6 +160,10 @@ static void switch_to_next_domain_context(struct hart_context *ctx,
 		    (i == SBI_SMEPMP_RESV_ENTRY)) {
 			continue;
 		}
+
+		if (pmp_is_fw_region(i, current_dom))
+			continue;
+
 		sbi_platform_pmp_disable(sbi_platform_thishart_ptr(), i);
 		pmp_disable(i);
 	}
-- 
2.39.3



From peter.lin at sifive.com  Thu Aug 14 04:10:12 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Thu, 14 Aug 2025 19:10:12 +0800
Subject: [PATCH] lib: serial: sifive-uart: add shared memory region for SiFive UART
Message-ID: <20250814111012.20151-1-peter.lin@sifive.com>

Add shared memory region so the driver has permission
to access it in OpenSBI.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 lib/utils/serial/sifive-uart.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/utils/serial/sifive-uart.c b/lib/utils/serial/sifive-uart.c
index 3581d47a..55637137 100644
--- a/lib/utils/serial/sifive-uart.c
+++ b/lib/utils/serial/sifive-uart.c
@@ -9,6 +9,7 @@
 
 #include <sbi/riscv_io.h>
 #include <sbi/sbi_console.h>
+#include <sbi/sbi_domain.h>
 #include <sbi_utils/serial/sifive-uart.h>
 
 /* clang-format off */
@@ -111,5 +112,7 @@ int sifive_uart_init(unsigned long base, u32 in_freq, u32 baudrate)
 
 	sbi_console_set_device(&sifive_console);
 
-	return 0;
+	return sbi_domain_root_add_memrange(base, PAGE_SIZE, PAGE_SIZE,
+					    (SBI_DOMAIN_MEMREGION_MMIO |
+					    SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW));
 }
-- 
2.48.0



From alvinga at andestech.com  Thu Aug 14 08:39:19 2025
From: alvinga at andestech.com (=?big5?B?QWx2aW4gQ2hlLUNoaWEgQ2hhbmcosWmt9bnFKQ==?=)
Date: Thu, 14 Aug 2025 15:39:19 +0000
Subject: [PATCH 6/8] lib: sbi_domain: add SBI_DOMAIN_MEMREGION_FW
 memregion flag
In-Reply-To: <20250814110522.18809-7-peter.lin@sifive.com>
References: <20250814110522.18809-1-peter.lin@sifive.com>
 <20250814110522.18809-7-peter.lin@sifive.com>
Message-ID: <SEYPR03MB670099666C0DA844001E3F9BA835A@SEYPR03MB6700.apcprd03.prod.outlook.com>

Hi Peter,

> -----Original Message-----
> From: Yu-Chien Peter Lin <peter.lin at sifive.com>
> Sent: Thursday, August 14, 2025 7:05 PM
> To: opensbi at lists.infradead.org
> Cc: zong.li at sifive.com; greentime.hu at sifive.com; Alvin Che-Chia Chang(??
> ?) <alvinga at andestech.com>; Yu-Chien Peter Lin <peter.lin at sifive.com>
> Subject: [PATCH 6/8] lib: sbi_domain: add SBI_DOMAIN_MEMREGION_FW
> memregion flag
>
> [EXTERNAL MAIL]
>
> Add a new memregion flag, SBI_DOMAIN_MEMREGION_FW and mark the
> code and data sections of firmware.
>
> Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
> ---
>  include/sbi/sbi_domain.h | 1 +
>  lib/sbi/sbi_domain.c     | 8 ++++++--
>  2 files changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h index
> 8a51f289..d71354c7 100644
> --- a/include/sbi/sbi_domain.h
> +++ b/include/sbi/sbi_domain.h
> @@ -157,6 +157,7 @@ struct sbi_domain_memregion {
>
> SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
>
>  #define SBI_DOMAIN_MEMREGION_MMIO              (1UL << 31)
> +#define SBI_DOMAIN_MEMREGION_FW                        (1UL <<
> 32)

This exceeds "unsigned long" of RV32 which only has 32 bits.
Besides, why we need this new flag?
Isn't SBI_DOMAIN_MEMREGION_M_ONLY_ACCESS(__flags) enough?

>         unsigned long flags;
>  };
>
> diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c index
> d6566b12..ccfcc7f0 100644
> --- a/lib/sbi/sbi_domain.c
> +++ b/lib/sbi/sbi_domain.c
> @@ -541,6 +541,8 @@ void sbi_domain_dump(const struct sbi_domain *dom,
> const char *suffix)
>                 sbi_printf("M: ");
>                 if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
>                         sbi_printf("%cI", (k++) ? ',' : '(');
> +               if (reg->flags & SBI_DOMAIN_MEMREGION_FW)
> +                       sbi_printf("%cF", (k++) ? ',' : '(');
>                 if (reg->flags &
> SBI_DOMAIN_MEMREGION_M_READABLE)
>                         sbi_printf("%cR", (k++) ? ',' : '(');
>                 if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
> @@ -894,13 +896,15 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32
> cold_hartid)
>         /* Root domain firmware memory region */
>         sbi_domain_memregion_init(scratch->fw_start,
> scratch->fw_rw_offset,
>
> (SBI_DOMAIN_MEMREGION_M_READABLE |
> -
> SBI_DOMAIN_MEMREGION_M_EXECUTABLE),
> +
> SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
> +                                  SBI_DOMAIN_MEMREGION_FW),
>
> &root_memregs[root_memregs_count++]);
>
>         sbi_domain_memregion_init((scratch->fw_start +
> scratch->fw_rw_offset),
>                                   (scratch->fw_size -
> scratch->fw_rw_offset),
>
> (SBI_DOMAIN_MEMREGION_M_READABLE |
> -
> SBI_DOMAIN_MEMREGION_M_WRITABLE),
> +
> SBI_DOMAIN_MEMREGION_M_WRITABLE |
> +                                  SBI_DOMAIN_MEMREGION_FW),
>
> &root_memregs[root_memregs_count++]);
>
>         root.fw_region_inited = true;
> --
> 2.39.3

CONFIDENTIALITY NOTICE:

This e-mail (and its attachments) may contain confidential and legally privileged information or information protected from disclosure. If you are not the intended recipient, you are hereby notified that any disclosure, copying, distribution, or use of the information contained herein is strictly prohibited. In this case, please immediately notify the sender by return e-mail, delete the message (and any accompanying documents) and destroy all printed hard copies. Thank you for your cooperation.

Copyright ANDES TECHNOLOGY CORPORATION - All Rights Reserved.

From peter.lin at sifive.com  Thu Aug 14 19:44:34 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Fri, 15 Aug 2025 10:44:34 +0800
Subject: [PATCH] lib: utils: fdt_helper: simplify fdt_parse_isa_extensions() helper
Message-ID: <20250815024434.14303-1-peter.lin@sifive.com>

The fdt_isa_bitmap was previously used as a temporary array
to store ISA extensions when parsing device-tree.
To reduce scratch space consumption, set the ISA bitmap
directly in hfeature->extensions, allows us to remove the
fdt_parse_isa_all_harts() as fdt_parse_isa_extensions() can
now handle the task directly.

This change makes the helper function more versatile, even
before scratch space is initialized.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 include/sbi_utils/fdt/fdt_helper.h |  3 +-
 lib/utils/fdt/fdt_helper.c         | 45 ++----------------------------
 platform/generic/platform.c        |  2 +-
 3 files changed, 4 insertions(+), 46 deletions(-)

diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h
index 04c850cc..24ad1a94 100644
--- a/include/sbi_utils/fdt/fdt_helper.h
+++ b/include/sbi_utils/fdt/fdt_helper.h
@@ -54,8 +54,7 @@ int fdt_parse_cbom_block_size(const void *fdt, int cpu_offset, unsigned long  *c
 
 int fdt_parse_timebase_frequency(const void *fdt, unsigned long *freq);
 
-int fdt_parse_isa_extensions(const void *fdt, unsigned int hartid,
-			     unsigned long *extensions);
+int fdt_parse_isa_extensions(const void *fdt, unsigned long *hart_exts);
 
 int fdt_parse_gaisler_uart_node(const void *fdt, int nodeoffset,
 				struct platform_uart_data *uart);
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index 0f4859c1..61a5962c 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -324,8 +324,6 @@ int fdt_parse_timebase_frequency(const void *fdt, unsigned long *freq)
 
 #define RISCV_ISA_EXT_NAME_LEN_MAX	32
 
-static unsigned long fdt_isa_bitmap_offset;
-
 static int fdt_parse_isa_one_hart(const char *isa, unsigned long *extensions)
 {
 	size_t i, j, isa_len;
@@ -405,15 +403,13 @@ static void fdt_parse_isa_extensions_one_hart(const char *isa,
 	}
 }
 
-static int fdt_parse_isa_all_harts(const void *fdt)
+int fdt_parse_isa_extensions(const void *fdt, unsigned long *hart_exts)
 {
 	u32 hartid;
 	const fdt32_t *val;
-	unsigned long *hart_exts;
-	struct sbi_scratch *scratch;
 	int err, cpu_offset, cpus_offset, len;
 
-	if (!fdt || !fdt_isa_bitmap_offset)
+	if (!fdt || !hart_exts)
 		return SBI_EINVAL;
 
 	cpus_offset = fdt_path_offset(fdt, "/cpus");
@@ -428,13 +424,6 @@ static int fdt_parse_isa_all_harts(const void *fdt)
 		if (!fdt_node_is_enabled(fdt, cpu_offset))
 			continue;
 
-		scratch = sbi_hartid_to_scratch(hartid);
-		if (!scratch)
-			return SBI_ENOENT;
-
-		hart_exts = sbi_scratch_offset_ptr(scratch,
-						   fdt_isa_bitmap_offset);
-
 		val = fdt_getprop(fdt, cpu_offset, "riscv,isa-extensions", &len);
 		if (val && len > 0) {
 			fdt_parse_isa_extensions_one_hart((const char *)val,
@@ -454,36 +443,6 @@ static int fdt_parse_isa_all_harts(const void *fdt)
 	return 0;
 }
 
-int fdt_parse_isa_extensions(const void *fdt, unsigned int hartid,
-			unsigned long *extensions)
-{
-	int rc, i;
-	unsigned long *hart_exts;
-	struct sbi_scratch *scratch;
-
-	if (!fdt_isa_bitmap_offset) {
-		fdt_isa_bitmap_offset = sbi_scratch_alloc_offset(
-					sizeof(*hart_exts) *
-					BITS_TO_LONGS(SBI_HART_EXT_MAX));
-		if (!fdt_isa_bitmap_offset)
-			return SBI_ENOMEM;
-
-		rc = fdt_parse_isa_all_harts(fdt);
-		if (rc)
-			return rc;
-	}
-
-	scratch = sbi_hartid_to_scratch(hartid);
-	if (!scratch)
-		return SBI_ENOENT;
-
-	hart_exts = sbi_scratch_offset_ptr(scratch, fdt_isa_bitmap_offset);
-
-	for (i = 0; i < BITS_TO_LONGS(SBI_HART_EXT_MAX); i++)
-		extensions[i] |= hart_exts[i];
-	return 0;
-}
-
 static int fdt_parse_uart_node_common(const void *fdt, int nodeoffset,
 				      struct platform_uart_data *uart,
 				      unsigned long default_freq,
diff --git a/platform/generic/platform.c b/platform/generic/platform.c
index 47e771ad..2e8c6051 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -251,7 +251,7 @@ int generic_final_init(bool cold_boot)
 int generic_extensions_init(struct sbi_hart_features *hfeatures)
 {
 	/* Parse the ISA string from FDT and enable the listed extensions */
-	return fdt_parse_isa_extensions(fdt_get_address(), current_hartid(),
+	return fdt_parse_isa_extensions(fdt_get_address(),
 					hfeatures->extensions);
 }
 
-- 
2.48.0



From alvinga at andestech.com  Thu Aug 14 22:54:16 2025
From: alvinga at andestech.com (=?big5?B?QWx2aW4gQ2hlLUNoaWEgQ2hhbmcosWmt9bnFKQ==?=)
Date: Fri, 15 Aug 2025 05:54:16 +0000
Subject: [PATCH 5/8] lib: sbi_domain_context: skip the reserved entry
 during domain context switch
In-Reply-To: <20250814110522.18809-6-peter.lin@sifive.com>
References: <20250814110522.18809-1-peter.lin@sifive.com>
 <20250814110522.18809-6-peter.lin@sifive.com>
Message-ID: <SEYPR03MB670028ED423612A1F943DA92A834A@SEYPR03MB6700.apcprd03.prod.outlook.com>

Hi Peter,

> -----Original Message-----
> From: Yu-Chien Peter Lin <peter.lin at sifive.com>
> Sent: Thursday, August 14, 2025 7:05 PM
> To: opensbi at lists.infradead.org
> Cc: zong.li at sifive.com; greentime.hu at sifive.com; Alvin Che-Chia Chang(??
> ?) <alvinga at andestech.com>; Yu-Chien Peter Lin <peter.lin at sifive.com>
> Subject: [PATCH 5/8] lib: sbi_domain_context: skip the reserved entry during
> domain context switch
>
> [EXTERNAL MAIL]
>
> The reserved entry is activated to create shared region between M-mode and
> S-mode, it should remain unchanged during domain context switch.
>
> Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
> ---
>  lib/sbi/sbi_domain_context.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/lib/sbi/sbi_domain_context.c b/lib/sbi/sbi_domain_context.c index
> fb04d81d..1812c7c9 100644
> --- a/lib/sbi/sbi_domain_context.c
> +++ b/lib/sbi/sbi_domain_context.c
> @@ -116,6 +116,11 @@ static void switch_to_next_domain_context(struct
> hart_context *ctx,
>
>         /* Reconfigure PMP settings for the new domain */
>         for (int i = 0; i < pmp_count; i++) {
> +               /* Skip the reserved entry when SmePMP is enabled */
> +               if (sbi_hart_has_extension(scratch,
> SBI_HART_EXT_SMEPMP) &&
> +                   (i == SBI_SMEPMP_RESV_ENTRY)) {
> +                       continue;
> +               }

Is this reserved entry mapped(activated) during domain context switch ?
If my understanding is correct, the mapped reserved entry creates shared region between M-mode and "current supervisor domain".
Now we are performing domain context switch to "next supervisor domain which does not have permission to access that shared region".
In my opinion, this reserved entry should be disabled for security reason.

Maybe OpenSBI should "context-switch" the reserved entry?
If the reserved entry is mapped during the domain A, and system switches to domain B without unmapping the reserved entry.
Does this mean that OpenSBI cannot call sbi_hart_map_saddr() to map shared-region with domain B? Because the function will return SBI_ENOSPC in this case.


Best regards,
Alvin


>                 sbi_platform_pmp_disable(sbi_platform_thishart_ptr(), i);
>                 pmp_disable(i);
>         }
> --
> 2.39.3

CONFIDENTIALITY NOTICE:

This e-mail (and its attachments) may contain confidential and legally privileged information or information protected from disclosure. If you are not the intended recipient, you are hereby notified that any disclosure, copying, distribution, or use of the information contained herein is strictly prohibited. In this case, please immediately notify the sender by return e-mail, delete the message (and any accompanying documents) and destroy all printed hard copies. Thank you for your cooperation.

Copyright ANDES TECHNOLOGY CORPORATION - All Rights Reserved.

From peter.lin at sifive.com  Fri Aug 15 03:01:08 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Fri, 15 Aug 2025 18:01:08 +0800
Subject: [RFC PATCH 0/7] Extend the reserved PMP entries
Message-ID: <20250815100116.27776-1-peter.lin@sifive.com>

This series extends the number of reserved PMP entry.
The capabilities of the reserved PMP entries include:
- Highest priority
- Allow TOR mode for platform-specific use cases
- Can be consistent across domain context switches
- Allow runtime PMP allocation

A potential use case for reserved PMP entries is parsing gaps in
memory ports marked as PMA_UNSAFE [1] in device-tree. These gaps
may not be able to exactly covered by 1 or 2 NAPOT entries, so TOR
mode PMP can be allocated to save PMP usage. Besides, they don't
need reconfiguration across domains.

This series depends on:
1) https://lore.kernel.org/all/20250815024434.14303-1-peter.lin at sifive.com/
2) https://lore.kernel.org/all/20250814110522.18809-1-peter.lin at sifive.com/

[1] https://patchwork.kernel.org/project/linux-riscv/patch/20241102000843.1301099-2-samuel.holland at sifive.com/

Yu-Chien Peter Lin (7):
  lib: utils: fdt_helper: add fdt_has_isa_extension() helper
  include: sbi: sbi_platform: add reserved_pmp_count field
  platform: generic: platform: introduce
    fw_platform_get_reserved_pmp_count()
  lib: sbi_init: print total and reserved PMP counts
  lib: sbi: riscv_asm: add reserved_pmp_alloc() to allocate a reserved
    PMP
  lib: sbi: sbi_hart: extend PMP handling to support multiple reserved
    entries
  docs: opensbi_config: add description for reserved-pmp-count

 docs/opensbi_config.md             |  4 +++
 include/sbi/riscv_asm.h            |  2 ++
 include/sbi/sbi_hart.h             | 15 --------
 include/sbi/sbi_platform.h         | 15 +++++---
 include/sbi_utils/fdt/fdt_helper.h |  2 ++
 lib/sbi/riscv_asm.c                | 25 +++++++++++++
 lib/sbi/sbi_domain_context.c       |  6 +++-
 lib/sbi/sbi_hart.c                 | 56 ++++++++++++++++++++++--------
 lib/sbi/sbi_init.c                 |  6 ++--
 lib/utils/fdt/fdt_helper.c         | 35 +++++++++++++++++++
 platform/generic/platform.c        | 34 ++++++++++++++++++
 11 files changed, 163 insertions(+), 37 deletions(-)

-- 
2.48.0



From peter.lin at sifive.com  Fri Aug 15 03:01:09 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Fri, 15 Aug 2025 18:01:09 +0800
Subject: [RFC PATCH 1/7] lib: utils: fdt_helper: add fdt_has_isa_extension() helper
In-Reply-To: <20250815100116.27776-1-peter.lin@sifive.com>
References: <20250815100116.27776-1-peter.lin@sifive.com>
Message-ID: <20250815100116.27776-2-peter.lin@sifive.com>

Add a helper function to search for a given ISA string in
`riscv,isa-extensions` or `riscv,isa` properties within
the FDT.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 include/sbi_utils/fdt/fdt_helper.h |  2 ++
 lib/utils/fdt/fdt_helper.c         | 35 ++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h
index 24ad1a94..8aa216c7 100644
--- a/include/sbi_utils/fdt/fdt_helper.h
+++ b/include/sbi_utils/fdt/fdt_helper.h
@@ -56,6 +56,8 @@ int fdt_parse_timebase_frequency(const void *fdt, unsigned long *freq);
 
 int fdt_parse_isa_extensions(const void *fdt, unsigned long *hart_exts);
 
+bool fdt_has_isa_extension(const void *fdt, const char *ext);
+
 int fdt_parse_gaisler_uart_node(const void *fdt, int nodeoffset,
 				struct platform_uart_data *uart);
 
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index b0b18b1c..de72f34a 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -447,6 +447,41 @@ int fdt_parse_isa_extensions(const void *fdt, unsigned long *hart_exts)
 	return 0;
 }
 
+bool fdt_has_isa_extension(const void *fdt, const char *ext)
+{
+	const struct sbi_hart_ext_data *ext_data = NULL;
+	DECLARE_BITMAP(hart_exts, SBI_HART_EXT_MAX);
+	int rc, i;
+
+	if (!fdt || !ext)
+		return false;
+
+	for (i = 0; i < SBI_HART_EXT_MAX; i++) {
+		if (!sbi_strncmp(sbi_hart_ext[i].name, ext,
+	                         sbi_strlen(ext))) {
+			ext_data = &sbi_hart_ext[i];
+			break;
+		}
+	}
+
+	if (!ext_data) {
+		sbi_printf("%s: extension %s not found in sbi_hart_ext[]\n",
+			   __func__, ext);
+		return false;
+	}
+
+	bitmap_zero(hart_exts, SBI_HART_EXT_MAX);
+
+	rc = fdt_parse_isa_extensions(fdt, hart_exts);
+	if (rc) {
+		sbi_printf("%s: failed to parse isa extensions\n",
+			   __func__);
+		return false;
+	}
+
+	return bitmap_test(hart_exts, ext_data->id);
+}
+
 static int fdt_parse_uart_node_common(const void *fdt, int nodeoffset,
 				      struct platform_uart_data *uart,
 				      unsigned long default_freq,
-- 
2.48.0



From peter.lin at sifive.com  Fri Aug 15 03:01:10 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Fri, 15 Aug 2025 18:01:10 +0800
Subject: [RFC PATCH 2/7] include: sbi: sbi_platform: add reserved_pmp_count field
In-Reply-To: <20250815100116.27776-1-peter.lin@sifive.com>
References: <20250815100116.27776-1-peter.lin@sifive.com>
Message-ID: <20250815100116.27776-3-peter.lin@sifive.com>

Add reserved_pmp_count field to struct sbi_platform to specify the
configurable number of high-priority PMP entries reserved.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 include/sbi/sbi_platform.h | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
index c6d30080..e2bf9b77 100644
--- a/include/sbi/sbi_platform.h
+++ b/include/sbi/sbi_platform.h
@@ -31,16 +31,18 @@
 #define SBI_PLATFORM_HART_STACK_SIZE_OFFSET (0x54)
 /** Offset of heap_size in struct sbi_platform */
 #define SBI_PLATFORM_HEAP_SIZE_OFFSET (0x58)
+/** Offset of reserved PMP entry count in struct sbi_platform */
+#define SBI_PLATFORM_RESERVED_PMP_COUNT_OFFSET (0x5c)
 /** Offset of reserved in struct sbi_platform */
-#define SBI_PLATFORM_RESERVED_OFFSET (0x5c)
+#define SBI_PLATFORM_RESERVED_OFFSET (0x60)
 /** Offset of platform_ops_addr in struct sbi_platform */
-#define SBI_PLATFORM_OPS_OFFSET (0x60)
+#define SBI_PLATFORM_OPS_OFFSET (0x68)
 /** Offset of firmware_context in struct sbi_platform */
-#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x60 + __SIZEOF_POINTER__)
+#define SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET (0x68 + __SIZEOF_POINTER__)
 /** Offset of hart_index2id in struct sbi_platform */
-#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x60 + (__SIZEOF_POINTER__ * 2))
+#define SBI_PLATFORM_HART_INDEX2ID_OFFSET (0x68 + (__SIZEOF_POINTER__ * 2))
 /** Offset of cbom_block_size in struct sbi_platform */
-#define SBI_PLATFORM_CBOM_BLOCK_SIZE_OFFSET (0x60 + (__SIZEOF_POINTER__ * 3))
+#define SBI_PLATFORM_CBOM_BLOCK_SIZE_OFFSET (0x68 + (__SIZEOF_POINTER__ * 3))
 
 #define SBI_PLATFORM_TLB_RANGE_FLUSH_LIMIT_DEFAULT		(1UL << 12)
 
@@ -182,6 +184,8 @@ struct sbi_platform {
 	u32 hart_stack_size;
 	/** Size of heap shared by all HARTs */
 	u32 heap_size;
+	/** Reserved PMP entry count */
+	u8 reserved_pmp_count;
 	/** Reserved for future use */
 	u32 reserved;
 	/** Pointer to sbi platform operations */
@@ -214,6 +218,7 @@ assert_member_offset(struct sbi_platform, features, SBI_PLATFORM_FEATURES_OFFSET
 assert_member_offset(struct sbi_platform, hart_count, SBI_PLATFORM_HART_COUNT_OFFSET);
 assert_member_offset(struct sbi_platform, hart_stack_size, SBI_PLATFORM_HART_STACK_SIZE_OFFSET);
 assert_member_offset(struct sbi_platform, heap_size, SBI_PLATFORM_HEAP_SIZE_OFFSET);
+assert_member_offset(struct sbi_platform, reserved_pmp_count, SBI_PLATFORM_RESERVED_PMP_COUNT_OFFSET);
 assert_member_offset(struct sbi_platform, reserved, SBI_PLATFORM_RESERVED_OFFSET);
 assert_member_offset(struct sbi_platform, platform_ops_addr, SBI_PLATFORM_OPS_OFFSET);
 assert_member_offset(struct sbi_platform, firmware_context, SBI_PLATFORM_FIRMWARE_CONTEXT_OFFSET);
-- 
2.48.0



From peter.lin at sifive.com  Fri Aug 15 03:01:11 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Fri, 15 Aug 2025 18:01:11 +0800
Subject: [RFC PATCH 3/7] platform: generic: platform: introduce fw_platform_get_reserved_pmp_count()
In-Reply-To: <20250815100116.27776-1-peter.lin@sifive.com>
References: <20250815100116.27776-1-peter.lin@sifive.com>
Message-ID: <20250815100116.27776-4-peter.lin@sifive.com>

Introduce fw_platform_get_reserved_pmp_count() to parse the
`reserved-pmp-count` property from the opensbi-config node.

Since mseccfg.{RLB,MMWP,MML} are sticky bits, we can't poll them
to detect the presence of Smempp. Therefore, the only way is to
parse it from FDT `riscv,isa-extensions` or `riscv,isa`.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 platform/generic/platform.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/platform/generic/platform.c b/platform/generic/platform.c
index 2e8c6051..10bc3137 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -67,6 +67,39 @@ default_config:
 	return fw_platform_calculate_heap_size(hart_count);
 }
 
+static u32 fw_platform_get_reserved_pmp_count(const void *fdt)
+{
+	int chosen_offset, config_offset, len;
+	u32 reserved_pmp_count;
+	const fdt32_t *val;
+
+	/*
+	 * Reserve one default entry if smepmp is enabned.
+	 * This entry is required for sbi_hart_map_saddr().
+	 */
+	if (fdt_has_isa_extension(fdt, "smepmp"))
+		reserved_pmp_count = 1;
+	else
+		reserved_pmp_count = 0;
+
+
+	/* Get the heap size from device tree */
+	chosen_offset = fdt_path_offset(fdt, "/chosen");
+	if (chosen_offset < 0)
+		goto out;
+
+	config_offset = fdt_node_offset_by_compatible(fdt, chosen_offset, "opensbi,config");
+	if (config_offset < 0)
+		goto out;
+
+	val = (fdt32_t *)fdt_getprop(fdt, config_offset, "reserved-pmp-count", &len);
+	if (len > 0 && val)
+		return fdt32_to_cpu(*val) + reserved_pmp_count;
+
+out:
+	return reserved_pmp_count;
+}
+
 extern struct sbi_platform platform;
 static bool platform_has_mlevel_imsic = false;
 static u32 generic_hart_index2id[SBI_HARTMASK_MAX_BITS] = { 0 };
@@ -185,6 +218,7 @@ unsigned long fw_platform_init(unsigned long arg0, unsigned long arg1,
 
 	platform.hart_count = hart_count;
 	platform.heap_size = fw_platform_get_heap_size(fdt, hart_count);
+	platform.reserved_pmp_count = fw_platform_get_reserved_pmp_count(fdt);
 	platform_has_mlevel_imsic = fdt_check_imsic_mlevel(fdt);
 	platform.cbom_block_size = cbom_block_size;
 
-- 
2.48.0



From peter.lin at sifive.com  Fri Aug 15 03:01:12 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Fri, 15 Aug 2025 18:01:12 +0800
Subject: [RFC PATCH 4/7] lib: sbi_init: print total and reserved PMP counts
In-Reply-To: <20250815100116.27776-1-peter.lin@sifive.com>
References: <20250815100116.27776-1-peter.lin@sifive.com>
Message-ID: <20250815100116.27776-5-peter.lin@sifive.com>

Show both total and reserved PMP counts in boot log.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 lib/sbi/sbi_init.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
index 84a63748..367476f0 100644
--- a/lib/sbi/sbi_init.c
+++ b/lib/sbi/sbi_init.c
@@ -163,6 +163,7 @@ static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
 	int xlen;
 	char str[256];
 	const struct sbi_domain *dom = sbi_domain_thishart_ptr();
+	const struct sbi_platform *plat = sbi_platform_ptr(scratch);
 
 	if (scratch->options & SBI_SCRATCH_NO_BOOT_PRINTS)
 		return;
@@ -183,8 +184,9 @@ static void sbi_boot_print_hart(struct sbi_scratch *scratch, u32 hartid)
 	sbi_printf("Boot HART Base ISA          : %s\n", str);
 	sbi_hart_get_extensions_str(scratch, str, sizeof(str));
 	sbi_printf("Boot HART ISA Extensions    : %s\n", str);
-	sbi_printf("Boot HART PMP Count         : %d\n",
-		   sbi_hart_pmp_count(scratch));
+	sbi_printf("Boot HART PMP Count         : "
+		   "%d (total), %d (reserved)\n",
+		   sbi_hart_pmp_count(scratch), plat->reserved_pmp_count);
 	sbi_printf("Boot HART PMP Granularity   : %u bits\n",
 		   sbi_hart_pmp_log2gran(scratch));
 	sbi_printf("Boot HART PMP Address Bits  : %d\n",
-- 
2.48.0



From peter.lin at sifive.com  Fri Aug 15 03:01:13 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Fri, 15 Aug 2025 18:01:13 +0800
Subject: [RFC PATCH 5/7] lib: sbi: riscv_asm: add reserved_pmp_alloc() to allocate a reserved PMP
In-Reply-To: <20250815100116.27776-1-peter.lin@sifive.com>
References: <20250815100116.27776-1-peter.lin@sifive.com>
Message-ID: <20250815100116.27776-6-peter.lin@sifive.com>

Add a function that allocates unused PMP entries from the high-priority
reserved pool.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 include/sbi/riscv_asm.h |  2 ++
 lib/sbi/riscv_asm.c     | 25 +++++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/include/sbi/riscv_asm.h b/include/sbi/riscv_asm.h
index ef48dc89..5fff2196 100644
--- a/include/sbi/riscv_asm.h
+++ b/include/sbi/riscv_asm.h
@@ -221,6 +221,8 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
 int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
 	    unsigned long *log2len);
 
+int reserved_pmp_alloc(unsigned int *pmp_id);
+
 #endif /* !__ASSEMBLER__ */
 
 #endif
diff --git a/lib/sbi/riscv_asm.c b/lib/sbi/riscv_asm.c
index c7d75ac0..daa5087a 100644
--- a/lib/sbi/riscv_asm.c
+++ b/lib/sbi/riscv_asm.c
@@ -403,3 +403,28 @@ int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
 
 	return 0;
 }
+
+/**
+ * reserved_pmp_alloc() - Allocate an unused reserved PMP entry
+ * @pmp_id: Pointer to store the allocated PMP entry ID
+ *
+ * Returns: 0 on success, negative error code on failure
+ *
+ * The caller is responsible for configuring the allocated entry
+ * using pmp_set() and pmp_disable().
+ */
+int reserved_pmp_alloc(unsigned int *pmp_id)
+{
+	const struct sbi_platform *plat = sbi_platform_thishart_ptr();
+
+	for (int n = 0; n < plat->reserved_pmp_count; n++) {
+		if (is_pmp_entry_mapped(n))
+			continue;
+		*pmp_id = n;
+		return SBI_SUCCESS;
+	}
+
+	sbi_printf("%s: Failed to allocate PMP entry. "
+		   "Please increase reserved-pmp-count\n", __func__);
+	return SBI_EFAIL;
+}
-- 
2.48.0



From peter.lin at sifive.com  Fri Aug 15 03:01:14 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Fri, 15 Aug 2025 18:01:14 +0800
Subject: [RFC PATCH 6/7] lib: sbi: sbi_hart: extend PMP handling to support multiple reserved entries
In-Reply-To: <20250815100116.27776-1-peter.lin@sifive.com>
References: <20250815100116.27776-1-peter.lin@sifive.com>
Message-ID: <20250815100116.27776-7-peter.lin@sifive.com>

Previously, OpenSBI supported only a single reserved PMP entry. This
change adds support for multiple reserved PMP entries, configurable
via the `reserved-pmp-count` DT property in the opensbi-config.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 include/sbi/sbi_hart.h       | 15 ----------
 lib/sbi/sbi_domain_context.c |  6 +++-
 lib/sbi/sbi_hart.c           | 56 +++++++++++++++++++++++++++---------
 3 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index 82b19dcf..86c2675b 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -101,21 +101,6 @@ enum sbi_hart_csrs {
 	SBI_HART_CSR_MAX,
 };
 
-/*
- * Smepmp enforces access boundaries between M-mode and
- * S/U-mode. When it is enabled, the PMPs are programmed
- * such that M-mode doesn't have access to S/U-mode memory.
- *
- * To give M-mode R/W access to the shared memory between M and
- * S/U-mode, first entry is reserved. It is disabled at boot.
- * When shared memory access is required, the physical address
- * should be programmed into the first PMP entry with R/W
- * permissions to the M-mode. Once the work is done, it should be
- * unmapped. sbi_hart_map_saddr/sbi_hart_unmap_saddr function
- * pair should be used to map/unmap the shared memory.
- */
-#define SBI_SMEPMP_RESV_ENTRY		0
-
 struct sbi_hart_features {
 	bool detected;
 	int priv_version;
diff --git a/lib/sbi/sbi_domain_context.c b/lib/sbi/sbi_domain_context.c
index fb04d81d..a78bd28c 100644
--- a/lib/sbi/sbi_domain_context.c
+++ b/lib/sbi/sbi_domain_context.c
@@ -101,6 +101,7 @@ static void switch_to_next_domain_context(struct hart_context *ctx,
 	struct sbi_domain *current_dom = ctx->dom;
 	struct sbi_domain *target_dom = dom_ctx->dom;
 	struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+	const struct sbi_platform *plat = sbi_platform_thishart_ptr();
 	unsigned int pmp_count = sbi_hart_pmp_count(scratch);
 
 	/* Assign current hart to target domain */
@@ -115,7 +116,10 @@ static void switch_to_next_domain_context(struct hart_context *ctx,
 	spin_unlock(&target_dom->assigned_harts_lock);
 
 	/* Reconfigure PMP settings for the new domain */
-	for (int i = 0; i < pmp_count; i++) {
+	for (int i = plat->reserved_pmp_count; i < pmp_count; i++) {
+		if (pmp_is_fw_region(i, current_dom))
+			continue;
+
 		sbi_platform_pmp_disable(sbi_platform_thishart_ptr(), i);
 		pmp_disable(i);
 	}
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 6a2d7d6f..e8762084 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -17,6 +17,7 @@
 #include <sbi/sbi_csr_detect.h>
 #include <sbi/sbi_error.h>
 #include <sbi/sbi_hart.h>
+#include <sbi/sbi_init.h>
 #include <sbi/sbi_math.h>
 #include <sbi/sbi_platform.h>
 #include <sbi/sbi_pmu.h>
@@ -30,6 +31,7 @@ extern void __sbi_expected_trap_hext(void);
 void (*sbi_hart_expected_trap)(void) = &__sbi_expected_trap;
 
 static unsigned long hart_features_offset;
+static unsigned int saddr_pmp_id;
 
 static void mstatus_init(struct sbi_scratch *scratch)
 {
@@ -393,6 +395,7 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
 				     unsigned long pmp_addr_max)
 {
 	struct sbi_domain_memregion *reg;
+	const struct sbi_platform *plat = sbi_platform_thishart_ptr();
 	struct sbi_domain *dom = sbi_domain_thishart_ptr();
 	unsigned int pmp_idx, pmp_flags;
 
@@ -402,16 +405,19 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
 	 */
 	csr_set(CSR_MSECCFG, MSECCFG_RLB);
 
-	/* Disable the reserved entry */
-	pmp_disable(SBI_SMEPMP_RESV_ENTRY);
+	/* Disable the reserved entries */
+	for (int i = 0; i < plat->reserved_pmp_count; i++)
+		pmp_disable(i);
 
 	/* Program M-only regions when MML is not set. */
 	pmp_idx = 0;
 	sbi_domain_for_each_memregion(dom, reg) {
 		/* Skip reserved entry */
-		if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
-			pmp_idx++;
-		if (pmp_count <= pmp_idx)
+		if (pmp_idx < plat->reserved_pmp_count)
+			pmp_idx += plat->reserved_pmp_count;
+		if (pmp_count <= pmp_idx) {
+			sbi_printf("%s: ERR: region %#lx cannot be protected - "
+				   "insufficient PMP entries\n", __func__, reg->base);
 			break;
 
 		/* Skip shared and SU-only regions */
@@ -435,9 +441,11 @@ static int sbi_hart_smepmp_configure(struct sbi_scratch *scratch,
 	pmp_idx = 0;
 	sbi_domain_for_each_memregion(dom, reg) {
 		/* Skip reserved entry */
-		if (pmp_idx == SBI_SMEPMP_RESV_ENTRY)
-			pmp_idx++;
-		if (pmp_count <= pmp_idx)
+		if (pmp_idx < plat->reserved_pmp_count)
+			pmp_idx += plat->reserved_pmp_count;
+		if (pmp_count <= pmp_idx) {
+			sbi_printf("%s: ERR: region %#lx cannot be protected - "
+				   "insufficient PMP entries\n", __func__, reg->base);
 			break;
 
 		/* Skip M-only regions */
@@ -468,13 +476,19 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
 				     unsigned long pmp_addr_max)
 {
 	struct sbi_domain_memregion *reg;
+	const struct sbi_platform *plat = sbi_platform_thishart_ptr();
 	struct sbi_domain *dom = sbi_domain_thishart_ptr();
 	unsigned int pmp_idx = 0;
 	unsigned int pmp_flags;
 	unsigned long pmp_addr;
 
 	sbi_domain_for_each_memregion(dom, reg) {
-		if (pmp_count <= pmp_idx)
+		/* Skip reserved entry */
+		if (pmp_idx < plat->reserved_pmp_count)
+			pmp_idx += plat->reserved_pmp_count;
+		if (pmp_count <= pmp_idx) {
+			sbi_printf("%s: ERR: region %#lx cannot be protected - "
+				   "insufficient PMP entries\n", __func__, reg->base);
 			break;
 
 		pmp_flags = 0;
@@ -510,6 +524,19 @@ static int sbi_hart_oldpmp_configure(struct sbi_scratch *scratch,
 	return 0;
 }
 
+/*
+ * Smepmp enforces access boundaries between M-mode and
+ * S/U-mode. When it is enabled, the PMPs are programmed
+ * such that M-mode doesn't have access to S/U-mode memory.
+ *
+ * To give M-mode R/W access to the shared memory between M and
+ * S/U-mode, high-priority entry is reserved. It is disabled at boot.
+ * When shared memory access is required, the physical address
+ * should be programmed into the reserved PMP entry with R/W
+ * permissions to the M-mode. Once the work is done, it should be
+ * unmapped. sbi_hart_map_saddr/sbi_hart_unmap_saddr function
+ * pair should be used to map/unmap the shared memory.
+ */
 int sbi_hart_map_saddr(unsigned long addr, unsigned long size)
 {
 	/* shared R/W access for M and S/U mode */
@@ -521,8 +548,9 @@ int sbi_hart_map_saddr(unsigned long addr, unsigned long size)
 	if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
 		return SBI_OK;
 
-	if (is_pmp_entry_mapped(SBI_SMEPMP_RESV_ENTRY))
+	if (reserved_pmp_alloc(&saddr_pmp_id)) {
 		return SBI_ENOSPC;
+	}
 
 	for (order = MAX(sbi_hart_pmp_log2gran(scratch), log2roundup(size));
 	     order <= __riscv_xlen; order++) {
@@ -538,10 +566,10 @@ int sbi_hart_map_saddr(unsigned long addr, unsigned long size)
 		}
 	}
 
-	sbi_platform_pmp_set(sbi_platform_ptr(scratch), SBI_SMEPMP_RESV_ENTRY,
+	sbi_platform_pmp_set(sbi_platform_ptr(scratch), saddr_pmp_id,
 			     SBI_DOMAIN_MEMREGION_SHARED_SURW_MRW,
 			     pmp_flags, base, order);
-	pmp_set(SBI_SMEPMP_RESV_ENTRY, pmp_flags, base, order);
+	pmp_set(saddr_pmp_id, pmp_flags, base, order);
 
 	return SBI_OK;
 }
@@ -553,8 +581,8 @@ int sbi_hart_unmap_saddr(void)
 	if (!sbi_hart_has_extension(scratch, SBI_HART_EXT_SMEPMP))
 		return SBI_OK;
 
-	sbi_platform_pmp_disable(sbi_platform_ptr(scratch), SBI_SMEPMP_RESV_ENTRY);
-	return pmp_disable(SBI_SMEPMP_RESV_ENTRY);
+	sbi_platform_pmp_disable(sbi_platform_ptr(scratch), saddr_pmp_id);
+	return pmp_disable(saddr_pmp_id);
 }
 
 int sbi_hart_pmp_configure(struct sbi_scratch *scratch)
-- 
2.48.0



From peter.lin at sifive.com  Fri Aug 15 03:01:15 2025
From: peter.lin at sifive.com (Yu-Chien Peter Lin)
Date: Fri, 15 Aug 2025 18:01:15 +0800
Subject: [RFC PATCH 7/7] docs: opensbi_config: add description for reserved-pmp-count
In-Reply-To: <20250815100116.27776-1-peter.lin@sifive.com>
References: <20250815100116.27776-1-peter.lin@sifive.com>
Message-ID: <20250815100116.27776-8-peter.lin@sifive.com>

Add documentation for the reserved-pmp-count property, which
specifies the number of additional high-priority PMP entries.

Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
---
 docs/opensbi_config.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/docs/opensbi_config.md b/docs/opensbi_config.md
index 104d82c9..02481800 100644
--- a/docs/opensbi_config.md
+++ b/docs/opensbi_config.md
@@ -26,6 +26,9 @@ The DT properties of a domain configuration DT node are as follows:
 * **heap-size** (Optional) - When present, the specified value is used
   as the size of the heap in bytes.
 
+* **reserved-pmp-count** (Optional) - When present, the specified value
+  is used as the additional number of reserved high-priority PMP entries.
+
 * **system-suspend-test** (Optional) - When present, enable a system
   suspend test implementation which simply waits five seconds and issues a WFI.
 
@@ -40,6 +43,7 @@ The OpenSBI Configuration Node will be deleted at the end of cold boot
             compatible = "opensbi,config";
             cold-boot-harts = <&cpu1 &cpu2 &cpu3 &cpu4>;
             heap-size = <0x400000>;
+            reserved-pmp-count = <2>;
             system-suspend-test;
         };
     };
-- 
2.48.0



From nick.hu at sifive.com  Tue Aug 19 20:32:39 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:39 +0800
Subject: [PATCH v4 00/11] Add SiFive TMC0 and SMC0 driver
Message-ID: <20250820033250.544-1-nick.hu@sifive.com>

SiFive TMC0 and SMC0 are the power controllers that controls the Tile and
CoreComplex power domain. Add the drivers to support the power
management features such as HSM STOP and System Suspend.

Features such as power management may require flushing the entire
cache before entering a non-retention power state. To support this, a
simple cache flush framework is introduced to allow the external CMO
to perform a full cache flush.

Changes in v4:
- Call fdt_cmo_init() directly as part of generic_early_init()
- Rename SBI_HART_EXT_XSF* to SBI_HART_EXT_XSIFIVE*
- Move the TMC0 driver to the lib/utils/hsm/
- Move the SMC0 driver to the lib/utils/suspend/

Changes in v3:
- Add the SiFive TMC and SMC driver

Changes in v2:
- Since the platform override hooks was deprecated, use the fdt_driver
for initializing the sifive_dev_platform.

Nick Hu (10):
  lib: utils: Add cache flush library
  lib: utils: Add FDT cache library
  lib: utils/cache: Add fdt cmo helpers
  lib: sbi: Add SiFive proprietary xsfcflushdlone
  lib: sbi: Add SiFive proprietary xsfcease
  lib: utils/ipi: Exposing the ACLINT IPI device
  lib: utils/irqchip: Add APLIC restore function
  platform: sifive: Add SiFive TMC0 driver
  lib: utils/timer: Expose timer update function
  platform: sifive: Add SiFive SMC0 driver

Vincent Chen (1):
  utils: cache: Add SiFive ccache controller

 include/sbi/sbi_hart.h                        |   4 +
 include/sbi_utils/cache/cache.h               |  69 +++
 include/sbi_utils/cache/fdt_cache.h           |  34 ++
 include/sbi_utils/cache/fdt_cmo_helper.h      |  34 ++
 include/sbi_utils/hsm/fdt_hsm_sifive_inst.h   |  20 +
 include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h   |  19 +
 include/sbi_utils/ipi/aclint_mswi.h           |   1 +
 include/sbi_utils/irqchip/aplic.h             |   3 +
 .../suspend/fdt_suspend_sifive_smc0.h         |  18 +
 include/sbi_utils/timer/aclint_mtimer.h       |   5 +
 lib/sbi/sbi_hart.c                            |   2 +
 lib/utils/Kconfig                             |   2 +
 lib/utils/cache/Kconfig                       |  23 +
 lib/utils/cache/cache.c                       |  46 ++
 lib/utils/cache/fdt_cache.c                   |  87 ++++
 lib/utils/cache/fdt_cache_drivers.carray      |   3 +
 lib/utils/cache/fdt_cmo_helper.c              | 112 +++++
 lib/utils/cache/fdt_sifive_ccache.c           | 175 +++++++
 lib/utils/cache/objects.mk                    |  14 +
 lib/utils/hsm/Kconfig                         |   5 +
 lib/utils/hsm/fdt_hsm_sifive_tmc0.c           | 468 ++++++++++++++++++
 lib/utils/hsm/objects.mk                      |   2 +
 lib/utils/ipi/aclint_mswi.c                   |   5 +
 lib/utils/irqchip/aplic.c                     | 160 +++---
 lib/utils/suspend/Kconfig                     |   4 +
 lib/utils/suspend/fdt_suspend_sifive_smc0.c   | 323 ++++++++++++
 lib/utils/suspend/objects.mk                  |   3 +
 lib/utils/timer/aclint_mtimer.c               |  28 +-
 platform/generic/Kconfig                      |   5 +
 platform/generic/configs/defconfig            |   5 +
 platform/generic/platform.c                   |   3 +-
 platform/generic/sifive/objects.mk            |   3 +
 platform/generic/sifive/sifive_dev_platform.c |  57 +++
 33 files changed, 1667 insertions(+), 75 deletions(-)
 create mode 100644 include/sbi_utils/cache/cache.h
 create mode 100644 include/sbi_utils/cache/fdt_cache.h
 create mode 100644 include/sbi_utils/cache/fdt_cmo_helper.h
 create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
 create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
 create mode 100644 include/sbi_utils/suspend/fdt_suspend_sifive_smc0.h
 create mode 100644 lib/utils/cache/Kconfig
 create mode 100644 lib/utils/cache/cache.c
 create mode 100644 lib/utils/cache/fdt_cache.c
 create mode 100644 lib/utils/cache/fdt_cache_drivers.carray
 create mode 100644 lib/utils/cache/fdt_cmo_helper.c
 create mode 100644 lib/utils/cache/fdt_sifive_ccache.c
 create mode 100644 lib/utils/cache/objects.mk
 create mode 100644 lib/utils/hsm/fdt_hsm_sifive_tmc0.c
 create mode 100644 lib/utils/suspend/fdt_suspend_sifive_smc0.c
 create mode 100644 platform/generic/sifive/sifive_dev_platform.c

-- 
2.17.1



From nick.hu at sifive.com  Tue Aug 19 20:32:40 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:40 +0800
Subject: [PATCH v4 01/11] lib: utils: Add cache flush library
In-Reply-To: <20250820033250.544-1-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com>
Message-ID: <20250820033250.544-2-nick.hu@sifive.com>

The current RISC-V CMO only defines how to flush a cache block. However,
certain use cases, such as power management, may require flushing the
entire cache. Therefore, a framework is being introduced to allow vendors
to flush the entire cache using their own methods.

Signed-off-by: Nick Hu <nick.hu at sifive.com>
Reviewed-by: Samuel Holland <samuel.holland at sifive.com>
Reviewed-by: Anup Patel <anup at brainfault.org>
---
 include/sbi_utils/cache/cache.h | 69 +++++++++++++++++++++++++++++++++
 lib/utils/Kconfig               |  2 +
 lib/utils/cache/Kconfig         |  9 +++++
 lib/utils/cache/cache.c         | 46 ++++++++++++++++++++++
 lib/utils/cache/objects.mk      |  7 ++++
 5 files changed, 133 insertions(+)
 create mode 100644 include/sbi_utils/cache/cache.h
 create mode 100644 lib/utils/cache/Kconfig
 create mode 100644 lib/utils/cache/cache.c
 create mode 100644 lib/utils/cache/objects.mk

diff --git a/include/sbi_utils/cache/cache.h b/include/sbi_utils/cache/cache.h
new file mode 100644
index 00000000..70d9286f
--- /dev/null
+++ b/include/sbi_utils/cache/cache.h
@@ -0,0 +1,69 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#ifndef __CACHE_H__
+#define __CACHE_H__
+
+#include <sbi/sbi_list.h>
+#include <sbi/sbi_types.h>
+
+#define CACHE_NAME_LEN	32
+
+struct cache_device;
+
+struct cache_ops {
+	/** Warm init **/
+	int (*warm_init)(struct cache_device *dev);
+	/** Flush entire cache **/
+	int (*cache_flush_all)(struct cache_device *dev);
+};
+
+struct cache_device {
+	/** Name of the device **/
+	char name[CACHE_NAME_LEN];
+	/** List node for search **/
+	struct sbi_dlist node;
+	/** Point to the next level cache **/
+	struct cache_device *next;
+	/** Cache Management Operations **/
+	struct cache_ops *ops;
+	/** CPU private cache **/
+	bool cpu_private;
+	/** The unique id of this cache device **/
+	u32 id;
+};
+
+/**
+ * Find a registered cache device
+ *
+ * @param id unique ID of the cache device
+ *
+ * @return the cache device or NULL
+ */
+struct cache_device *cache_find(u32 id);
+
+/**
+ * Register a cache device
+ *
+ * cache_device->id must be initialized already and must not change during the life
+ * of the cache_device object.
+ *
+ * @param dev the cache device to register
+ *
+ * @return 0 on success, or a negative error code on failure
+ */
+int cache_add(struct cache_device *dev);
+
+/**
+ * Flush the entire cache
+ *
+ * @param dev the cache to flush
+ *
+ * @return 0 on success, or a negative error code on failure
+ */
+int cache_flush_all(struct cache_device *dev);
+
+#endif
diff --git a/lib/utils/Kconfig b/lib/utils/Kconfig
index 901ba564..5a5b3b1e 100644
--- a/lib/utils/Kconfig
+++ b/lib/utils/Kconfig
@@ -2,6 +2,8 @@
 
 menu "Utils and Drivers Support"
 
+source "$(OPENSBI_SRC_DIR)/lib/utils/cache/Kconfig"
+
 source "$(OPENSBI_SRC_DIR)/lib/utils/cppc/Kconfig"
 
 source "$(OPENSBI_SRC_DIR)/lib/utils/fdt/Kconfig"
diff --git a/lib/utils/cache/Kconfig b/lib/utils/cache/Kconfig
new file mode 100644
index 00000000..24aa41bc
--- /dev/null
+++ b/lib/utils/cache/Kconfig
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: BSD-2-Clause
+
+menu "Cache Support"
+
+config CACHE
+	bool "Cache support"
+	default n
+
+endmenu
diff --git a/lib/utils/cache/cache.c b/lib/utils/cache/cache.c
new file mode 100644
index 00000000..6bc3d10e
--- /dev/null
+++ b/lib/utils/cache/cache.c
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#include <sbi/sbi_error.h>
+#include <sbi_utils/cache/cache.h>
+
+static SBI_LIST_HEAD(cache_list);
+
+struct cache_device *cache_find(u32 id)
+{
+	struct cache_device *dev;
+
+	sbi_list_for_each_entry(dev, &cache_list, node) {
+		if (dev->id == id)
+			return dev;
+	}
+
+	return NULL;
+}
+
+int cache_add(struct cache_device *dev)
+{
+	if (!dev)
+		return SBI_ENODEV;
+
+	if (cache_find(dev->id))
+		return SBI_EALREADY;
+
+	sbi_list_add(&dev->node, &cache_list);
+
+	return SBI_OK;
+}
+
+int cache_flush_all(struct cache_device *dev)
+{
+	if (!dev)
+		return SBI_ENODEV;
+
+	if (!dev->ops || !dev->ops->cache_flush_all)
+		return SBI_ENOTSUPP;
+
+	return dev->ops->cache_flush_all(dev);
+}
diff --git a/lib/utils/cache/objects.mk b/lib/utils/cache/objects.mk
new file mode 100644
index 00000000..21d30ce8
--- /dev/null
+++ b/lib/utils/cache/objects.mk
@@ -0,0 +1,7 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2025 SiFive
+#
+
+libsbiutils-objs-$(CONFIG_CACHE) += cache/cache.o
-- 
2.17.1



From nick.hu at sifive.com  Tue Aug 19 20:32:41 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:41 +0800
Subject: [PATCH v4 02/11] lib: utils: Add FDT cache library
In-Reply-To: <20250820033250.544-1-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com>
Message-ID: <20250820033250.544-3-nick.hu@sifive.com>

Add the FDT cache library so we can build up the cache topology via the
'next-level-cache' DT property.

Co-developed-by: Vincent Chen <vincent.chen at sifive.com>
Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
Co-developed-by: Andy Chiu <andy.chiu at sifive.com>
Signed-off-by: Andy Chiu <andy.chiu at sifive.com>
Signed-off-by: Nick Hu <nick.hu at sifive.com>
Reviewed-by: Samuel Holland <samuel.holland at sifive.com>
Reviewed-by: Anup Patel <anup at brainfault.org>
---
 include/sbi_utils/cache/fdt_cache.h      | 34 +++++++++
 lib/utils/cache/Kconfig                  |  6 ++
 lib/utils/cache/fdt_cache.c              | 87 ++++++++++++++++++++++++
 lib/utils/cache/fdt_cache_drivers.carray |  3 +
 lib/utils/cache/objects.mk               |  3 +
 platform/generic/configs/defconfig       |  1 +
 6 files changed, 134 insertions(+)
 create mode 100644 include/sbi_utils/cache/fdt_cache.h
 create mode 100644 lib/utils/cache/fdt_cache.c
 create mode 100644 lib/utils/cache/fdt_cache_drivers.carray

diff --git a/include/sbi_utils/cache/fdt_cache.h b/include/sbi_utils/cache/fdt_cache.h
new file mode 100644
index 00000000..b377d6f5
--- /dev/null
+++ b/include/sbi_utils/cache/fdt_cache.h
@@ -0,0 +1,34 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#ifndef __FDT_CACHE_H__
+#define __FDT_CACHE_H__
+
+#include <sbi_utils/cache/cache.h>
+
+/**
+ * Register a cache device using information from the DT
+ *
+ * @param fdt devicetree blob
+ * @param noff offset of a node in the devicetree blob
+ * @param dev cache device to register for this devicetree node
+ *
+ * @return 0 on success, or a negative error code on failure
+ */
+int fdt_cache_add(const void *fdt, int noff, struct cache_device *dev);
+
+/**
+ * Get the cache device referencd by the "next-level-cache" property of a DT node
+ *
+ * @param fdt devicetree blob
+ * @param noff offset of a node in the devicetree blob
+ * @param out_dev location to return the cache device
+ *
+ * @return 0 on success, or a negative error code on failure
+ */
+int fdt_next_cache_get(const void *fdt, int noff, struct cache_device **out_dev);
+
+#endif
diff --git a/lib/utils/cache/Kconfig b/lib/utils/cache/Kconfig
index 24aa41bc..10602176 100644
--- a/lib/utils/cache/Kconfig
+++ b/lib/utils/cache/Kconfig
@@ -2,6 +2,12 @@
 
 menu "Cache Support"
 
+config FDT_CACHE
+	bool "FDT based cache drivers"
+	depends on FDT
+	select CACHE
+	default n
+
 config CACHE
 	bool "Cache support"
 	default n
diff --git a/lib/utils/cache/fdt_cache.c b/lib/utils/cache/fdt_cache.c
new file mode 100644
index 00000000..e1c6f67c
--- /dev/null
+++ b/lib/utils/cache/fdt_cache.c
@@ -0,0 +1,87 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#include <libfdt.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_heap.h>
+#include <sbi_utils/cache/fdt_cache.h>
+#include <sbi_utils/fdt/fdt_driver.h>
+
+/* List of FDT cache drivers generated at compile time */
+extern const struct fdt_driver *const fdt_cache_drivers[];
+
+int fdt_cache_add(const void *fdt, int noff, struct cache_device *dev)
+{
+	int rc;
+
+	dev->id = noff;
+	sbi_strncpy(dev->name, fdt_get_name(fdt, noff, NULL), sizeof(dev->name) - 1);
+	sbi_dprintf("%s: %s\n", __func__, dev->name);
+
+	rc = fdt_next_cache_get(fdt, noff, &dev->next);
+	if (rc)
+		return rc;
+
+	return cache_add(dev);
+}
+
+static int fdt_cache_add_generic(const void *fdt, int noff)
+{
+	struct cache_device *dev;
+	int rc;
+
+	dev = sbi_zalloc(sizeof(*dev));
+	if (!dev)
+		return SBI_ENOMEM;
+
+	rc = fdt_cache_add(fdt, noff, dev);
+	if (rc) {
+		sbi_free(dev);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int fdt_cache_find(const void *fdt, int noff, struct cache_device **out_dev)
+{
+	struct cache_device *dev = cache_find(noff);
+	int rc;
+
+	if (!dev) {
+		rc = fdt_driver_init_by_offset(fdt, noff, fdt_cache_drivers);
+		if (rc == SBI_ENODEV)
+			rc = fdt_cache_add_generic(fdt, noff);
+		if (rc)
+			return rc;
+
+		dev = cache_find(noff);
+		if (!dev)
+			return SBI_EFAIL;
+	}
+
+	if (out_dev)
+		*out_dev = dev;
+
+	return SBI_OK;
+}
+
+int fdt_next_cache_get(const void *fdt, int noff, struct cache_device **out_dev)
+{
+	const fdt32_t *val;
+	int len;
+
+	val = fdt_getprop(fdt, noff, "next-level-cache", &len);
+	if (!val || len < sizeof(*val))
+		return SBI_OK;
+
+	noff = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(val[0]));
+	if (noff < 0)
+		return noff;
+
+	return fdt_cache_find(fdt, noff, out_dev);
+}
diff --git a/lib/utils/cache/fdt_cache_drivers.carray b/lib/utils/cache/fdt_cache_drivers.carray
new file mode 100644
index 00000000..c1b1791c
--- /dev/null
+++ b/lib/utils/cache/fdt_cache_drivers.carray
@@ -0,0 +1,3 @@
+HEADER: sbi_utils/cache/fdt_cache.h
+TYPE: const struct fdt_driver
+NAME: fdt_cache_drivers
diff --git a/lib/utils/cache/objects.mk b/lib/utils/cache/objects.mk
index 21d30ce8..2fcf9666 100644
--- a/lib/utils/cache/objects.mk
+++ b/lib/utils/cache/objects.mk
@@ -4,4 +4,7 @@
 # Copyright (c) 2025 SiFive
 #
 
+libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache.o
+libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache_drivers.carray.o
+
 libsbiutils-objs-$(CONFIG_CACHE) += cache/cache.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index c7a6531e..b5a7993d 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -7,6 +7,7 @@ CONFIG_PLATFORM_SOPHGO_SG2042=y
 CONFIG_PLATFORM_STARFIVE_JH7110=y
 CONFIG_PLATFORM_THEAD=y
 CONFIG_PLATFORM_MIPS_P8700=y
+CONFIG_FDT_CACHE=y
 CONFIG_FDT_CPPC=y
 CONFIG_FDT_CPPC_RPMI=y
 CONFIG_FDT_GPIO=y
-- 
2.17.1



From nick.hu at sifive.com  Tue Aug 19 20:32:42 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:42 +0800
Subject: [PATCH v4 03/11] utils: cache: Add SiFive ccache controller
In-Reply-To: <20250820033250.544-1-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com>
Message-ID: <20250820033250.544-4-nick.hu@sifive.com>

From: Vincent Chen <vincent.chen at sifive.com>

SiFive Composable cache is a L3 share cache of the core complex. Add this
driver to support the share cache maintenance operations via the MMIO
registers.

Co-developed-by: Samuel Holland <samuel.holland at sifive.com>
Signed-off-by: Samuel Holland <samuel.holland at sifive.com>
Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
Co-developed-by: Nick Hu <nick.hu at sifive.com>
Signed-off-by: Nick Hu <nick.hu at sifive.com>
Reviewed-by: Samuel Holland <samuel.holland at sifive.com>
Reviewed-by: Anup Patel <anup at brainfault.org>
---
 lib/utils/cache/Kconfig             |   8 ++
 lib/utils/cache/fdt_sifive_ccache.c | 175 ++++++++++++++++++++++++++++
 lib/utils/cache/objects.mk          |   3 +
 platform/generic/configs/defconfig  |   1 +
 4 files changed, 187 insertions(+)
 create mode 100644 lib/utils/cache/fdt_sifive_ccache.c

diff --git a/lib/utils/cache/Kconfig b/lib/utils/cache/Kconfig
index 10602176..1c7abdc9 100644
--- a/lib/utils/cache/Kconfig
+++ b/lib/utils/cache/Kconfig
@@ -8,6 +8,14 @@ config FDT_CACHE
 	select CACHE
 	default n
 
+if FDT_CACHE
+
+config FDT_CACHE_SIFIVE_CCACHE
+	bool "SiFive CCACHE FDT cache driver"
+	default n
+
+endif
+
 config CACHE
 	bool "Cache support"
 	default n
diff --git a/lib/utils/cache/fdt_sifive_ccache.c b/lib/utils/cache/fdt_sifive_ccache.c
new file mode 100644
index 00000000..b641ed16
--- /dev/null
+++ b/lib/utils/cache/fdt_sifive_ccache.c
@@ -0,0 +1,175 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#include <libfdt.h>
+#include <sbi/riscv_barrier.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_heap.h>
+#include <sbi_utils/cache/fdt_cache.h>
+#include <sbi_utils/fdt/fdt_driver.h>
+
+#define CCACHE_CFG_CSR			0
+#define CCACHE_CMD_CSR			0x280
+#define CCACHE_STATUS_CSR		0x288
+
+#define CFG_CSR_BANK_MASK		0xff
+#define CFG_CSR_WAY_MASK		0xff00
+#define CFG_CSR_WAY_OFFSET		8
+#define CFG_CSR_SET_MASK		0xff0000
+#define CFG_CSR_SET_OFFSET		16
+
+#define CMD_CSR_CMD_OFFSET	56
+#define CMD_CSR_BANK_OFFSET	6
+
+#define CMD_OPCODE_SETWAY	0x1ULL
+#define CMD_OPCODE_OFFSET	0x2ULL
+
+#define CFLUSH_SETWAY_CLEANINV  ((CMD_OPCODE_SETWAY << CMD_OPCODE_OFFSET) | 0x3)
+
+#define CCACHE_CMD_QLEN	0xff
+
+#define ccache_mb_b()		RISCV_FENCE(rw, o)
+#define ccache_mb_a()		RISCV_FENCE(o, rw)
+
+#define CCACHE_ALL_OP_REQ_BATCH_NUM	0x10
+#define CCACHE_ALL_OP_REQ_BATCH_MASK (CCACHE_CMD_QLEN + 1 - CCACHE_ALL_OP_REQ_BATCH_NUM)
+
+struct sifive_ccache {
+	struct cache_device dev;
+	void *addr;
+	u64 total_lines;
+};
+
+#define to_ccache(_dev) container_of(_dev, struct sifive_ccache, dev)
+
+static inline unsigned int sifive_ccache_read_status(void *status_addr)
+{
+	return readl_relaxed(status_addr);
+}
+
+static inline void sifive_ccache_write_cmd(u64 cmd, void *cmd_csr_addr)
+{
+#if __riscv_xlen != 32
+	writeq_relaxed(cmd, cmd_csr_addr);
+#else
+	/*
+	 * The cache maintenance request is only generated when the "command"
+	 * field (part of the high word) is written.
+	 */
+	writel_relaxed(cmd, cmd_csr_addr);
+	writel(cmd >> 32, cmd_csr_addr + 4);
+#endif
+}
+
+static int sifive_ccache_flush_all(struct cache_device *dev)
+{
+	struct sifive_ccache *ccache = to_ccache(dev);
+	void *status_addr = (char *)ccache->addr + CCACHE_STATUS_CSR;
+	void *cmd_csr_addr = (char *)ccache->addr + CCACHE_CMD_CSR;
+	u64 total_cnt = ccache->total_lines;
+	u64 cmd = CFLUSH_SETWAY_CLEANINV << CMD_CSR_CMD_OFFSET;
+	int loop_cnt = CCACHE_CMD_QLEN & CCACHE_ALL_OP_REQ_BATCH_MASK;
+
+	ccache_mb_b();
+send_cmd:
+	total_cnt -= loop_cnt;
+	while (loop_cnt > 0) {
+		sifive_ccache_write_cmd(cmd + (0 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (1 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (2 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (3 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (4 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (5 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (6 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (7 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (8 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (9 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (10 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (11 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (12 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (13 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (14 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		sifive_ccache_write_cmd(cmd + (15 << CMD_CSR_BANK_OFFSET), cmd_csr_addr);
+		cmd += CCACHE_ALL_OP_REQ_BATCH_NUM << CMD_CSR_BANK_OFFSET;
+		loop_cnt -= CCACHE_ALL_OP_REQ_BATCH_NUM;
+	}
+	if (!total_cnt)
+		goto done;
+
+	/* Ensure the ccache is able receive more than 16 requests */
+	do {
+		loop_cnt = (CCACHE_CMD_QLEN - sifive_ccache_read_status(status_addr));
+	} while (loop_cnt < CCACHE_ALL_OP_REQ_BATCH_NUM);
+	loop_cnt &= CCACHE_ALL_OP_REQ_BATCH_MASK;
+
+	if (total_cnt < loop_cnt) {
+		loop_cnt = (total_cnt + CCACHE_ALL_OP_REQ_BATCH_NUM) & CCACHE_ALL_OP_REQ_BATCH_MASK;
+		cmd -= ((loop_cnt - total_cnt) << CMD_CSR_BANK_OFFSET);
+		total_cnt = loop_cnt;
+	}
+	goto send_cmd;
+done:
+	do {} while (sifive_ccache_read_status(status_addr));
+	ccache_mb_a();
+
+	return 0;
+}
+
+static struct cache_ops sifive_ccache_ops = {
+	.cache_flush_all = sifive_ccache_flush_all,
+};
+
+static int sifive_ccache_cold_init(const void *fdt, int nodeoff, const struct fdt_match *match)
+{
+	struct sifive_ccache *ccache;
+	struct cache_device *dev;
+	u64 reg_addr = 0;
+	u32 config_csr, banks, sets, ways;
+	int rc;
+
+	/* find the ccache base control address */
+	rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &reg_addr, NULL);
+	if (rc < 0 && reg_addr)
+		return SBI_ENODEV;
+
+	ccache = sbi_zalloc(sizeof(*ccache));
+	if (!ccache)
+		return SBI_ENOMEM;
+
+	dev = &ccache->dev;
+	dev->ops = &sifive_ccache_ops;
+	rc = fdt_cache_add(fdt, nodeoff, dev);
+	if (rc) {
+		sbi_free(ccache);
+		return rc;
+	}
+
+	ccache->addr = (void *)(uintptr_t)reg_addr;
+
+	/* get the info of ccache from config CSR */
+	config_csr = readl(ccache->addr + CCACHE_CFG_CSR);
+	banks = config_csr & CFG_CSR_BANK_MASK;
+
+	sets = (config_csr & CFG_CSR_SET_MASK) >> CFG_CSR_SET_OFFSET;
+	sets = (1 << sets);
+
+	ways = (config_csr & CFG_CSR_WAY_MASK) >> CFG_CSR_WAY_OFFSET;
+
+	ccache->total_lines = sets * ways * banks;
+
+	return SBI_OK;
+}
+
+static const struct fdt_match sifive_ccache_match[] = {
+	{ .compatible = "sifive,ccache2" },
+	{},
+};
+
+const struct fdt_driver fdt_sifive_ccache = {
+	.match_table = sifive_ccache_match,
+	.init = sifive_ccache_cold_init,
+};
diff --git a/lib/utils/cache/objects.mk b/lib/utils/cache/objects.mk
index 2fcf9666..a343eb8c 100644
--- a/lib/utils/cache/objects.mk
+++ b/lib/utils/cache/objects.mk
@@ -7,4 +7,7 @@
 libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache.o
 libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache_drivers.carray.o
 
+carray-fdt_cache_drivers-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += fdt_sifive_ccache
+libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += cache/fdt_sifive_ccache.o
+
 libsbiutils-objs-$(CONFIG_CACHE) += cache/cache.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index b5a7993d..6b219cfb 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -8,6 +8,7 @@ CONFIG_PLATFORM_STARFIVE_JH7110=y
 CONFIG_PLATFORM_THEAD=y
 CONFIG_PLATFORM_MIPS_P8700=y
 CONFIG_FDT_CACHE=y
+CONFIG_FDT_CACHE_SIFIVE_CCACHE=y
 CONFIG_FDT_CPPC=y
 CONFIG_FDT_CPPC_RPMI=y
 CONFIG_FDT_GPIO=y
-- 
2.17.1



From nick.hu at sifive.com  Tue Aug 19 20:32:43 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:43 +0800
Subject: [PATCH v4 04/11] lib: utils/cache: Add fdt cmo helpers
In-Reply-To: <20250820033250.544-1-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com>
Message-ID: <20250820033250.544-5-nick.hu@sifive.com>

Add the helpers to build up the cache hierarchy via FDT and provide some
cmo functions for the user who want to flush the entire cache.

Signed-off-by: Nick Hu <nick.hu at sifive.com>
Reviewed-by: Samuel Holland <samuel.holland at sifive.com>
Reviewed-by: Anup Patel <anup at brainfault.org>
---
 include/sbi_utils/cache/fdt_cmo_helper.h |  34 +++++++
 lib/utils/cache/fdt_cmo_helper.c         | 112 +++++++++++++++++++++++
 lib/utils/cache/objects.mk               |   1 +
 platform/generic/platform.c              |   3 +-
 4 files changed, 149 insertions(+), 1 deletion(-)
 create mode 100644 include/sbi_utils/cache/fdt_cmo_helper.h
 create mode 100644 lib/utils/cache/fdt_cmo_helper.c

diff --git a/include/sbi_utils/cache/fdt_cmo_helper.h b/include/sbi_utils/cache/fdt_cmo_helper.h
new file mode 100644
index 00000000..4275725e
--- /dev/null
+++ b/include/sbi_utils/cache/fdt_cmo_helper.h
@@ -0,0 +1,34 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#ifndef __FDT_CMO_HELPER_H__
+#define __FDT_CMO_HELPER_H__
+
+/**
+ * Flush the private first level cache of the current hart
+ *
+ * @return 0 on success, or a negative error code on failure
+ */
+int fdt_cmo_private_flc_flush_all(void);
+
+/**
+ * Flush the last level cache of the current hart
+ *
+ * @return 0 on success, or a negative error code on failure
+ */
+int fdt_cmo_llc_flush_all(void);
+
+/**
+ * Initialize the cache devices for each hart
+ *
+ * @param fdt devicetree blob
+ * @param cold_boot cold init or warm init
+ *
+ * @return 0 on success, or a negative error code on failure
+ */
+int fdt_cmo_init(bool cold_boot);
+
+#endif
diff --git a/lib/utils/cache/fdt_cmo_helper.c b/lib/utils/cache/fdt_cmo_helper.c
new file mode 100644
index 00000000..6d2e853d
--- /dev/null
+++ b/lib/utils/cache/fdt_cmo_helper.c
@@ -0,0 +1,112 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#include <libfdt.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_scratch.h>
+#include <sbi_utils/cache/fdt_cache.h>
+#include <sbi_utils/cache/fdt_cmo_helper.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+
+static unsigned long flc_offset;
+
+#define get_hart_flc(_s) \
+	sbi_scratch_read_type(_s, struct cache_device *, flc_offset)
+#define set_hart_flc(_s, _p) \
+	sbi_scratch_write_type(_s, struct cache_device *, flc_offset, _p)
+
+int fdt_cmo_private_flc_flush_all(void)
+{
+	struct cache_device *flc = get_hart_flc(sbi_scratch_thishart_ptr());
+
+	if (!flc || !flc->cpu_private)
+		return SBI_ENODEV;
+
+	return cache_flush_all(flc);
+}
+
+int fdt_cmo_llc_flush_all(void)
+{
+	struct cache_device *llc = get_hart_flc(sbi_scratch_thishart_ptr());
+
+	if (!llc)
+		return SBI_ENODEV;
+
+	while (llc->next)
+		llc = llc->next;
+
+	return cache_flush_all(llc);
+}
+
+static int fdt_cmo_cold_init(const void *fdt)
+{
+	struct sbi_scratch *scratch;
+	struct cache_device *dev;
+	int cpu_offset, cpus_offset, rc;
+	u32 hartid;
+
+	cpus_offset = fdt_path_offset(fdt, "/cpus");
+	if (cpus_offset < 0)
+		return SBI_EINVAL;
+
+	fdt_for_each_subnode(cpu_offset, fdt, cpus_offset) {
+		rc = fdt_parse_hart_id(fdt, cpu_offset, &hartid);
+		if (rc)
+			continue;
+
+		scratch = sbi_hartid_to_scratch(hartid);
+		if (!scratch)
+			continue;
+
+		rc = fdt_next_cache_get(fdt, cpu_offset, &dev);
+		if (rc)
+			return rc;
+
+		set_hart_flc(scratch, dev);
+	}
+
+	return SBI_OK;
+}
+
+static int fdt_cmo_warm_init(void)
+{
+	struct cache_device *cur = get_hart_flc(sbi_scratch_thishart_ptr());
+	int rc;
+
+	while (cur) {
+		if (cur->ops && cur->ops->warm_init) {
+			rc = cur->ops->warm_init(cur);
+			if (rc)
+				return rc;
+		}
+
+		cur = cur->next;
+	}
+
+	return SBI_OK;
+}
+
+int fdt_cmo_init(bool cold_boot)
+{
+	const void *fdt = fdt_get_address();
+	int rc;
+
+	if (cold_boot) {
+		flc_offset = sbi_scratch_alloc_type_offset(struct cache_device *);
+		if (!flc_offset)
+			return SBI_ENOMEM;
+
+		rc = fdt_cmo_cold_init(fdt);
+		if (rc)
+			return rc;
+	}
+
+	rc = fdt_cmo_warm_init();
+	if (rc)
+		return rc;
+
+	return SBI_OK;
+}
diff --git a/lib/utils/cache/objects.mk b/lib/utils/cache/objects.mk
index a343eb8c..6829a966 100644
--- a/lib/utils/cache/objects.mk
+++ b/lib/utils/cache/objects.mk
@@ -6,6 +6,7 @@
 
 libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache.o
 libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cache_drivers.carray.o
+libsbiutils-objs-$(CONFIG_FDT_CACHE) += cache/fdt_cmo_helper.o
 
 carray-fdt_cache_drivers-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += fdt_sifive_ccache
 libsbiutils-objs-$(CONFIG_FDT_CACHE_SIFIVE_CCACHE) += cache/fdt_sifive_ccache.o
diff --git a/platform/generic/platform.c b/platform/generic/platform.c
index 47e771ad..de40791b 100644
--- a/platform/generic/platform.c
+++ b/platform/generic/platform.c
@@ -17,6 +17,7 @@
 #include <sbi/sbi_string.h>
 #include <sbi/sbi_system.h>
 #include <sbi/sbi_tlb.h>
+#include <sbi_utils/cache/fdt_cmo_helper.h>
 #include <sbi_utils/fdt/fdt_domain.h>
 #include <sbi_utils/fdt/fdt_driver.h>
 #include <sbi_utils/fdt/fdt_fixup.h>
@@ -231,7 +232,7 @@ int generic_early_init(bool cold_boot)
 		fdt_driver_init_all(fdt, fdt_early_drivers);
 	}
 
-	return 0;
+	return fdt_cmo_init(cold_boot);
 }
 
 int generic_final_init(bool cold_boot)
-- 
2.17.1



From nick.hu at sifive.com  Tue Aug 19 20:32:44 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:44 +0800
Subject: [PATCH v4 05/11] lib: sbi: Add SiFive proprietary xsfcflushdlone
In-Reply-To: <20250820033250.544-1-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com>
Message-ID: <20250820033250.544-6-nick.hu@sifive.com>

Using ISA string "xsfcflushdlone" to detect the support of the
SiFive L1D cache flush custom instruction.

Signed-off-by: Nick Hu <nick.hu at sifive.com>
Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
---
 include/sbi/sbi_hart.h | 2 ++
 lib/sbi/sbi_hart.c     | 1 +
 2 files changed, 3 insertions(+)

diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index 82b19dcf..fdcf400a 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -81,6 +81,8 @@ enum sbi_hart_extensions {
 	SBI_HART_EXT_SSCTR,
 	/** HART has Ssstateen extension **/
 	SBI_HART_EXT_SSSTATEEN,
+	/** Hart has Xsfcflushdlone extension */
+	SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1,
 
 	/** Maximum index of Hart extension */
 	SBI_HART_EXT_MAX,
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 6a2d7d6f..4160ad6c 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -715,6 +715,7 @@ const struct sbi_hart_ext_data sbi_hart_ext[] = {
 	__SBI_HART_EXT_DATA(smctr, SBI_HART_EXT_SMCTR),
 	__SBI_HART_EXT_DATA(ssctr, SBI_HART_EXT_SSCTR),
 	__SBI_HART_EXT_DATA(ssstateen, SBI_HART_EXT_SSSTATEEN),
+	__SBI_HART_EXT_DATA(xsfcflushdlone, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1),
 };
 
 _Static_assert(SBI_HART_EXT_MAX == array_size(sbi_hart_ext),
-- 
2.17.1



From nick.hu at sifive.com  Tue Aug 19 20:32:45 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:45 +0800
Subject: [PATCH v4 06/11] lib: sbi: Add SiFive proprietary xsfcease
In-Reply-To: <20250820033250.544-1-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com>
Message-ID: <20250820033250.544-7-nick.hu@sifive.com>

Using ISA string "xsfcease" to detect the support of the custom
instruction "CEASE".

Signed-off-by: Nick Hu <nick.hu at sifive.com>
Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
---
 include/sbi/sbi_hart.h | 2 ++
 lib/sbi/sbi_hart.c     | 1 +
 2 files changed, 3 insertions(+)

diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index fdcf400a..ff682fb4 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -83,6 +83,8 @@ enum sbi_hart_extensions {
 	SBI_HART_EXT_SSSTATEEN,
 	/** Hart has Xsfcflushdlone extension */
 	SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1,
+	/** Hart has Xsfcease extension */
+	SBI_HART_EXT_XSIFIVE_CEASE,
 
 	/** Maximum index of Hart extension */
 	SBI_HART_EXT_MAX,
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 4160ad6c..2519f3f0 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -716,6 +716,7 @@ const struct sbi_hart_ext_data sbi_hart_ext[] = {
 	__SBI_HART_EXT_DATA(ssctr, SBI_HART_EXT_SSCTR),
 	__SBI_HART_EXT_DATA(ssstateen, SBI_HART_EXT_SSSTATEEN),
 	__SBI_HART_EXT_DATA(xsfcflushdlone, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1),
+	__SBI_HART_EXT_DATA(xsfcease, SBI_HART_EXT_XSIFIVE_CEASE),
 };
 
 _Static_assert(SBI_HART_EXT_MAX == array_size(sbi_hart_ext),
-- 
2.17.1



From nick.hu at sifive.com  Tue Aug 19 20:32:46 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:46 +0800
Subject: [PATCH v4 07/11] lib: utils/ipi: Exposing the ACLINT IPI device
In-Reply-To: <20250820033250.544-1-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com>
Message-ID: <20250820033250.544-8-nick.hu@sifive.com>

Exposing the ACLINT IPI device so the other driver can send the CLINT
IPI on the platform with IMSIC.

Signed-off-by: Nick Hu <nick.hu at sifive.com>
Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
---
 include/sbi_utils/ipi/aclint_mswi.h | 1 +
 lib/utils/ipi/aclint_mswi.c         | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/include/sbi_utils/ipi/aclint_mswi.h b/include/sbi_utils/ipi/aclint_mswi.h
index 4b8249f2..311228eb 100644
--- a/include/sbi_utils/ipi/aclint_mswi.h
+++ b/include/sbi_utils/ipi/aclint_mswi.h
@@ -26,6 +26,7 @@ struct aclint_mswi_data {
 	u32 hart_count;
 };
 
+struct sbi_ipi_device *aclint_mswi_get(void);
 int aclint_mswi_cold_init(struct aclint_mswi_data *mswi);
 
 #endif
diff --git a/lib/utils/ipi/aclint_mswi.c b/lib/utils/ipi/aclint_mswi.c
index 9e55078a..a4173b7c 100644
--- a/lib/utils/ipi/aclint_mswi.c
+++ b/lib/utils/ipi/aclint_mswi.c
@@ -66,6 +66,11 @@ static struct sbi_ipi_device aclint_mswi = {
 	.ipi_clear = mswi_ipi_clear
 };
 
+struct sbi_ipi_device *aclint_mswi_get(void)
+{
+	return &aclint_mswi;
+}
+
 int aclint_mswi_cold_init(struct aclint_mswi_data *mswi)
 {
 	u32 i;
-- 
2.17.1



From nick.hu at sifive.com  Tue Aug 19 20:32:47 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:47 +0800
Subject: [PATCH v4 08/11] lib: utils/irqchip: Add APLIC restore function
In-Reply-To: <20250820033250.544-1-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com>
Message-ID: <20250820033250.544-9-nick.hu@sifive.com>

Since the APLIC may enter a reset state upon system wake-up from a
platform low power state, adding a restore function to reinitialize
the APLIC.

Signed-off-by: Nick Hu <nick.hu at sifive.com>
Reviewed-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
---
 include/sbi_utils/irqchip/aplic.h |   3 +
 lib/utils/irqchip/aplic.c         | 160 +++++++++++++++++-------------
 2 files changed, 96 insertions(+), 67 deletions(-)

diff --git a/include/sbi_utils/irqchip/aplic.h b/include/sbi_utils/irqchip/aplic.h
index e31f48a4..ca606d06 100644
--- a/include/sbi_utils/irqchip/aplic.h
+++ b/include/sbi_utils/irqchip/aplic.h
@@ -33,6 +33,7 @@ struct aplic_delegate_data {
 struct aplic_data {
 	/* Private members */
 	struct sbi_irqchip_device irqchip;
+	struct sbi_dlist node;
 	/* Public members */
 	unsigned long addr;
 	unsigned long size;
@@ -48,4 +49,6 @@ struct aplic_data {
 
 int aplic_cold_irqchip_init(struct aplic_data *aplic);
 
+void aplic_restore(void);
+
 #endif
diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
index 72906d5d..68f5d107 100644
--- a/lib/utils/irqchip/aplic.c
+++ b/lib/utils/irqchip/aplic.c
@@ -115,6 +115,88 @@
 #define APLIC_DISABLE_ITHRESHOLD	1
 #define APLIC_ENABLE_ITHRESHOLD		0
 
+static SBI_LIST_HEAD(aplic_list);
+static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
+				void *msicfgaddr, void *msicfgaddrH);
+
+static void aplic_init(struct aplic_data *aplic)
+{
+	u32 i, j, tmp;
+	struct aplic_delegate_data *deleg;
+
+	/* Set domain configuration to 0 */
+	writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
+
+	/* Disable all interrupts */
+	for (i = 0; i <= aplic->num_source; i += 32)
+		writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
+				     (i / 32) * sizeof(u32)));
+
+	/* Set interrupt type and priority for all interrupts */
+	for (i = 1; i <= aplic->num_source; i++) {
+		/* Set IRQ source configuration to 0 */
+		writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
+			  (i - 1) * sizeof(u32)));
+		/* Set IRQ target hart index and priority to 1 */
+		writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
+						APLIC_TARGET_BASE +
+						(i - 1) * sizeof(u32)));
+	}
+
+	/* Configure IRQ delegation */
+	for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
+		deleg = &aplic->delegate[i];
+		if (!deleg->first_irq || !deleg->last_irq)
+			continue;
+		if (aplic->num_source < deleg->first_irq ||
+		    aplic->num_source < deleg->last_irq)
+			continue;
+		if (deleg->child_index > APLIC_SOURCECFG_CHILDIDX_MASK)
+			continue;
+		if (deleg->first_irq > deleg->last_irq) {
+			tmp = deleg->first_irq;
+			deleg->first_irq = deleg->last_irq;
+			deleg->last_irq = tmp;
+		}
+		for (j = deleg->first_irq; j <= deleg->last_irq; j++)
+			writel(APLIC_SOURCECFG_D | deleg->child_index,
+			       (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
+			       (j - 1) * sizeof(u32)));
+	}
+
+	/* Default initialization of IDC structures */
+	for (i = 0; i < aplic->num_idc; i++) {
+		writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
+				   i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
+		writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
+				   i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
+		writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
+						  APLIC_IDC_BASE +
+						  (i * APLIC_IDC_SIZE) +
+						  APLIC_IDC_ITHRESHOLD));
+	}
+
+	/* MSI configuration */
+	if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
+		aplic_writel_msicfg(&aplic->msicfg_mmode,
+				    (void *)(aplic->addr + APLIC_MMSICFGADDR),
+				    (void *)(aplic->addr + APLIC_MMSICFGADDRH));
+	}
+	if (aplic->targets_mmode && aplic->has_msicfg_smode) {
+		aplic_writel_msicfg(&aplic->msicfg_smode,
+				    (void *)(aplic->addr + APLIC_SMSICFGADDR),
+				    (void *)(aplic->addr + APLIC_SMSICFGADDRH));
+	}
+}
+
+void aplic_restore(void)
+{
+	struct aplic_data *aplic;
+
+	sbi_list_for_each_entry(aplic, &aplic_list, node)
+		aplic_init(aplic);
+}
+
 static void aplic_writel_msicfg(struct aplic_msicfg_data *msicfg,
 				void *msicfgaddr, void *msicfgaddrH)
 {
@@ -168,9 +250,8 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
 int aplic_cold_irqchip_init(struct aplic_data *aplic)
 {
 	int rc;
-	u32 i, j, tmp;
 	struct aplic_delegate_data *deleg;
-	u32 first_deleg_irq, last_deleg_irq;
+	u32 first_deleg_irq, last_deleg_irq, i;
 
 	/* Sanity checks */
 	if (!aplic ||
@@ -188,81 +269,23 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
 			return rc;
 	}
 
-	/* Set domain configuration to 0 */
-	writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
-
-	/* Disable all interrupts */
-	for (i = 0; i <= aplic->num_source; i += 32)
-		writel(-1U, (void *)(aplic->addr + APLIC_CLRIE_BASE +
-				     (i / 32) * sizeof(u32)));
-
-	/* Set interrupt type and priority for all interrupts */
-	for (i = 1; i <= aplic->num_source; i++) {
-		/* Set IRQ source configuration to 0 */
-		writel(0, (void *)(aplic->addr + APLIC_SOURCECFG_BASE +
-			  (i - 1) * sizeof(u32)));
-		/* Set IRQ target hart index and priority to 1 */
-		writel(APLIC_DEFAULT_PRIORITY, (void *)(aplic->addr +
-						APLIC_TARGET_BASE +
-						(i - 1) * sizeof(u32)));
-	}
+	/* Init the APLIC registers */
+	aplic_init(aplic);
 
-	/* Configure IRQ delegation */
+	/*
+	 * Add APLIC region to the root domain if:
+	 * 1) It targets M-mode of any HART directly or via MSIs
+	 * 2) All interrupts are delegated to some child APLIC
+	 */
 	first_deleg_irq = -1U;
 	last_deleg_irq = 0;
 	for (i = 0; i < APLIC_MAX_DELEGATE; i++) {
 		deleg = &aplic->delegate[i];
-		if (!deleg->first_irq || !deleg->last_irq)
-			continue;
-		if (aplic->num_source < deleg->first_irq ||
-		    aplic->num_source < deleg->last_irq)
-			continue;
-		if (APLIC_SOURCECFG_CHILDIDX_MASK < deleg->child_index)
-			continue;
-		if (deleg->first_irq > deleg->last_irq) {
-			tmp = deleg->first_irq;
-			deleg->first_irq = deleg->last_irq;
-			deleg->last_irq = tmp;
-		}
 		if (deleg->first_irq < first_deleg_irq)
 			first_deleg_irq = deleg->first_irq;
 		if (last_deleg_irq < deleg->last_irq)
 			last_deleg_irq = deleg->last_irq;
-		for (j = deleg->first_irq; j <= deleg->last_irq; j++)
-			writel(APLIC_SOURCECFG_D | deleg->child_index,
-				(void *)(aplic->addr + APLIC_SOURCECFG_BASE +
-				(j - 1) * sizeof(u32)));
-	}
-
-	/* Default initialization of IDC structures */
-	for (i = 0; i < aplic->num_idc; i++) {
-		writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
-			  i * APLIC_IDC_SIZE + APLIC_IDC_IDELIVERY));
-		writel(0, (void *)(aplic->addr + APLIC_IDC_BASE +
-			  i * APLIC_IDC_SIZE + APLIC_IDC_IFORCE));
-		writel(APLIC_DISABLE_ITHRESHOLD, (void *)(aplic->addr +
-						  APLIC_IDC_BASE +
-						  (i * APLIC_IDC_SIZE) +
-						  APLIC_IDC_ITHRESHOLD));
-	}
-
-	/* MSI configuration */
-	if (aplic->targets_mmode && aplic->has_msicfg_mmode) {
-		aplic_writel_msicfg(&aplic->msicfg_mmode,
-				(void *)(aplic->addr + APLIC_MMSICFGADDR),
-				(void *)(aplic->addr + APLIC_MMSICFGADDRH));
-	}
-	if (aplic->targets_mmode && aplic->has_msicfg_smode) {
-		aplic_writel_msicfg(&aplic->msicfg_smode,
-				(void *)(aplic->addr + APLIC_SMSICFGADDR),
-				(void *)(aplic->addr + APLIC_SMSICFGADDRH));
 	}
-
-	/*
-	 * Add APLIC region to the root domain if:
-	 * 1) It targets M-mode of any HART directly or via MSIs
-	 * 2) All interrupts are delegated to some child APLIC
-	 */
 	if (aplic->targets_mmode ||
 	    ((first_deleg_irq < last_deleg_irq) &&
 	    (last_deleg_irq == aplic->num_source) &&
@@ -278,5 +301,8 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
 	/* Register irqchip device */
 	sbi_irqchip_add_device(&aplic->irqchip);
 
+	/* Attach to the aplic list */
+	sbi_list_add_tail(&aplic->node, &aplic_list);
+
 	return 0;
 }
-- 
2.17.1



From nick.hu at sifive.com  Tue Aug 19 20:32:48 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:48 +0800
Subject: [PATCH v4 09/11] platform: sifive: Add SiFive TMC0 driver
In-Reply-To: <20250820033250.544-1-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com>
Message-ID: <20250820033250.544-10-nick.hu@sifive.com>

The SiFive TMC0 controls the tile power domains on SiFive platform. The
CPU enters the low power state via the `CEASE` instruction after
configuring the TMC0. Any devices that inside the tile power domain will
be power gated, including the private cache. Therefore flushing the
private cache before entering the low power state.

Co-developed-by: Vincent Chen <vincent.chen at sifive.com>
Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
Signed-off-by: Nick Hu <nick.hu at sifive.com>
Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
---
 include/sbi_utils/hsm/fdt_hsm_sifive_inst.h   |  20 +
 include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h   |  16 +
 lib/utils/hsm/Kconfig                         |   5 +
 lib/utils/hsm/fdt_hsm_sifive_tmc0.c           | 380 ++++++++++++++++++
 lib/utils/hsm/objects.mk                      |   2 +
 platform/generic/Kconfig                      |   5 +
 platform/generic/configs/defconfig            |   2 +
 platform/generic/sifive/objects.mk            |   3 +
 platform/generic/sifive/sifive_dev_platform.c |  57 +++
 9 files changed, 490 insertions(+)
 create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
 create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
 create mode 100644 lib/utils/hsm/fdt_hsm_sifive_tmc0.c
 create mode 100644 platform/generic/sifive/sifive_dev_platform.c

diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h b/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
new file mode 100644
index 00000000..de8aba19
--- /dev/null
+++ b/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
@@ -0,0 +1,20 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#ifndef __FDT_HSM_SIFIVE_INST_H__
+#define __FDT_HSM_SIFIVE_INST_H__
+
+static inline void sifive_cease(void)
+{
+	__asm__ __volatile__(".insn 0x30500073" ::: "memory");
+}
+
+static inline void sifive_cflush(void)
+{
+	__asm__ __volatile__(".insn 0xfc000073" ::: "memory");
+}
+
+#endif
diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
new file mode 100644
index 00000000..4ba048b9
--- /dev/null
+++ b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
@@ -0,0 +1,16 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#ifndef __FDT_HSM_SIFIVE_TMC0_H__
+#define __FDT_HSM_SIFIVE_TMC0_H__
+
+#ifdef CONFIG_FDT_HSM_SIFIVE_TMC0
+int fdt_hsm_sifive_tmc0_cold_init(void);
+#else
+static inline int fdt_hsm_sifive_tmc0_cold_init(void) { return 0; }
+#endif
+
+#endif
diff --git a/lib/utils/hsm/Kconfig b/lib/utils/hsm/Kconfig
index 1ad7958f..3e6f8909 100644
--- a/lib/utils/hsm/Kconfig
+++ b/lib/utils/hsm/Kconfig
@@ -14,6 +14,11 @@ config FDT_HSM_RPMI
 	depends on FDT_MAILBOX && RPMI_MAILBOX
 	default n
 
+config FDT_HSM_SIFIVE_TMC0
+	bool "FDT SiFive TMC v0 driver"
+	depends on PLATFORM_SIFIVE_DEV
+	default n
+
 endif
 
 endmenu
diff --git a/lib/utils/hsm/fdt_hsm_sifive_tmc0.c b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
new file mode 100644
index 00000000..83f86c88
--- /dev/null
+++ b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
@@ -0,0 +1,380 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive
+ */
+
+#include <libfdt.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_bitops.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_heap.h>
+#include <sbi/sbi_hsm.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi_utils/cache/fdt_cmo_helper.h>
+#include <sbi_utils/fdt/fdt_driver.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
+#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
+#include <sbi_utils/ipi/aclint_mswi.h>
+
+struct sifive_tmc0 {
+	unsigned long reg;
+	struct sbi_dlist node;
+	u32 id;
+};
+
+static SBI_LIST_HEAD(tmc0_list);
+static unsigned long tmc0_offset;
+
+#define tmc0_ptr_get(__scratch)				\
+	sbi_scratch_read_type((__scratch), struct sifive_tmc0 *, tmc0_offset)
+
+#define tmc0_ptr_set(__scratch, __tmc0)			\
+	sbi_scratch_write_type((__scratch), struct sifive_tmc0 *, tmc0_offset, (__tmc0))
+
+/* TMC.PGPREP */
+#define SIFIVE_TMC_PGPREP_OFF			0x0
+#define SIFIVE_TMC_PGPREP_ENA_REQ		BIT(31)
+#define SIFIVE_TMC_PGPREP_ENA_ACK		BIT(30)
+#define SIFIVE_TMC_PGPREP_DIS_REQ		BIT(29)
+#define SIFIVE_TMC_PGPREP_DIS_ACK		BIT(28)
+#define SIFIVE_TMC_PGPREP_CLFPNOTQ		BIT(18)
+#define SIFIVE_TMC_PGPREP_PMCENAERR		BIT(17)
+#define SIFIVE_TMC_PGPREP_PMCDENY		BIT(16)
+#define SIFIVE_TMC_PGPREP_BUSERR		BIT(15)
+#define SIFIVE_TMC_PGPREP_WAKE_DETECT		BIT(12)
+#define SIFIVE_TMC_PGPREP_INTERNAL_ABORT	BIT(2)
+#define SIFIVE_TMC_PGPREP_ENARSP		(SIFIVE_TMC_PGPREP_CLFPNOTQ | \
+						 SIFIVE_TMC_PGPREP_PMCENAERR | \
+						 SIFIVE_TMC_PGPREP_PMCDENY | \
+						 SIFIVE_TMC_PGPREP_BUSERR | \
+						 SIFIVE_TMC_PGPREP_WAKE_DETECT)
+
+/* TMC.PG */
+#define SIFIVE_TMC_PG_OFF			0x4
+#define SIFIVE_TMC_PG_ENA_REQ			BIT(31)
+#define SIFIVE_TMC_PG_ENA_ACK			BIT(30)
+#define SIFIVE_TMC_PG_DIS_REQ			BIT(29)
+#define SIFIVE_TMC_PG_DIS_ACK			BIT(28)
+#define SIFIVE_TMC_PG_PMC_ENA_ERR		BIT(17)
+#define SIFIVE_TMC_PG_PMC_DENY			BIT(16)
+#define SIFIVE_TMC_PG_BUS_ERR			BIT(15)
+#define SIFIVE_TMC_PG_MASTNOTQ			BIT(14)
+#define SIFIVE_TMC_PG_WARM_RESET		BIT(1)
+#define SIFIVE_TMC_PG_ENARSP			(SIFIVE_TMC_PG_PMC_ENA_ERR | \
+						 SIFIVE_TMC_PG_PMC_DENY | \
+						 SIFIVE_TMC_PG_BUS_ERR | \
+						 SIFIVE_TMC_PG_MASTNOTQ)
+
+/* TMC.RESUMEPC */
+#define SIFIVE_TMC_RESUMEPC_LO			0x10
+#define SIFIVE_TMC_RESUMEPC_HI			0x14
+
+/* TMC.WAKEMASK */
+#define SIFIVE_TMC_WAKE_MASK_OFF		0x20
+#define SIFIVE_TMC_WAKE_MASK_WREQ		BIT(31)
+#define SIFIVE_TMC_WAKE_MASK_ACK		BIT(30)
+
+static void sifive_tmc0_set_resumepc(physical_addr_t addr)
+{
+	struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
+
+	writel((u32)addr, (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_LO));
+#if __riscv_xlen > 32
+	writel((u32)(addr >> 32), (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_HI));
+#endif
+}
+
+static u32 sifive_tmc0_set_pgprep_enareq(void)
+{
+	struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
+	unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
+	u32 v = readl((void *)reg);
+
+	writel(v | SIFIVE_TMC_PGPREP_ENA_REQ, (void *)reg);
+	while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_ENA_ACK));
+
+	v = readl((void *)reg);
+	return v & SIFIVE_TMC_PGPREP_INTERNAL_ABORT;
+}
+
+static void sifive_tmc0_set_pgprep_disreq(void)
+{
+	struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
+	unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
+	u32 v = readl((void *)reg);
+
+	writel(v | SIFIVE_TMC_PGPREP_DIS_REQ, (void *)reg);
+	while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_DIS_ACK));
+}
+
+static u32 sifive_tmc0_get_pgprep_enarsp(void)
+{
+	struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
+	unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
+	u32 v = readl((void *)reg);
+
+	return v & SIFIVE_TMC_PGPREP_ENARSP;
+}
+
+static void sifive_tmc0_set_pg_enareq(void)
+{
+	struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
+	unsigned long reg = tmc0->reg + SIFIVE_TMC_PG_OFF;
+	u32 v = readl((void *)reg);
+
+	writel(v | SIFIVE_TMC_PG_ENA_REQ, (void *)reg);
+}
+
+static int sifive_tmc0_prep(void)
+{
+	struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+	u32 rc;
+
+	if (!tmc0_ptr_get(scratch))
+		return SBI_ENODEV;
+
+	rc = sifive_tmc0_set_pgprep_enareq();
+	if (rc) {
+		sbi_printf("TMC0 error: Internal Abort (Wake detect)\n");
+		goto fail;
+	}
+
+	rc = sifive_tmc0_get_pgprep_enarsp();
+	if (rc) {
+		sifive_tmc0_set_pgprep_disreq();
+		sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
+		goto fail;
+	}
+
+	sifive_tmc0_set_resumepc(scratch->warmboot_addr);
+
+	return SBI_OK;
+
+fail:
+	return SBI_EFAIL;
+}
+
+static int sifive_tmc0_enter(void)
+{
+	struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+	u32 rc;
+
+	/* Flush cache and check if there is wake detect or bus error */
+	if (fdt_cmo_private_flc_flush_all() &&
+	    sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1))
+		sifive_cflush();
+
+	rc = sifive_tmc0_get_pgprep_enarsp();
+	if (rc) {
+		sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
+		goto fail;
+	}
+
+	if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CEASE)) {
+		sifive_tmc0_set_pg_enareq();
+		while (1)
+			sifive_cease();
+	}
+
+	rc = SBI_ENOTSUPP;
+fail:
+	sifive_tmc0_set_pgprep_disreq();
+	return rc;
+}
+
+static int sifive_tmc0_tile_pg(void)
+{
+	int rc;
+
+	rc = sifive_tmc0_prep();
+	if (rc)
+		return rc;
+
+	return sifive_tmc0_enter();
+}
+
+static struct sifive_tmc0 *sifive_tmc0_find(u32 id)
+{
+	struct sifive_tmc0 *tmc0;
+
+	sbi_list_for_each_entry(tmc0, &tmc0_list, node) {
+		if (tmc0->id == id)
+			return tmc0;
+	}
+
+	return NULL;
+}
+
+static int sifive_tmc0_add(struct sifive_tmc0 *tmc0)
+{
+	if (!tmc0)
+		return SBI_ENODEV;
+
+	if (sifive_tmc0_find(tmc0->id))
+		return SBI_EALREADY;
+
+	sbi_list_add(&tmc0->node, &tmc0_list);
+
+	return SBI_OK;
+}
+
+static int sifive_tmc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
+{
+	struct sifive_tmc0 *tmc0;
+	int rc;
+	u64 addr;
+
+	tmc0 = sbi_zalloc(sizeof(*tmc0));
+	if (!tmc0)
+		return SBI_ENOMEM;
+
+	rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
+	if (rc)
+		goto free_tmc0;
+
+	tmc0->reg = (unsigned long)addr;
+	tmc0->id = nodeoff;
+
+	rc = sifive_tmc0_add(tmc0);
+	if (rc)
+		goto free_tmc0;
+
+	return SBI_OK;
+
+free_tmc0:
+	sbi_free(tmc0);
+	return rc;
+}
+
+static const struct fdt_match sifive_tmc0_match[] = {
+	{ .compatible = "sifive,tmc0" },
+	{ },
+};
+
+const struct fdt_driver fdt_hsm_sifive_tmc0 = {
+	.match_table = sifive_tmc0_match,
+	.init = sifive_tmc0_probe,
+};
+
+static const struct fdt_driver *const fdt_hsm_sifive_tmc0_drivers[] = {
+	&fdt_hsm_sifive_tmc0,
+	NULL
+};
+
+static int fdt_sifive_tmc0_get(const void *fdt, int noff, struct sifive_tmc0 **out)
+{
+	struct sifive_tmc0 *tmc0;
+	int rc;
+
+	noff = fdt_node_offset_by_phandle(fdt, noff);
+	if (noff < 0)
+		return noff;
+
+	rc = fdt_driver_init_by_offset(fdt, noff, fdt_hsm_sifive_tmc0_drivers);
+	if (rc)
+		return rc;
+
+	tmc0 = sifive_tmc0_find(noff);
+	if (!tmc0)
+		return SBI_EFAIL;
+
+	if (out)
+		*out = tmc0;
+
+	return SBI_OK;
+}
+
+static int fdt_sifive_tmc0_cold_init(const void *fdt)
+{
+	struct sbi_scratch *scratch;
+	struct sifive_tmc0 *tmc0;
+	const fdt32_t *val;
+	int cpus_off, cpu_off, rc;
+	u32 hartid;
+
+	cpus_off = fdt_path_offset(fdt, "/cpus");
+	if (cpus_off < 0)
+		return SBI_ENOENT;
+
+	fdt_for_each_subnode(cpu_off, fdt, cpus_off) {
+		rc = fdt_parse_hart_id(fdt, cpu_off, &hartid);
+		if (rc)
+			continue;
+
+		val = fdt_getprop(fdt, cpu_off, "power-domains", NULL);
+		if (!val)
+			return SBI_ENOENT;
+
+		rc = fdt_sifive_tmc0_get(fdt, fdt32_to_cpu(val[0]), &tmc0);
+		if (rc)
+			return rc;
+
+		scratch = sbi_hartid_to_scratch(hartid);
+		if (!scratch)
+			continue;
+
+		tmc0_ptr_set(scratch, tmc0);
+	}
+
+	return SBI_OK;
+}
+
+static int sifive_tmc0_start(u32 hartid, ulong saddr)
+{
+	struct sbi_ipi_device *clint = aclint_mswi_get();
+
+	/*
+	 * In system suspend, the IMSIC will be reset in SiFive platform so
+	 * we use the CLINT IPI as the wake event.
+	 */
+	if (clint && clint->ipi_send)
+		clint->ipi_send(sbi_hartid_to_hartindex(hartid));
+	else
+		sbi_ipi_raw_send(sbi_hartid_to_hartindex(hartid));
+
+	return SBI_OK;
+}
+
+static int sifive_tmc0_stop(void)
+{
+	unsigned long mie = csr_read(CSR_MIE);
+	int rc;
+	// Set IPI as wake up source
+	csr_set(CSR_MIE, MIP_MEIP | MIP_MSIP);
+
+	rc = sifive_tmc0_tile_pg();
+	if (rc) {
+		csr_write(CSR_MIE, mie);
+		return rc;
+	}
+
+	return SBI_OK;
+}
+
+static struct sbi_hsm_device tmc0_hsm_dev = {
+	.name = "SiFive TMC0",
+	.hart_start = sifive_tmc0_start,
+	.hart_stop = sifive_tmc0_stop,
+};
+
+int fdt_hsm_sifive_tmc0_cold_init(void)
+{
+	int rc;
+
+	tmc0_offset = sbi_scratch_alloc_type_offset(struct sifive_tmc0 *);
+	if (!tmc0_offset)
+		return SBI_ENOMEM;
+
+	rc = fdt_sifive_tmc0_cold_init(fdt_get_address());
+	if (rc)
+		return rc;
+
+	sbi_hsm_set_device(&tmc0_hsm_dev);
+
+	return SBI_OK;
+}
diff --git a/lib/utils/hsm/objects.mk b/lib/utils/hsm/objects.mk
index c13d81f7..04f4a208 100644
--- a/lib/utils/hsm/objects.mk
+++ b/lib/utils/hsm/objects.mk
@@ -9,3 +9,5 @@
 
 carray-fdt_early_drivers-$(CONFIG_FDT_HSM_RPMI) += fdt_hsm_rpmi
 libsbiutils-objs-$(CONFIG_FDT_HSM_RPMI) += hsm/fdt_hsm_rpmi.o
+
+libsbiutils-objs-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += hsm/fdt_hsm_sifive_tmc0.o
diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
index a24d6ab2..20c25a83 100644
--- a/platform/generic/Kconfig
+++ b/platform/generic/Kconfig
@@ -43,6 +43,11 @@ config PLATFORM_RENESAS_RZFIVE
 	select ANDES_PMU
 	default n
 
+config PLATFORM_SIFIVE_DEV
+	bool "SiFive development platform support"
+	depends on FDT_CACHE
+	default n
+
 config PLATFORM_SIFIVE_FU540
 	bool "SiFive FU540 support"
 	default n
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 6b219cfb..837acd79 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -1,6 +1,7 @@
 CONFIG_PLATFORM_ALLWINNER_D1=y
 CONFIG_PLATFORM_ANDES_AE350=y
 CONFIG_PLATFORM_RENESAS_RZFIVE=y
+CONFIG_PLATFORM_SIFIVE_DEV=y
 CONFIG_PLATFORM_SIFIVE_FU540=y
 CONFIG_PLATFORM_SIFIVE_FU740=y
 CONFIG_PLATFORM_SOPHGO_SG2042=y
@@ -17,6 +18,7 @@ CONFIG_FDT_GPIO_SIFIVE=y
 CONFIG_FDT_GPIO_STARFIVE=y
 CONFIG_FDT_HSM=y
 CONFIG_FDT_HSM_RPMI=y
+CONFIG_FDT_HSM_SIFIVE_TMC0=y
 CONFIG_FDT_I2C=y
 CONFIG_FDT_I2C_SIFIVE=y
 CONFIG_FDT_I2C_DW=y
diff --git a/platform/generic/sifive/objects.mk b/platform/generic/sifive/objects.mk
index d75e444a..d32e1273 100644
--- a/platform/generic/sifive/objects.mk
+++ b/platform/generic/sifive/objects.mk
@@ -2,6 +2,9 @@
 # SPDX-License-Identifier: BSD-2-Clause
 #
 
+carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_DEV) += sifive_dev_platform
+platform-objs-$(CONFIG_PLATFORM_SIFIVE_DEV) += sifive/sifive_dev_platform.o
+
 carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive_fu540
 platform-objs-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive/fu540.o
 
diff --git a/platform/generic/sifive/sifive_dev_platform.c b/platform/generic/sifive/sifive_dev_platform.c
new file mode 100644
index 00000000..48774492
--- /dev/null
+++ b/platform/generic/sifive/sifive_dev_platform.c
@@ -0,0 +1,57 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#include <platform_override.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi_utils/cache/fdt_cmo_helper.h>
+#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
+#include <sbi_utils/ipi/aclint_mswi.h>
+
+static int sifive_early_init(bool cold_boot)
+{
+	int rc;
+
+	rc = generic_early_init(cold_boot);
+	if (rc)
+		return rc;
+
+	if (cold_boot) {
+		rc = fdt_hsm_sifive_tmc0_cold_init();
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+static int sifive_final_init(bool cold_boot)
+{
+	struct sbi_ipi_device *clint = aclint_mswi_get();
+
+	if (clint && clint->ipi_clear)
+		clint->ipi_clear();
+
+	return generic_final_init(cold_boot);
+}
+
+static int sifive_platform_init(const void *fdt, int nodeoff,
+				const struct fdt_match *match)
+{
+	generic_platform_ops.early_init = sifive_early_init;
+	generic_platform_ops.final_init = sifive_final_init;
+
+	return 0;
+}
+
+static const struct fdt_match sifive_dev_platform_match[] = {
+	{ .compatible = "sifive-dev" },
+	{ },
+};
+
+const struct fdt_driver sifive_dev_platform = {
+	.match_table = sifive_dev_platform_match,
+	.init = sifive_platform_init,
+};
-- 
2.17.1



From nick.hu at sifive.com  Tue Aug 19 20:32:49 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:49 +0800
Subject: [PATCH v4 10/11] lib: utils/timer: Expose timer update function
In-Reply-To: <20250820033250.544-1-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com>
Message-ID: <20250820033250.544-11-nick.hu@sifive.com>

Exposing the ACLINT timer update APIs so the user can update the mtimer
after waking up from the non-retentive suspend.

Signed-off-by: Nick Hu <nick.hu at sifive.com>
Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
---
 include/sbi_utils/timer/aclint_mtimer.h |  5 +++++
 lib/utils/timer/aclint_mtimer.c         | 28 ++++++++++++++++++-------
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/include/sbi_utils/timer/aclint_mtimer.h b/include/sbi_utils/timer/aclint_mtimer.h
index a245e13e..f8d2e5b4 100644
--- a/include/sbi_utils/timer/aclint_mtimer.h
+++ b/include/sbi_utils/timer/aclint_mtimer.h
@@ -42,6 +42,11 @@ struct aclint_mtimer_data {
 	void (*time_wr)(bool timecmp, u64 value, volatile u64 *addr);
 };
 
+struct aclint_mtimer_data *aclint_get_mtimer_data(void);
+
+void aclint_mtimer_update(struct aclint_mtimer_data *mt,
+			  struct aclint_mtimer_data *ref);
+
 void aclint_mtimer_sync(struct aclint_mtimer_data *mt);
 
 void aclint_mtimer_set_reference(struct aclint_mtimer_data *mt,
diff --git a/lib/utils/timer/aclint_mtimer.c b/lib/utils/timer/aclint_mtimer.c
index 3db3c3be..fd6189aa 100644
--- a/lib/utils/timer/aclint_mtimer.c
+++ b/lib/utils/timer/aclint_mtimer.c
@@ -109,28 +109,42 @@ static struct sbi_timer_device mtimer = {
 	.timer_event_stop = mtimer_event_stop
 };
 
-void aclint_mtimer_sync(struct aclint_mtimer_data *mt)
+struct aclint_mtimer_data *aclint_get_mtimer_data(void)
+{
+	return mtimer_get_hart_data_ptr(sbi_scratch_thishart_ptr());
+}
+
+void aclint_mtimer_update(struct aclint_mtimer_data *mt,
+			  struct aclint_mtimer_data *ref)
 {
 	u64 v1, v2, mv, delta;
 	u64 *mt_time_val, *ref_time_val;
-	struct aclint_mtimer_data *reference;
 
-	/* Sync-up non-shared MTIME if reference is available */
-	if (mt->has_shared_mtime || !mt->time_delta_reference)
+	if (!mt || !ref || !mt->time_rd || !mt->time_wr || !ref->time_rd)
 		return;
 
-	reference = mt->time_delta_reference;
 	mt_time_val = (void *)mt->mtime_addr;
-	ref_time_val = (void *)reference->mtime_addr;
+	ref_time_val = (void *)ref->mtime_addr;
 	if (!atomic_raw_xchg_ulong(&mt->time_delta_computed, 1)) {
 		v1 = mt->time_rd(mt_time_val);
-		mv = reference->time_rd(ref_time_val);
+		mv = ref->time_rd(ref_time_val);
 		v2 = mt->time_rd(mt_time_val);
 		delta = mv - ((v1 / 2) + (v2 / 2));
 		mt->time_wr(false, mt->time_rd(mt_time_val) + delta,
 			    mt_time_val);
 	}
+}
 
+void aclint_mtimer_sync(struct aclint_mtimer_data *mt)
+{
+	struct aclint_mtimer_data *reference;
+
+	/* Sync-up non-shared MTIME if reference is available */
+	if (mt->has_shared_mtime || !mt->time_delta_reference)
+		return;
+
+	reference = mt->time_delta_reference;
+	aclint_mtimer_update(mt, reference);
 }
 
 void aclint_mtimer_set_reference(struct aclint_mtimer_data *mt,
-- 
2.17.1



From nick.hu at sifive.com  Tue Aug 19 20:32:50 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Wed, 20 Aug 2025 11:32:50 +0800
Subject: [PATCH v4 11/11] platform: sifive: Add SiFive SMC0 driver
In-Reply-To: <20250820033250.544-1-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com>
Message-ID: <20250820033250.544-12-nick.hu@sifive.com>

The SiFive SMC0 controls the clock and power domain of the core complex
on the SiFive platform. The core complex enters the low power state
after the secondary cores enter the tile power gating and last core
execute the `CEASE` instruction with the corresponding SMC0
configurations. The devices that inside both tile power domain and core
complex power domain will be off, including caches and timer. Therefore
we need to flush the last level cache before entering the core complex
power gating and update the timer after waking up.

Signed-off-by: Nick Hu <nick.hu at sifive.com>
Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
---
 include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h   |   3 +
 .../suspend/fdt_suspend_sifive_smc0.h         |  18 +
 lib/utils/hsm/fdt_hsm_sifive_tmc0.c           |  88 +++++
 lib/utils/suspend/Kconfig                     |   4 +
 lib/utils/suspend/fdt_suspend_sifive_smc0.c   | 323 ++++++++++++++++++
 lib/utils/suspend/objects.mk                  |   3 +
 platform/generic/configs/defconfig            |   1 +
 7 files changed, 440 insertions(+)
 create mode 100644 include/sbi_utils/suspend/fdt_suspend_sifive_smc0.h
 create mode 100644 lib/utils/suspend/fdt_suspend_sifive_smc0.c

diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
index 4ba048b9..d370158a 100644
--- a/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
+++ b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
@@ -9,6 +9,9 @@
 
 #ifdef CONFIG_FDT_HSM_SIFIVE_TMC0
 int fdt_hsm_sifive_tmc0_cold_init(void);
+int sifive_tmc0_set_wakemask_enareq(u32 hartid);
+void sifive_tmc0_set_wakemask_disreq(u32 hartid);
+bool sifive_tmc0_is_pg(u32 hartid);
 #else
 static inline int fdt_hsm_sifive_tmc0_cold_init(void) { return 0; }
 #endif
diff --git a/include/sbi_utils/suspend/fdt_suspend_sifive_smc0.h b/include/sbi_utils/suspend/fdt_suspend_sifive_smc0.h
new file mode 100644
index 00000000..f092be52
--- /dev/null
+++ b/include/sbi_utils/suspend/fdt_suspend_sifive_smc0.h
@@ -0,0 +1,18 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#ifndef __FDT_SUSPEND_SIFIVE_SMC0_H__
+#define __FDT_SUSPEND_SIFIVE_SMC0_H__
+
+#ifdef CONFIG_FDT_SUSPEND_SIFIVE_SMC0
+bool sifive_smc0_check_warm_reset(void);
+void sifive_smc0_mtime_update(void);
+#else
+static inline bool sifive_smc0_check_warm_reset(void) { return false; }
+static inline void sifive_smc0_mtime_update(void) { return; }
+#endif
+
+#endif
diff --git a/lib/utils/hsm/fdt_hsm_sifive_tmc0.c b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
index 83f86c88..4a13fd4d 100644
--- a/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
+++ b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
@@ -20,6 +20,8 @@
 #include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
 #include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
 #include <sbi_utils/ipi/aclint_mswi.h>
+#include <sbi_utils/irqchip/aplic.h>
+#include <sbi_utils/suspend/fdt_suspend_sifive_smc0.h>
 
 struct sifive_tmc0 {
 	unsigned long reg;
@@ -79,6 +81,73 @@ static unsigned long tmc0_offset;
 #define SIFIVE_TMC_WAKE_MASK_WREQ		BIT(31)
 #define SIFIVE_TMC_WAKE_MASK_ACK		BIT(30)
 
+int sifive_tmc0_set_wakemask_enareq(u32 hartid)
+{
+	struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
+	struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
+	unsigned long addr;
+	u32 v;
+
+	if (!tmc0)
+		return SBI_ENODEV;
+
+	addr = tmc0->reg + SIFIVE_TMC_WAKE_MASK_OFF;
+	v = readl((void *)addr);
+	writel(v | SIFIVE_TMC_WAKE_MASK_WREQ, (void *)addr);
+
+	while (!(readl((void *)addr) & SIFIVE_TMC_WAKE_MASK_ACK));
+
+	return SBI_OK;
+}
+
+void sifive_tmc0_set_wakemask_disreq(u32 hartid)
+{
+	struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
+	struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
+	unsigned long addr;
+	u32 v;
+
+	if (!tmc0)
+		return;
+
+	addr = tmc0->reg + SIFIVE_TMC_WAKE_MASK_OFF;
+	v = readl((void *)addr);
+	writel(v & ~SIFIVE_TMC_WAKE_MASK_WREQ, (void *)addr);
+
+	while (readl((void *)addr) & SIFIVE_TMC_WAKE_MASK_ACK);
+}
+
+bool sifive_tmc0_is_pg(u32 hartid)
+{
+	struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
+	struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
+	unsigned long addr;
+	u32 v;
+
+	if (!tmc0)
+		return false;
+
+	addr = tmc0->reg + SIFIVE_TMC_PG_OFF;
+	v = readl((void *)addr);
+	if (!(v & SIFIVE_TMC_PG_ENA_ACK) ||
+	    (v & SIFIVE_TMC_PG_ENARSP) ||
+	    (v & SIFIVE_TMC_PG_DIS_REQ))
+		return false;
+
+	return true;
+}
+
+static bool sifive_tmc0_check_warm_reset(void)
+{
+	struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
+	unsigned long addr = tmc0->reg + SIFIVE_TMC_PG_OFF;
+
+	if (!tmc0)
+		return false;
+
+	return readl((void *)addr) & SIFIVE_TMC_PG_WARM_RESET ? true : false;
+}
+
 static void sifive_tmc0_set_resumepc(physical_addr_t addr)
 {
 	struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
@@ -356,10 +425,29 @@ static int sifive_tmc0_stop(void)
 	return SBI_OK;
 }
 
+static void sifive_pg_resume(void)
+{
+	/*
+	 * To simplify the implementation, the SW won't clear the warm
+	 * reset bit. If the system woken up from the Core Complex power
+	 * gating, the warm reset bit of the TMC0 will be clear. Therefore
+	 * we need to check the warm reset bit of the TMC0 first as the
+	 * Tile power gating won't clear the warm reset bit of the SMC0.
+	 */
+	if (sifive_tmc0_check_warm_reset())
+		return;
+
+	if (sifive_smc0_check_warm_reset()) {
+		aplic_restore();
+		sifive_smc0_mtime_update();
+	}
+}
+
 static struct sbi_hsm_device tmc0_hsm_dev = {
 	.name = "SiFive TMC0",
 	.hart_start = sifive_tmc0_start,
 	.hart_stop = sifive_tmc0_stop,
+	.hart_resume = sifive_pg_resume,
 };
 
 int fdt_hsm_sifive_tmc0_cold_init(void)
diff --git a/lib/utils/suspend/Kconfig b/lib/utils/suspend/Kconfig
index 2cbea75c..623e053f 100644
--- a/lib/utils/suspend/Kconfig
+++ b/lib/utils/suspend/Kconfig
@@ -14,6 +14,10 @@ config FDT_SUSPEND_RPMI
 	depends on FDT_MAILBOX && RPMI_MAILBOX
 	default n
 
+config FDT_SUSPEND_SIFIVE_SMC0
+	bool "FDT SIFIVE SMC0 suspend driver"
+	depends on FDT_HSM_SIFIVE_TMC0
+	default n
 endif
 
 endmenu
diff --git a/lib/utils/suspend/fdt_suspend_sifive_smc0.c b/lib/utils/suspend/fdt_suspend_sifive_smc0.c
new file mode 100644
index 00000000..005486b4
--- /dev/null
+++ b/lib/utils/suspend/fdt_suspend_sifive_smc0.c
@@ -0,0 +1,323 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive
+ */
+
+#include <libfdt.h>
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_domain.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_hsm.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_timer.h>
+#include <sbi_utils/cache/fdt_cmo_helper.h>
+#include <sbi_utils/fdt/fdt_driver.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
+#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
+#include <sbi_utils/suspend/fdt_suspend_sifive_smc0.h>
+#include <sbi_utils/timer/aclint_mtimer.h>
+
+#define SIFIVE_SMC_PGPREP_OFF			0x0
+#define SIFIVE_SMC_PG_OFF			0x4
+#define SIFIVE_SMC_CCTIMER_OFF			0xc
+#define SIFIVE_SMC_RESUMEPC_LO_OFF		0x10
+#define SIFIVE_SMC_RESUMEPC_HI_OFF		0x14
+#define SIFIVE_SMC_SYNC_PMC_OFF			0x24
+#define SIFIVE_SMC_CYCLECOUNT_LO_OFF		0x28
+#define SIFIVE_SMC_CYCLECOUNT_HI_OFF		0x2c
+#define SIFIVE_SMC_WFI_UNCORE_CG_OFF		0x50
+
+#define SIFIVE_SMC_PGPREP_ENA_REQ		BIT(31)
+#define SIFIVE_SMC_PGPREP_ENA_ACK		BIT(30)
+#define SIFIVE_SMC_PGPREP_DIS_REQ		BIT(29)
+#define SIFIVE_SMC_PGPREP_DIS_ACK		BIT(29)
+#define SIFIVE_SMC_PGPREP_FRONTNOTQ		BIT(19)
+#define SIFIVE_SMC_PGPREP_CLFPNOTQ		BIT(18)
+#define SIFIVE_SMC_PGPREP_PMCENAERR		BIT(17)
+#define SIFIVE_SMC_PGPREP_WAKE_DETECT		BIT(16)
+#define SIFIVE_SMC_PGPREP_BUSERR		BIT(15)
+#define SIFIVE_SMC_PGPREP_EARLY_ABORT		BIT(3)
+#define SIFIVE_SMC_PGPREP_INTERNAL_ABORT	BIT(2)
+#define SIFIVE_SMC_PGPREP_ENARSP		(SIFIVE_SMC_PGPREP_FRONTNOTQ | \
+						 SIFIVE_SMC_PGPREP_CLFPNOTQ | \
+						 SIFIVE_SMC_PGPREP_PMCENAERR | \
+						 SIFIVE_SMC_PGPREP_WAKE_DETECT | \
+						 SIFIVE_SMC_PGPREP_BUSERR)
+
+#define SIFIVE_SMC_PGPREP_ABORT			(SIFIVE_SMC_PGPREP_EARLY_ABORT | \
+						 SIFIVE_SMC_PGPREP_INTERNAL_ABORT)
+
+#define SIFIVE_SMC_PG_ENA_REQ			BIT(31)
+#define SIFIVE_SMC_PG_WARM_RESET		BIT(1)
+
+#define SIFIVE_SMC_SYNCPMC_SYNC_REQ		BIT(31)
+#define SIFIVE_SMC_SYNCPMC_SYNC_WREQ		BIT(30)
+#define SIFIVE_SMC_SYNCPMC_SYNC_ACK		BIT(29)
+
+static struct aclint_mtimer_data smc_sync_timer;
+static unsigned long smc0_base;
+
+static void sifive_smc0_set_pmcsync(char regid, bool write_mode)
+{
+	unsigned long addr = smc0_base + SIFIVE_SMC_SYNC_PMC_OFF;
+	u32 v = regid | SIFIVE_SMC_SYNCPMC_SYNC_REQ;
+
+	if (write_mode)
+		v |= SIFIVE_SMC_SYNCPMC_SYNC_WREQ;
+
+	writel(v, (void *)addr);
+	while (!(readl((void *)addr) & SIFIVE_SMC_SYNCPMC_SYNC_ACK));
+}
+
+static u64 sifive_smc0_time_read(volatile u64 *addr)
+{
+	u32 lo, hi;
+
+	do {
+		sifive_smc0_set_pmcsync(SIFIVE_SMC_CYCLECOUNT_LO_OFF, false);
+		sifive_smc0_set_pmcsync(SIFIVE_SMC_CYCLECOUNT_HI_OFF, false);
+		hi = readl_relaxed((u32 *)addr + 1);
+		lo = readl_relaxed((u32 *)addr);
+	} while (hi != readl_relaxed((u32 *)addr + 1));
+
+	return ((u64)hi << 32) | (u64)lo;
+}
+
+static void sifive_smc0_set_resumepc(physical_addr_t raddr)
+{
+	/* Set resumepc_lo */
+	writel((u32)raddr, (void *)(smc0_base + SIFIVE_SMC_RESUMEPC_LO_OFF));
+	/* copy resumepc_lo from SMC to PMC */
+	sifive_smc0_set_pmcsync(SIFIVE_SMC_RESUMEPC_LO_OFF, true);
+#if __riscv_xlen > 32
+	/* Set resumepc_hi */
+	writel((u32)(raddr >> 32), (void *)(smc0_base + SIFIVE_SMC_RESUMEPC_HI_OFF));
+	/* copy resumepc_hi from SMC to PMC */
+	sifive_smc0_set_pmcsync(SIFIVE_SMC_RESUMEPC_HI_OFF, true);
+#endif
+}
+
+static u32 sifive_smc0_get_pgprep_enarsp(void)
+{
+	u32 v = readl((void *)(smc0_base + SIFIVE_SMC_PGPREP_OFF));
+
+	return v & SIFIVE_SMC_PGPREP_ENARSP;
+}
+
+static void sifive_smc0_set_pgprep_disreq(void)
+{
+	unsigned long addr = smc0_base + SIFIVE_SMC_PGPREP_OFF;
+	u32 v = readl((void *)addr);
+
+	writel(v | SIFIVE_SMC_PGPREP_DIS_REQ, (void *)addr);
+	while (!(readl((void *)addr) & SIFIVE_SMC_PGPREP_DIS_ACK));
+}
+
+static u32 sifive_smc0_set_pgprep_enareq(void)
+{
+	unsigned long addr = smc0_base + SIFIVE_SMC_PGPREP_OFF;
+	u32 v = readl((void *)addr);
+
+	writel(v | SIFIVE_SMC_PGPREP_ENA_REQ, (void *)addr);
+	while (!(readl((void *)addr) & SIFIVE_SMC_PGPREP_ENA_ACK));
+
+	v = readl((void *)addr);
+
+	return v & SIFIVE_SMC_PGPREP_ABORT;
+}
+
+static void sifive_smc0_set_pg_enareq(void)
+{
+	unsigned long addr = smc0_base + SIFIVE_SMC_PG_OFF;
+	u32 v = readl((void *)addr);
+
+	writel(v | SIFIVE_SMC_PG_ENA_REQ, (void *)addr);
+}
+
+bool sifive_smc0_check_warm_reset(void)
+{
+	unsigned long addr = smc0_base + SIFIVE_SMC_PG_OFF;
+
+	if (!smc0_base)
+		return false;
+
+	sifive_smc0_set_pmcsync(SIFIVE_SMC_PG_OFF, false);
+
+	return readl((void *)addr) & SIFIVE_SMC_PG_WARM_RESET ? true : false;
+}
+
+static inline void sifive_smc0_set_cg(bool enable)
+{
+	unsigned long addr = smc0_base + SIFIVE_SMC_WFI_UNCORE_CG_OFF;
+
+	if (enable)
+		writel(0, (void *)addr);
+	else
+		writel(1, (void *)addr);
+}
+
+static int sifive_smc0_prep(void)
+{
+	const struct sbi_domain *dom = &root;
+	struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+	unsigned long i;
+	int rc;
+	u32 target;
+
+	if (!smc0_base)
+		return SBI_ENODEV;
+
+	/* Prevent all secondary tiles from waking up from PG state */
+	sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
+		target = sbi_hartindex_to_hartid(i);
+		if (target != current_hartid()) {
+			rc = sifive_tmc0_set_wakemask_enareq(target);
+			if (rc) {
+				sbi_printf("Fail to enable wakemask for hart %d\n",
+					   target);
+				goto fail;
+			}
+		}
+	}
+
+	/* Check if all secondary tiles enter PG state */
+	sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
+		target = sbi_hartindex_to_hartid(i);
+		if (target != current_hartid() &&
+		    !sifive_tmc0_is_pg(target)) {
+			sbi_printf("Hart %d not in the PG state\n", target);
+			goto fail;
+		}
+	}
+
+	rc = sifive_smc0_set_pgprep_enareq();
+	if (rc) {
+		sbi_printf("SMC0 error: abort code: 0x%x\n", rc);
+		goto fail;
+	}
+
+	rc = sifive_smc0_get_pgprep_enarsp();
+	if (rc) {
+		sifive_smc0_set_pgprep_disreq();
+		sbi_printf("SMC0 error: error response code: 0x%x\n", rc);
+		goto fail;
+	}
+
+	sifive_smc0_set_resumepc(scratch->warmboot_addr);
+	return SBI_OK;
+fail:
+	sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
+		target = sbi_hartindex_to_hartid(i);
+		if (target != current_hartid())
+			sifive_tmc0_set_wakemask_disreq(target);
+	}
+
+	return SBI_EFAIL;
+}
+
+static int sifive_smc0_enter(void)
+{
+	const struct sbi_domain *dom = &root;
+	struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
+	unsigned long i;
+	u32 target, rc;
+
+	/* Flush cache and check if there is wake detect or bus error */
+	if (fdt_cmo_llc_flush_all() &&
+	    sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1))
+		sifive_cflush();
+
+	rc = sifive_smc0_get_pgprep_enarsp();
+	if (rc) {
+		sbi_printf("SMC0 error: error response code: 0x%x\n", rc);
+		rc = SBI_EFAIL;
+		goto fail;
+	}
+
+	if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CEASE)) {
+		sifive_smc0_set_pg_enareq();
+		while (1)
+			sifive_cease();
+	}
+
+	rc = SBI_ENOTSUPP;
+fail:
+	sifive_smc0_set_pgprep_disreq();
+	sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
+		target = sbi_hartindex_to_hartid(i);
+		if (target != current_hartid())
+			sifive_tmc0_set_wakemask_disreq(target);
+	}
+	return rc;
+}
+
+static int sifive_smc0_pg(void)
+{
+	int rc;
+
+	rc = sifive_smc0_prep();
+	if (rc)
+		return rc;
+
+	return sifive_smc0_enter();
+}
+
+static int sifive_smc0_system_suspend(u32 sleep_type, unsigned long addr)
+{
+	/* Disable the timer interrupt */
+	sbi_timer_exit(sbi_scratch_thishart_ptr());
+
+	return sifive_smc0_pg();
+}
+
+static int sifive_smc0_system_suspend_check(u32 sleep_type)
+{
+	return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? SBI_OK : SBI_EINVAL;
+}
+
+static struct sbi_system_suspend_device smc0_sys_susp = {
+	.name = "Sifive SMC0",
+	.system_suspend_check = sifive_smc0_system_suspend_check,
+	.system_suspend = sifive_smc0_system_suspend,
+};
+
+void sifive_smc0_mtime_update(void)
+{
+	struct aclint_mtimer_data *mt = aclint_get_mtimer_data();
+
+	aclint_mtimer_update(mt, &smc_sync_timer);
+}
+
+static int sifive_smc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
+{
+	int rc;
+	u64 addr;
+
+	rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
+	if (rc)
+		return rc;
+
+	smc0_base = (unsigned long)addr;
+	smc_sync_timer.time_rd = sifive_smc0_time_read;
+	smc_sync_timer.mtime_addr = smc0_base + SIFIVE_SMC_CYCLECOUNT_LO_OFF;
+
+	sbi_system_suspend_set_device(&smc0_sys_susp);
+	sifive_smc0_set_cg(true);
+
+	return SBI_OK;
+}
+
+static const struct fdt_match sifive_smc0_match[] = {
+	{ .compatible = "sifive,smc0" },
+	{ },
+};
+
+const struct fdt_driver fdt_suspend_sifive_smc0 = {
+	.match_table = sifive_smc0_match,
+	.init = sifive_smc0_probe,
+};
diff --git a/lib/utils/suspend/objects.mk b/lib/utils/suspend/objects.mk
index 9c386248..1fb29b5e 100644
--- a/lib/utils/suspend/objects.mk
+++ b/lib/utils/suspend/objects.mk
@@ -9,3 +9,6 @@
 
 carray-fdt_early_drivers-$(CONFIG_FDT_SUSPEND_RPMI) += fdt_suspend_rpmi
 libsbiutils-objs-$(CONFIG_FDT_SUSPEND_RPMI) += suspend/fdt_suspend_rpmi.o
+
+carray-fdt_early_drivers-$(CONFIG_FDT_SUSPEND_SIFIVE_SMC0) += fdt_suspend_sifive_smc0
+libsbiutils-objs-$(CONFIG_FDT_SUSPEND_SIFIVE_SMC0) += suspend/fdt_suspend_sifive_smc0.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 837acd79..258988cc 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -55,6 +55,7 @@ CONFIG_FDT_SERIAL_XILINX_UARTLITE=y
 CONFIG_SERIAL_SEMIHOSTING=y
 CONFIG_FDT_SUSPEND=y
 CONFIG_FDT_SUSPEND_RPMI=y
+CONFIG_FDT_SUSPEND_SIFIVE_SMC0=y
 CONFIG_FDT_TIMER=y
 CONFIG_FDT_TIMER_MTIMER=y
 CONFIG_FDT_TIMER_PLMT=y
-- 
2.17.1



From wxjstz at 126.com  Tue Aug 19 21:03:38 2025
From: wxjstz at 126.com (Xiang W)
Date: Wed, 20 Aug 2025 12:03:38 +0800
Subject: [PATCH] lib: utils: fdt_helper: simplify
 fdt_parse_isa_extensions() helper
In-Reply-To: <20250815024434.14303-1-peter.lin@sifive.com>
References: <20250815024434.14303-1-peter.lin@sifive.com>
Message-ID: <7870307554f9366a85685402353ddd4cff83df46.camel@126.com>

? 2025-08-15?? 10:44 +0800?Yu-Chien Peter Lin???
> The fdt_isa_bitmap was previously used as a temporary array
> to store ISA extensions when parsing device-tree.
> To reduce scratch space consumption, set the ISA bitmap
> directly in hfeature->extensions, allows us to remove the
> fdt_parse_isa_all_harts() as fdt_parse_isa_extensions() can
> now handle the task directly.
> 
> This change makes the helper function more versatile, even
> before scratch space is initialized.
> 
> Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
NACK

Originally, the extensions parsed by fdt_parse_isa_extensions?
were related to hartid. After the modification, it will collect?
the extensions supported by all the HART.

To remove fdt_isa_bitmap_offset, call sbi_hart_update_extension?
in fdt_parse_isa_extensions_one_hart/fdt_parse_isa_one_hart

Regards,
Xiang W

> ---
> ?include/sbi_utils/fdt/fdt_helper.h |? 3 +-
> ?lib/utils/fdt/fdt_helper.c???????? | 45 ++----------------------------
> ?platform/generic/platform.c??????? |? 2 +-
> ?3 files changed, 4 insertions(+), 46 deletions(-)
> 
> diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h
> index 04c850cc..24ad1a94 100644
> --- a/include/sbi_utils/fdt/fdt_helper.h
> +++ b/include/sbi_utils/fdt/fdt_helper.h
> @@ -54,8 +54,7 @@ int fdt_parse_cbom_block_size(const void *fdt, int cpu_offset, unsigned long? *c
> ?
> ?int fdt_parse_timebase_frequency(const void *fdt, unsigned long *freq);
> ?
> -int fdt_parse_isa_extensions(const void *fdt, unsigned int hartid,
> -			???? unsigned long *extensions);
> +int fdt_parse_isa_extensions(const void *fdt, unsigned long *hart_exts);
> ?
> ?int fdt_parse_gaisler_uart_node(const void *fdt, int nodeoffset,
> ?				struct platform_uart_data *uart);
> diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
> index 0f4859c1..61a5962c 100644
> --- a/lib/utils/fdt/fdt_helper.c
> +++ b/lib/utils/fdt/fdt_helper.c
> @@ -324,8 +324,6 @@ int fdt_parse_timebase_frequency(const void *fdt, unsigned long *freq)
> ?
> ?#define RISCV_ISA_EXT_NAME_LEN_MAX	32
> ?
> -static unsigned long fdt_isa_bitmap_offset;
> -
> ?static int fdt_parse_isa_one_hart(const char *isa, unsigned long *extensions)
> ?{
> ?	size_t i, j, isa_len;
> @@ -405,15 +403,13 @@ static void fdt_parse_isa_extensions_one_hart(const char *isa,
> ?	}
> ?}
> ?
> -static int fdt_parse_isa_all_harts(const void *fdt)
> +int fdt_parse_isa_extensions(const void *fdt, unsigned long *hart_exts)
> ?{
> ?	u32 hartid;
> ?	const fdt32_t *val;
> -	unsigned long *hart_exts;
> -	struct sbi_scratch *scratch;
> ?	int err, cpu_offset, cpus_offset, len;
> ?
> -	if (!fdt || !fdt_isa_bitmap_offset)
> +	if (!fdt || !hart_exts)
> ?		return SBI_EINVAL;
> ?
> ?	cpus_offset = fdt_path_offset(fdt, "/cpus");
> @@ -428,13 +424,6 @@ static int fdt_parse_isa_all_harts(const void *fdt)
> ?		if (!fdt_node_is_enabled(fdt, cpu_offset))
> ?			continue;
> ?
> -		scratch = sbi_hartid_to_scratch(hartid);
> -		if (!scratch)
> -			return SBI_ENOENT;
> -
> -		hart_exts = sbi_scratch_offset_ptr(scratch,
> -						?? fdt_isa_bitmap_offset);
> -
> ?		val = fdt_getprop(fdt, cpu_offset, "riscv,isa-extensions", &len);
> ?		if (val && len > 0) {
> ?			fdt_parse_isa_extensions_one_hart((const char *)val,
> @@ -454,36 +443,6 @@ static int fdt_parse_isa_all_harts(const void *fdt)
> ?	return 0;
> ?}
> ?
> -int fdt_parse_isa_extensions(const void *fdt, unsigned int hartid,
> -			unsigned long *extensions)
> -{
> -	int rc, i;
> -	unsigned long *hart_exts;
> -	struct sbi_scratch *scratch;
> -
> -	if (!fdt_isa_bitmap_offset) {
> -		fdt_isa_bitmap_offset = sbi_scratch_alloc_offset(
> -					sizeof(*hart_exts) *
> -					BITS_TO_LONGS(SBI_HART_EXT_MAX));
> -		if (!fdt_isa_bitmap_offset)
> -			return SBI_ENOMEM;
> -
> -		rc = fdt_parse_isa_all_harts(fdt);
> -		if (rc)
> -			return rc;
> -	}
> -
> -	scratch = sbi_hartid_to_scratch(hartid);
> -	if (!scratch)
> -		return SBI_ENOENT;
> -
> -	hart_exts = sbi_scratch_offset_ptr(scratch, fdt_isa_bitmap_offset);
> -
> -	for (i = 0; i < BITS_TO_LONGS(SBI_HART_EXT_MAX); i++)
> -		extensions[i] |= hart_exts[i];
> -	return 0;
> -}
> -
> ?static int fdt_parse_uart_node_common(const void *fdt, int nodeoffset,
> ?				????? struct platform_uart_data *uart,
> ?				????? unsigned long default_freq,
> diff --git a/platform/generic/platform.c b/platform/generic/platform.c
> index 47e771ad..2e8c6051 100644
> --- a/platform/generic/platform.c
> +++ b/platform/generic/platform.c
> @@ -251,7 +251,7 @@ int generic_final_init(bool cold_boot)
> ?int generic_extensions_init(struct sbi_hart_features *hfeatures)
> ?{
> ?	/* Parse the ISA string from FDT and enable the listed extensions */
> -	return fdt_parse_isa_extensions(fdt_get_address(), current_hartid(),
> +	return fdt_parse_isa_extensions(fdt_get_address(),
> ?					hfeatures->extensions);
> ?}
> ?
> -- 
> 2.48.0
> 



From wxjstz at 126.com  Thu Aug 21 01:32:48 2025
From: wxjstz at 126.com (Xiang W)
Date: Thu, 21 Aug 2025 16:32:48 +0800
Subject: [PATCH 6/8] lib: sbi_domain: add SBI_DOMAIN_MEMREGION_FW
 memregion flag
In-Reply-To: <20250814110522.18809-7-peter.lin@sifive.com>
References: <20250814110522.18809-1-peter.lin@sifive.com>
	 <20250814110522.18809-7-peter.lin@sifive.com>
Message-ID: <fa5090abc7ed94f9e4f66913138644021c1e630a.camel@126.com>

? 2025-08-14?? 19:05 +0800?Yu-Chien Peter Lin???
> Add a new memregion flag, SBI_DOMAIN_MEMREGION_FW and mark the
> code and data sections of firmware.
> 
> Signed-off-by: Yu-Chien Peter Lin <peter.lin at sifive.com>
> ---
> ?include/sbi/sbi_domain.h | 1 +
> ?lib/sbi/sbi_domain.c???? | 8 ++++++--
> ?2 files changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/include/sbi/sbi_domain.h b/include/sbi/sbi_domain.h
> index 8a51f289..d71354c7 100644
> --- a/include/sbi/sbi_domain.h
> +++ b/include/sbi/sbi_domain.h
> @@ -157,6 +157,7 @@ struct sbi_domain_memregion {
> ?				 SBI_DOMAIN_MEMREGION_M_EXECUTABLE)
> ?
> ?#define SBI_DOMAIN_MEMREGION_MMIO		(1UL << 31)
> +#define SBI_DOMAIN_MEMREGION_FW			(1UL << 32)
Will overflow under RV32.

Regards,
Xiang W
> ?	unsigned long flags;
> ?};
> ?
> diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
> index d6566b12..ccfcc7f0 100644
> --- a/lib/sbi/sbi_domain.c
> +++ b/lib/sbi/sbi_domain.c
> @@ -541,6 +541,8 @@ void sbi_domain_dump(const struct sbi_domain *dom, const char *suffix)
> ?		sbi_printf("M: ");
> ?		if (reg->flags & SBI_DOMAIN_MEMREGION_MMIO)
> ?			sbi_printf("%cI", (k++) ? ',' : '(');
> +		if (reg->flags & SBI_DOMAIN_MEMREGION_FW)
> +			sbi_printf("%cF", (k++) ? ',' : '(');
> ?		if (reg->flags & SBI_DOMAIN_MEMREGION_M_READABLE)
> ?			sbi_printf("%cR", (k++) ? ',' : '(');
> ?		if (reg->flags & SBI_DOMAIN_MEMREGION_M_WRITABLE)
> @@ -894,13 +896,15 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
> ?	/* Root domain firmware memory region */
> ?	sbi_domain_memregion_init(scratch->fw_start, scratch->fw_rw_offset,
> ?				? (SBI_DOMAIN_MEMREGION_M_READABLE |
> -				?? SBI_DOMAIN_MEMREGION_M_EXECUTABLE),
> +				?? SBI_DOMAIN_MEMREGION_M_EXECUTABLE |
> +				?? SBI_DOMAIN_MEMREGION_FW),
> ?				? &root_memregs[root_memregs_count++]);
> ?
> ?	sbi_domain_memregion_init((scratch->fw_start + scratch->fw_rw_offset),
> ?				? (scratch->fw_size - scratch->fw_rw_offset),
> ?				? (SBI_DOMAIN_MEMREGION_M_READABLE |
> -				?? SBI_DOMAIN_MEMREGION_M_WRITABLE),
> +				?? SBI_DOMAIN_MEMREGION_M_WRITABLE |
> +				?? SBI_DOMAIN_MEMREGION_FW),
> ?				? &root_memregs[root_memregs_count++]);
> ?
> ?	root.fw_region_inited = true;
> -- 
> 2.39.3
> 



From anup at brainfault.org  Tue Aug 26 01:39:56 2025
From: anup at brainfault.org (Anup Patel)
Date: Tue, 26 Aug 2025 14:09:56 +0530
Subject: [PATCH v4 05/11] lib: sbi: Add SiFive proprietary xsfcflushdlone
In-Reply-To: <20250820033250.544-6-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com> <20250820033250.544-6-nick.hu@sifive.com>
Message-ID: <CAAhSdy33NgNSK4hS5rmjPko-m2hNyKPArGBpHEHacJez54dGfw@mail.gmail.com>

On Wed, Aug 20, 2025 at 9:03?AM Nick Hu <nick.hu at sifive.com> wrote:
>
> Using ISA string "xsfcflushdlone" to detect the support of the
> SiFive L1D cache flush custom instruction.
>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Cyan Yang <cyan.yang at sifive.com>

LGTM.

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

Regards,
Anup

> ---
>  include/sbi/sbi_hart.h | 2 ++
>  lib/sbi/sbi_hart.c     | 1 +
>  2 files changed, 3 insertions(+)
>
> diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
> index 82b19dcf..fdcf400a 100644
> --- a/include/sbi/sbi_hart.h
> +++ b/include/sbi/sbi_hart.h
> @@ -81,6 +81,8 @@ enum sbi_hart_extensions {
>         SBI_HART_EXT_SSCTR,
>         /** HART has Ssstateen extension **/
>         SBI_HART_EXT_SSSTATEEN,
> +       /** Hart has Xsfcflushdlone extension */
> +       SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1,
>
>         /** Maximum index of Hart extension */
>         SBI_HART_EXT_MAX,
> diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
> index 6a2d7d6f..4160ad6c 100644
> --- a/lib/sbi/sbi_hart.c
> +++ b/lib/sbi/sbi_hart.c
> @@ -715,6 +715,7 @@ const struct sbi_hart_ext_data sbi_hart_ext[] = {
>         __SBI_HART_EXT_DATA(smctr, SBI_HART_EXT_SMCTR),
>         __SBI_HART_EXT_DATA(ssctr, SBI_HART_EXT_SSCTR),
>         __SBI_HART_EXT_DATA(ssstateen, SBI_HART_EXT_SSSTATEEN),
> +       __SBI_HART_EXT_DATA(xsfcflushdlone, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1),
>  };
>
>  _Static_assert(SBI_HART_EXT_MAX == array_size(sbi_hart_ext),
> --
> 2.17.1
>


From anup at brainfault.org  Tue Aug 26 01:40:15 2025
From: anup at brainfault.org (Anup Patel)
Date: Tue, 26 Aug 2025 14:10:15 +0530
Subject: [PATCH v4 06/11] lib: sbi: Add SiFive proprietary xsfcease
In-Reply-To: <20250820033250.544-7-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com> <20250820033250.544-7-nick.hu@sifive.com>
Message-ID: <CAAhSdy30VWfob_xay4w34AAOD5TEfu5f--2D9knZ8r6kQfLQyw@mail.gmail.com>

On Wed, Aug 20, 2025 at 9:03?AM Nick Hu <nick.hu at sifive.com> wrote:
>
> Using ISA string "xsfcease" to detect the support of the custom
> instruction "CEASE".
>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Cyan Yang <cyan.yang at sifive.com>

LGTM.

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

Regards,
Anup

> ---
>  include/sbi/sbi_hart.h | 2 ++
>  lib/sbi/sbi_hart.c     | 1 +
>  2 files changed, 3 insertions(+)
>
> diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
> index fdcf400a..ff682fb4 100644
> --- a/include/sbi/sbi_hart.h
> +++ b/include/sbi/sbi_hart.h
> @@ -83,6 +83,8 @@ enum sbi_hart_extensions {
>         SBI_HART_EXT_SSSTATEEN,
>         /** Hart has Xsfcflushdlone extension */
>         SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1,
> +       /** Hart has Xsfcease extension */
> +       SBI_HART_EXT_XSIFIVE_CEASE,
>
>         /** Maximum index of Hart extension */
>         SBI_HART_EXT_MAX,
> diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
> index 4160ad6c..2519f3f0 100644
> --- a/lib/sbi/sbi_hart.c
> +++ b/lib/sbi/sbi_hart.c
> @@ -716,6 +716,7 @@ const struct sbi_hart_ext_data sbi_hart_ext[] = {
>         __SBI_HART_EXT_DATA(ssctr, SBI_HART_EXT_SSCTR),
>         __SBI_HART_EXT_DATA(ssstateen, SBI_HART_EXT_SSSTATEEN),
>         __SBI_HART_EXT_DATA(xsfcflushdlone, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1),
> +       __SBI_HART_EXT_DATA(xsfcease, SBI_HART_EXT_XSIFIVE_CEASE),
>  };
>
>  _Static_assert(SBI_HART_EXT_MAX == array_size(sbi_hart_ext),
> --
> 2.17.1
>


From anup at brainfault.org  Tue Aug 26 01:51:56 2025
From: anup at brainfault.org (Anup Patel)
Date: Tue, 26 Aug 2025 14:21:56 +0530
Subject: [PATCH v4 09/11] platform: sifive: Add SiFive TMC0 driver
In-Reply-To: <20250820033250.544-10-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com> <20250820033250.544-10-nick.hu@sifive.com>
Message-ID: <CAAhSdy2RzuFFcz87a_7N6UXCXYxkV=khhAa7jb2NpjceN5ijBw@mail.gmail.com>

On Wed, Aug 20, 2025 at 9:03?AM Nick Hu <nick.hu at sifive.com> wrote:
>
> The SiFive TMC0 controls the tile power domains on SiFive platform. The
> CPU enters the low power state via the `CEASE` instruction after
> configuring the TMC0. Any devices that inside the tile power domain will
> be power gated, including the private cache. Therefore flushing the
> private cache before entering the low power state.
>
> Co-developed-by: Vincent Chen <vincent.chen at sifive.com>
> Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
> ---
>  include/sbi_utils/hsm/fdt_hsm_sifive_inst.h   |  20 +
>  include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h   |  16 +
>  lib/utils/hsm/Kconfig                         |   5 +
>  lib/utils/hsm/fdt_hsm_sifive_tmc0.c           | 380 ++++++++++++++++++
>  lib/utils/hsm/objects.mk                      |   2 +
>  platform/generic/Kconfig                      |   5 +
>  platform/generic/configs/defconfig            |   2 +
>  platform/generic/sifive/objects.mk            |   3 +
>  platform/generic/sifive/sifive_dev_platform.c |  57 +++
>  9 files changed, 490 insertions(+)
>  create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
>  create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
>  create mode 100644 lib/utils/hsm/fdt_hsm_sifive_tmc0.c
>  create mode 100644 platform/generic/sifive/sifive_dev_platform.c
>
> diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h b/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
> new file mode 100644
> index 00000000..de8aba19
> --- /dev/null
> +++ b/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
> @@ -0,0 +1,20 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#ifndef __FDT_HSM_SIFIVE_INST_H__
> +#define __FDT_HSM_SIFIVE_INST_H__
> +
> +static inline void sifive_cease(void)
> +{
> +       __asm__ __volatile__(".insn 0x30500073" ::: "memory");
> +}
> +
> +static inline void sifive_cflush(void)
> +{
> +       __asm__ __volatile__(".insn 0xfc000073" ::: "memory");
> +}
> +
> +#endif
> diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> new file mode 100644
> index 00000000..4ba048b9
> --- /dev/null
> +++ b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> @@ -0,0 +1,16 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#ifndef __FDT_HSM_SIFIVE_TMC0_H__
> +#define __FDT_HSM_SIFIVE_TMC0_H__
> +
> +#ifdef CONFIG_FDT_HSM_SIFIVE_TMC0
> +int fdt_hsm_sifive_tmc0_cold_init(void);
> +#else
> +static inline int fdt_hsm_sifive_tmc0_cold_init(void) { return 0; }
> +#endif
> +
> +#endif
> diff --git a/lib/utils/hsm/Kconfig b/lib/utils/hsm/Kconfig
> index 1ad7958f..3e6f8909 100644
> --- a/lib/utils/hsm/Kconfig
> +++ b/lib/utils/hsm/Kconfig
> @@ -14,6 +14,11 @@ config FDT_HSM_RPMI
>         depends on FDT_MAILBOX && RPMI_MAILBOX
>         default n
>
> +config FDT_HSM_SIFIVE_TMC0
> +       bool "FDT SiFive TMC v0 driver"
> +       depends on PLATFORM_SIFIVE_DEV
> +       default n
> +
>  endif
>
>  endmenu
> diff --git a/lib/utils/hsm/fdt_hsm_sifive_tmc0.c b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> new file mode 100644
> index 00000000..83f86c88
> --- /dev/null
> +++ b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> @@ -0,0 +1,380 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive
> + */
> +
> +#include <libfdt.h>
> +#include <sbi/riscv_asm.h>
> +#include <sbi/riscv_io.h>
> +#include <sbi/sbi_bitops.h>
> +#include <sbi/sbi_console.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_hart.h>
> +#include <sbi/sbi_heap.h>
> +#include <sbi/sbi_hsm.h>
> +#include <sbi/sbi_ipi.h>
> +#include <sbi_utils/cache/fdt_cmo_helper.h>
> +#include <sbi_utils/fdt/fdt_driver.h>
> +#include <sbi_utils/fdt/fdt_helper.h>
> +#include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
> +#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
> +#include <sbi_utils/ipi/aclint_mswi.h>
> +
> +struct sifive_tmc0 {
> +       unsigned long reg;
> +       struct sbi_dlist node;
> +       u32 id;
> +};
> +
> +static SBI_LIST_HEAD(tmc0_list);
> +static unsigned long tmc0_offset;
> +
> +#define tmc0_ptr_get(__scratch)                                \
> +       sbi_scratch_read_type((__scratch), struct sifive_tmc0 *, tmc0_offset)
> +
> +#define tmc0_ptr_set(__scratch, __tmc0)                        \
> +       sbi_scratch_write_type((__scratch), struct sifive_tmc0 *, tmc0_offset, (__tmc0))
> +
> +/* TMC.PGPREP */
> +#define SIFIVE_TMC_PGPREP_OFF                  0x0
> +#define SIFIVE_TMC_PGPREP_ENA_REQ              BIT(31)
> +#define SIFIVE_TMC_PGPREP_ENA_ACK              BIT(30)
> +#define SIFIVE_TMC_PGPREP_DIS_REQ              BIT(29)
> +#define SIFIVE_TMC_PGPREP_DIS_ACK              BIT(28)
> +#define SIFIVE_TMC_PGPREP_CLFPNOTQ             BIT(18)
> +#define SIFIVE_TMC_PGPREP_PMCENAERR            BIT(17)
> +#define SIFIVE_TMC_PGPREP_PMCDENY              BIT(16)
> +#define SIFIVE_TMC_PGPREP_BUSERR               BIT(15)
> +#define SIFIVE_TMC_PGPREP_WAKE_DETECT          BIT(12)
> +#define SIFIVE_TMC_PGPREP_INTERNAL_ABORT       BIT(2)
> +#define SIFIVE_TMC_PGPREP_ENARSP               (SIFIVE_TMC_PGPREP_CLFPNOTQ | \
> +                                                SIFIVE_TMC_PGPREP_PMCENAERR | \
> +                                                SIFIVE_TMC_PGPREP_PMCDENY | \
> +                                                SIFIVE_TMC_PGPREP_BUSERR | \
> +                                                SIFIVE_TMC_PGPREP_WAKE_DETECT)
> +
> +/* TMC.PG */
> +#define SIFIVE_TMC_PG_OFF                      0x4
> +#define SIFIVE_TMC_PG_ENA_REQ                  BIT(31)
> +#define SIFIVE_TMC_PG_ENA_ACK                  BIT(30)
> +#define SIFIVE_TMC_PG_DIS_REQ                  BIT(29)
> +#define SIFIVE_TMC_PG_DIS_ACK                  BIT(28)
> +#define SIFIVE_TMC_PG_PMC_ENA_ERR              BIT(17)
> +#define SIFIVE_TMC_PG_PMC_DENY                 BIT(16)
> +#define SIFIVE_TMC_PG_BUS_ERR                  BIT(15)
> +#define SIFIVE_TMC_PG_MASTNOTQ                 BIT(14)
> +#define SIFIVE_TMC_PG_WARM_RESET               BIT(1)
> +#define SIFIVE_TMC_PG_ENARSP                   (SIFIVE_TMC_PG_PMC_ENA_ERR | \
> +                                                SIFIVE_TMC_PG_PMC_DENY | \
> +                                                SIFIVE_TMC_PG_BUS_ERR | \
> +                                                SIFIVE_TMC_PG_MASTNOTQ)
> +
> +/* TMC.RESUMEPC */
> +#define SIFIVE_TMC_RESUMEPC_LO                 0x10
> +#define SIFIVE_TMC_RESUMEPC_HI                 0x14
> +
> +/* TMC.WAKEMASK */
> +#define SIFIVE_TMC_WAKE_MASK_OFF               0x20
> +#define SIFIVE_TMC_WAKE_MASK_WREQ              BIT(31)
> +#define SIFIVE_TMC_WAKE_MASK_ACK               BIT(30)
> +
> +static void sifive_tmc0_set_resumepc(physical_addr_t addr)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +
> +       writel((u32)addr, (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_LO));
> +#if __riscv_xlen > 32
> +       writel((u32)(addr >> 32), (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_HI));
> +#endif
> +}
> +
> +static u32 sifive_tmc0_set_pgprep_enareq(void)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> +       u32 v = readl((void *)reg);
> +
> +       writel(v | SIFIVE_TMC_PGPREP_ENA_REQ, (void *)reg);
> +       while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_ENA_ACK));
> +
> +       v = readl((void *)reg);
> +       return v & SIFIVE_TMC_PGPREP_INTERNAL_ABORT;
> +}
> +
> +static void sifive_tmc0_set_pgprep_disreq(void)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> +       u32 v = readl((void *)reg);
> +
> +       writel(v | SIFIVE_TMC_PGPREP_DIS_REQ, (void *)reg);
> +       while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_DIS_ACK));
> +}
> +
> +static u32 sifive_tmc0_get_pgprep_enarsp(void)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> +       u32 v = readl((void *)reg);
> +
> +       return v & SIFIVE_TMC_PGPREP_ENARSP;
> +}
> +
> +static void sifive_tmc0_set_pg_enareq(void)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PG_OFF;
> +       u32 v = readl((void *)reg);
> +
> +       writel(v | SIFIVE_TMC_PG_ENA_REQ, (void *)reg);
> +}
> +
> +static int sifive_tmc0_prep(void)
> +{
> +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> +       u32 rc;
> +
> +       if (!tmc0_ptr_get(scratch))
> +               return SBI_ENODEV;
> +
> +       rc = sifive_tmc0_set_pgprep_enareq();
> +       if (rc) {
> +               sbi_printf("TMC0 error: Internal Abort (Wake detect)\n");
> +               goto fail;
> +       }
> +
> +       rc = sifive_tmc0_get_pgprep_enarsp();
> +       if (rc) {
> +               sifive_tmc0_set_pgprep_disreq();
> +               sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
> +               goto fail;
> +       }
> +
> +       sifive_tmc0_set_resumepc(scratch->warmboot_addr);
> +
> +       return SBI_OK;
> +
> +fail:
> +       return SBI_EFAIL;
> +}
> +
> +static int sifive_tmc0_enter(void)
> +{
> +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> +       u32 rc;
> +
> +       /* Flush cache and check if there is wake detect or bus error */
> +       if (fdt_cmo_private_flc_flush_all() &&
> +           sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1))
> +               sifive_cflush();
> +
> +       rc = sifive_tmc0_get_pgprep_enarsp();
> +       if (rc) {
> +               sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
> +               goto fail;
> +       }
> +
> +       if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CEASE)) {
> +               sifive_tmc0_set_pg_enareq();
> +               while (1)
> +                       sifive_cease();
> +       }
> +
> +       rc = SBI_ENOTSUPP;
> +fail:
> +       sifive_tmc0_set_pgprep_disreq();
> +       return rc;
> +}
> +
> +static int sifive_tmc0_tile_pg(void)
> +{
> +       int rc;
> +
> +       rc = sifive_tmc0_prep();
> +       if (rc)
> +               return rc;
> +
> +       return sifive_tmc0_enter();
> +}
> +
> +static struct sifive_tmc0 *sifive_tmc0_find(u32 id)
> +{
> +       struct sifive_tmc0 *tmc0;
> +
> +       sbi_list_for_each_entry(tmc0, &tmc0_list, node) {
> +               if (tmc0->id == id)
> +                       return tmc0;
> +       }
> +
> +       return NULL;
> +}
> +
> +static int sifive_tmc0_add(struct sifive_tmc0 *tmc0)
> +{
> +       if (!tmc0)
> +               return SBI_ENODEV;
> +
> +       if (sifive_tmc0_find(tmc0->id))
> +               return SBI_EALREADY;
> +
> +       sbi_list_add(&tmc0->node, &tmc0_list);
> +
> +       return SBI_OK;
> +}
> +
> +static int sifive_tmc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
> +{
> +       struct sifive_tmc0 *tmc0;
> +       int rc;
> +       u64 addr;
> +
> +       tmc0 = sbi_zalloc(sizeof(*tmc0));
> +       if (!tmc0)
> +               return SBI_ENOMEM;
> +
> +       rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
> +       if (rc)
> +               goto free_tmc0;
> +
> +       tmc0->reg = (unsigned long)addr;
> +       tmc0->id = nodeoff;
> +
> +       rc = sifive_tmc0_add(tmc0);
> +       if (rc)
> +               goto free_tmc0;
> +
> +       return SBI_OK;
> +
> +free_tmc0:
> +       sbi_free(tmc0);
> +       return rc;
> +}
> +
> +static const struct fdt_match sifive_tmc0_match[] = {
> +       { .compatible = "sifive,tmc0" },
> +       { },
> +};
> +
> +const struct fdt_driver fdt_hsm_sifive_tmc0 = {
> +       .match_table = sifive_tmc0_match,
> +       .init = sifive_tmc0_probe,
> +};
> +
> +static const struct fdt_driver *const fdt_hsm_sifive_tmc0_drivers[] = {
> +       &fdt_hsm_sifive_tmc0,
> +       NULL
> +};
> +
> +static int fdt_sifive_tmc0_get(const void *fdt, int noff, struct sifive_tmc0 **out)
> +{
> +       struct sifive_tmc0 *tmc0;
> +       int rc;
> +
> +       noff = fdt_node_offset_by_phandle(fdt, noff);
> +       if (noff < 0)
> +               return noff;
> +
> +       rc = fdt_driver_init_by_offset(fdt, noff, fdt_hsm_sifive_tmc0_drivers);
> +       if (rc)
> +               return rc;
> +
> +       tmc0 = sifive_tmc0_find(noff);
> +       if (!tmc0)
> +               return SBI_EFAIL;
> +
> +       if (out)
> +               *out = tmc0;
> +
> +       return SBI_OK;
> +}
> +
> +static int fdt_sifive_tmc0_cold_init(const void *fdt)
> +{
> +       struct sbi_scratch *scratch;
> +       struct sifive_tmc0 *tmc0;
> +       const fdt32_t *val;
> +       int cpus_off, cpu_off, rc;
> +       u32 hartid;
> +
> +       cpus_off = fdt_path_offset(fdt, "/cpus");
> +       if (cpus_off < 0)
> +               return SBI_ENOENT;
> +
> +       fdt_for_each_subnode(cpu_off, fdt, cpus_off) {
> +               rc = fdt_parse_hart_id(fdt, cpu_off, &hartid);
> +               if (rc)
> +                       continue;
> +
> +               val = fdt_getprop(fdt, cpu_off, "power-domains", NULL);
> +               if (!val)
> +                       return SBI_ENOENT;
> +
> +               rc = fdt_sifive_tmc0_get(fdt, fdt32_to_cpu(val[0]), &tmc0);
> +               if (rc)
> +                       return rc;
> +
> +               scratch = sbi_hartid_to_scratch(hartid);
> +               if (!scratch)
> +                       continue;
> +
> +               tmc0_ptr_set(scratch, tmc0);
> +       }
> +
> +       return SBI_OK;
> +}
> +
> +static int sifive_tmc0_start(u32 hartid, ulong saddr)
> +{
> +       struct sbi_ipi_device *clint = aclint_mswi_get();
> +
> +       /*
> +        * In system suspend, the IMSIC will be reset in SiFive platform so
> +        * we use the CLINT IPI as the wake event.
> +        */
> +       if (clint && clint->ipi_send)
> +               clint->ipi_send(sbi_hartid_to_hartindex(hartid));
> +       else
> +               sbi_ipi_raw_send(sbi_hartid_to_hartindex(hartid));
> +
> +       return SBI_OK;
> +}
> +
> +static int sifive_tmc0_stop(void)
> +{
> +       unsigned long mie = csr_read(CSR_MIE);
> +       int rc;
> +       // Set IPI as wake up source

Please don't use c++ style "//" comments.

> +       csr_set(CSR_MIE, MIP_MEIP | MIP_MSIP);
> +
> +       rc = sifive_tmc0_tile_pg();
> +       if (rc) {
> +               csr_write(CSR_MIE, mie);
> +               return rc;
> +       }
> +
> +       return SBI_OK;
> +}
> +
> +static struct sbi_hsm_device tmc0_hsm_dev = {
> +       .name = "SiFive TMC0",
> +       .hart_start = sifive_tmc0_start,
> +       .hart_stop = sifive_tmc0_stop,
> +};
> +
> +int fdt_hsm_sifive_tmc0_cold_init(void)
> +{
> +       int rc;
> +
> +       tmc0_offset = sbi_scratch_alloc_type_offset(struct sifive_tmc0 *);
> +       if (!tmc0_offset)
> +               return SBI_ENOMEM;
> +
> +       rc = fdt_sifive_tmc0_cold_init(fdt_get_address());
> +       if (rc)
> +               return rc;
> +
> +       sbi_hsm_set_device(&tmc0_hsm_dev);
> +
> +       return SBI_OK;
> +}

Why can't the SiFive TMC driver probe as fdt_early_driver ?

> diff --git a/lib/utils/hsm/objects.mk b/lib/utils/hsm/objects.mk
> index c13d81f7..04f4a208 100644
> --- a/lib/utils/hsm/objects.mk
> +++ b/lib/utils/hsm/objects.mk
> @@ -9,3 +9,5 @@
>
>  carray-fdt_early_drivers-$(CONFIG_FDT_HSM_RPMI) += fdt_hsm_rpmi
>  libsbiutils-objs-$(CONFIG_FDT_HSM_RPMI) += hsm/fdt_hsm_rpmi.o
> +
> +libsbiutils-objs-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += hsm/fdt_hsm_sifive_tmc0.o
> diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
> index a24d6ab2..20c25a83 100644
> --- a/platform/generic/Kconfig
> +++ b/platform/generic/Kconfig
> @@ -43,6 +43,11 @@ config PLATFORM_RENESAS_RZFIVE
>         select ANDES_PMU
>         default n
>
> +config PLATFORM_SIFIVE_DEV
> +       bool "SiFive development platform support"
> +       depends on FDT_CACHE
> +       default n
> +
>  config PLATFORM_SIFIVE_FU540
>         bool "SiFive FU540 support"
>         default n
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index 6b219cfb..837acd79 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -1,6 +1,7 @@
>  CONFIG_PLATFORM_ALLWINNER_D1=y
>  CONFIG_PLATFORM_ANDES_AE350=y
>  CONFIG_PLATFORM_RENESAS_RZFIVE=y
> +CONFIG_PLATFORM_SIFIVE_DEV=y
>  CONFIG_PLATFORM_SIFIVE_FU540=y
>  CONFIG_PLATFORM_SIFIVE_FU740=y
>  CONFIG_PLATFORM_SOPHGO_SG2042=y
> @@ -17,6 +18,7 @@ CONFIG_FDT_GPIO_SIFIVE=y
>  CONFIG_FDT_GPIO_STARFIVE=y
>  CONFIG_FDT_HSM=y
>  CONFIG_FDT_HSM_RPMI=y
> +CONFIG_FDT_HSM_SIFIVE_TMC0=y
>  CONFIG_FDT_I2C=y
>  CONFIG_FDT_I2C_SIFIVE=y
>  CONFIG_FDT_I2C_DW=y
> diff --git a/platform/generic/sifive/objects.mk b/platform/generic/sifive/objects.mk
> index d75e444a..d32e1273 100644
> --- a/platform/generic/sifive/objects.mk
> +++ b/platform/generic/sifive/objects.mk
> @@ -2,6 +2,9 @@
>  # SPDX-License-Identifier: BSD-2-Clause
>  #
>
> +carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_DEV) += sifive_dev_platform
> +platform-objs-$(CONFIG_PLATFORM_SIFIVE_DEV) += sifive/sifive_dev_platform.o
> +
>  carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive_fu540
>  platform-objs-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive/fu540.o
>
> diff --git a/platform/generic/sifive/sifive_dev_platform.c b/platform/generic/sifive/sifive_dev_platform.c
> new file mode 100644
> index 00000000..48774492
> --- /dev/null
> +++ b/platform/generic/sifive/sifive_dev_platform.c
> @@ -0,0 +1,57 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#include <platform_override.h>
> +#include <sbi/sbi_ipi.h>
> +#include <sbi_utils/cache/fdt_cmo_helper.h>
> +#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
> +#include <sbi_utils/ipi/aclint_mswi.h>
> +
> +static int sifive_early_init(bool cold_boot)
> +{
> +       int rc;
> +
> +       rc = generic_early_init(cold_boot);
> +       if (rc)
> +               return rc;
> +
> +       if (cold_boot) {
> +               rc = fdt_hsm_sifive_tmc0_cold_init();
> +               if (rc)
> +                       return rc;
> +       }
> +
> +       return 0;
> +}
> +
> +static int sifive_final_init(bool cold_boot)
> +{
> +       struct sbi_ipi_device *clint = aclint_mswi_get();
> +
> +       if (clint && clint->ipi_clear)
> +               clint->ipi_clear();
> +
> +       return generic_final_init(cold_boot);
> +}
> +
> +static int sifive_platform_init(const void *fdt, int nodeoff,
> +                               const struct fdt_match *match)
> +{
> +       generic_platform_ops.early_init = sifive_early_init;
> +       generic_platform_ops.final_init = sifive_final_init;
> +
> +       return 0;
> +}
> +
> +static const struct fdt_match sifive_dev_platform_match[] = {
> +       { .compatible = "sifive-dev" },
> +       { },
> +};
> +
> +const struct fdt_driver sifive_dev_platform = {
> +       .match_table = sifive_dev_platform_match,
> +       .init = sifive_platform_init,
> +};
> --
> 2.17.1
>

Regards,
Anup


From anup at brainfault.org  Tue Aug 26 01:52:09 2025
From: anup at brainfault.org (Anup Patel)
Date: Tue, 26 Aug 2025 14:22:09 +0530
Subject: [PATCH v4 11/11] platform: sifive: Add SiFive SMC0 driver
In-Reply-To: <20250820033250.544-12-nick.hu@sifive.com>
References: <20250820033250.544-1-nick.hu@sifive.com> <20250820033250.544-12-nick.hu@sifive.com>
Message-ID: <CAAhSdy1FOFsO1VtksYQ1WJOVZ6SMp8oo-RykTrDayA4d27A-_w@mail.gmail.com>

On Wed, Aug 20, 2025 at 9:03?AM Nick Hu <nick.hu at sifive.com> wrote:
>
> The SiFive SMC0 controls the clock and power domain of the core complex
> on the SiFive platform. The core complex enters the low power state
> after the secondary cores enter the tile power gating and last core
> execute the `CEASE` instruction with the corresponding SMC0
> configurations. The devices that inside both tile power domain and core
> complex power domain will be off, including caches and timer. Therefore
> we need to flush the last level cache before entering the core complex
> power gating and update the timer after waking up.
>
> Signed-off-by: Nick Hu <nick.hu at sifive.com>
> Reviewed-by: Cyan Yang <cyan.yang at sifive.com>

LGTM.

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

Regards,
Anup


> ---
>  include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h   |   3 +
>  .../suspend/fdt_suspend_sifive_smc0.h         |  18 +
>  lib/utils/hsm/fdt_hsm_sifive_tmc0.c           |  88 +++++
>  lib/utils/suspend/Kconfig                     |   4 +
>  lib/utils/suspend/fdt_suspend_sifive_smc0.c   | 323 ++++++++++++++++++
>  lib/utils/suspend/objects.mk                  |   3 +
>  platform/generic/configs/defconfig            |   1 +
>  7 files changed, 440 insertions(+)
>  create mode 100644 include/sbi_utils/suspend/fdt_suspend_sifive_smc0.h
>  create mode 100644 lib/utils/suspend/fdt_suspend_sifive_smc0.c
>
> diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> index 4ba048b9..d370158a 100644
> --- a/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> +++ b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> @@ -9,6 +9,9 @@
>
>  #ifdef CONFIG_FDT_HSM_SIFIVE_TMC0
>  int fdt_hsm_sifive_tmc0_cold_init(void);
> +int sifive_tmc0_set_wakemask_enareq(u32 hartid);
> +void sifive_tmc0_set_wakemask_disreq(u32 hartid);
> +bool sifive_tmc0_is_pg(u32 hartid);
>  #else
>  static inline int fdt_hsm_sifive_tmc0_cold_init(void) { return 0; }
>  #endif
> diff --git a/include/sbi_utils/suspend/fdt_suspend_sifive_smc0.h b/include/sbi_utils/suspend/fdt_suspend_sifive_smc0.h
> new file mode 100644
> index 00000000..f092be52
> --- /dev/null
> +++ b/include/sbi_utils/suspend/fdt_suspend_sifive_smc0.h
> @@ -0,0 +1,18 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#ifndef __FDT_SUSPEND_SIFIVE_SMC0_H__
> +#define __FDT_SUSPEND_SIFIVE_SMC0_H__
> +
> +#ifdef CONFIG_FDT_SUSPEND_SIFIVE_SMC0
> +bool sifive_smc0_check_warm_reset(void);
> +void sifive_smc0_mtime_update(void);
> +#else
> +static inline bool sifive_smc0_check_warm_reset(void) { return false; }
> +static inline void sifive_smc0_mtime_update(void) { return; }
> +#endif
> +
> +#endif
> diff --git a/lib/utils/hsm/fdt_hsm_sifive_tmc0.c b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> index 83f86c88..4a13fd4d 100644
> --- a/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> +++ b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> @@ -20,6 +20,8 @@
>  #include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
>  #include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
>  #include <sbi_utils/ipi/aclint_mswi.h>
> +#include <sbi_utils/irqchip/aplic.h>
> +#include <sbi_utils/suspend/fdt_suspend_sifive_smc0.h>
>
>  struct sifive_tmc0 {
>         unsigned long reg;
> @@ -79,6 +81,73 @@ static unsigned long tmc0_offset;
>  #define SIFIVE_TMC_WAKE_MASK_WREQ              BIT(31)
>  #define SIFIVE_TMC_WAKE_MASK_ACK               BIT(30)
>
> +int sifive_tmc0_set_wakemask_enareq(u32 hartid)
> +{
> +       struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
> +       unsigned long addr;
> +       u32 v;
> +
> +       if (!tmc0)
> +               return SBI_ENODEV;
> +
> +       addr = tmc0->reg + SIFIVE_TMC_WAKE_MASK_OFF;
> +       v = readl((void *)addr);
> +       writel(v | SIFIVE_TMC_WAKE_MASK_WREQ, (void *)addr);
> +
> +       while (!(readl((void *)addr) & SIFIVE_TMC_WAKE_MASK_ACK));
> +
> +       return SBI_OK;
> +}
> +
> +void sifive_tmc0_set_wakemask_disreq(u32 hartid)
> +{
> +       struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
> +       unsigned long addr;
> +       u32 v;
> +
> +       if (!tmc0)
> +               return;
> +
> +       addr = tmc0->reg + SIFIVE_TMC_WAKE_MASK_OFF;
> +       v = readl((void *)addr);
> +       writel(v & ~SIFIVE_TMC_WAKE_MASK_WREQ, (void *)addr);
> +
> +       while (readl((void *)addr) & SIFIVE_TMC_WAKE_MASK_ACK);
> +}
> +
> +bool sifive_tmc0_is_pg(u32 hartid)
> +{
> +       struct sbi_scratch *scratch = sbi_hartid_to_scratch(hartid);
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(scratch);
> +       unsigned long addr;
> +       u32 v;
> +
> +       if (!tmc0)
> +               return false;
> +
> +       addr = tmc0->reg + SIFIVE_TMC_PG_OFF;
> +       v = readl((void *)addr);
> +       if (!(v & SIFIVE_TMC_PG_ENA_ACK) ||
> +           (v & SIFIVE_TMC_PG_ENARSP) ||
> +           (v & SIFIVE_TMC_PG_DIS_REQ))
> +               return false;
> +
> +       return true;
> +}
> +
> +static bool sifive_tmc0_check_warm_reset(void)
> +{
> +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> +       unsigned long addr = tmc0->reg + SIFIVE_TMC_PG_OFF;
> +
> +       if (!tmc0)
> +               return false;
> +
> +       return readl((void *)addr) & SIFIVE_TMC_PG_WARM_RESET ? true : false;
> +}
> +
>  static void sifive_tmc0_set_resumepc(physical_addr_t addr)
>  {
>         struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> @@ -356,10 +425,29 @@ static int sifive_tmc0_stop(void)
>         return SBI_OK;
>  }
>
> +static void sifive_pg_resume(void)
> +{
> +       /*
> +        * To simplify the implementation, the SW won't clear the warm
> +        * reset bit. If the system woken up from the Core Complex power
> +        * gating, the warm reset bit of the TMC0 will be clear. Therefore
> +        * we need to check the warm reset bit of the TMC0 first as the
> +        * Tile power gating won't clear the warm reset bit of the SMC0.
> +        */
> +       if (sifive_tmc0_check_warm_reset())
> +               return;
> +
> +       if (sifive_smc0_check_warm_reset()) {
> +               aplic_restore();
> +               sifive_smc0_mtime_update();
> +       }
> +}
> +
>  static struct sbi_hsm_device tmc0_hsm_dev = {
>         .name = "SiFive TMC0",
>         .hart_start = sifive_tmc0_start,
>         .hart_stop = sifive_tmc0_stop,
> +       .hart_resume = sifive_pg_resume,
>  };
>
>  int fdt_hsm_sifive_tmc0_cold_init(void)
> diff --git a/lib/utils/suspend/Kconfig b/lib/utils/suspend/Kconfig
> index 2cbea75c..623e053f 100644
> --- a/lib/utils/suspend/Kconfig
> +++ b/lib/utils/suspend/Kconfig
> @@ -14,6 +14,10 @@ config FDT_SUSPEND_RPMI
>         depends on FDT_MAILBOX && RPMI_MAILBOX
>         default n
>
> +config FDT_SUSPEND_SIFIVE_SMC0
> +       bool "FDT SIFIVE SMC0 suspend driver"
> +       depends on FDT_HSM_SIFIVE_TMC0
> +       default n
>  endif
>
>  endmenu
> diff --git a/lib/utils/suspend/fdt_suspend_sifive_smc0.c b/lib/utils/suspend/fdt_suspend_sifive_smc0.c
> new file mode 100644
> index 00000000..005486b4
> --- /dev/null
> +++ b/lib/utils/suspend/fdt_suspend_sifive_smc0.c
> @@ -0,0 +1,323 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive
> + */
> +
> +#include <libfdt.h>
> +#include <sbi/riscv_asm.h>
> +#include <sbi/riscv_io.h>
> +#include <sbi/sbi_console.h>
> +#include <sbi/sbi_domain.h>
> +#include <sbi/sbi_error.h>
> +#include <sbi/sbi_hart.h>
> +#include <sbi/sbi_hsm.h>
> +#include <sbi/sbi_system.h>
> +#include <sbi/sbi_timer.h>
> +#include <sbi_utils/cache/fdt_cmo_helper.h>
> +#include <sbi_utils/fdt/fdt_driver.h>
> +#include <sbi_utils/fdt/fdt_helper.h>
> +#include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
> +#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
> +#include <sbi_utils/suspend/fdt_suspend_sifive_smc0.h>
> +#include <sbi_utils/timer/aclint_mtimer.h>
> +
> +#define SIFIVE_SMC_PGPREP_OFF                  0x0
> +#define SIFIVE_SMC_PG_OFF                      0x4
> +#define SIFIVE_SMC_CCTIMER_OFF                 0xc
> +#define SIFIVE_SMC_RESUMEPC_LO_OFF             0x10
> +#define SIFIVE_SMC_RESUMEPC_HI_OFF             0x14
> +#define SIFIVE_SMC_SYNC_PMC_OFF                        0x24
> +#define SIFIVE_SMC_CYCLECOUNT_LO_OFF           0x28
> +#define SIFIVE_SMC_CYCLECOUNT_HI_OFF           0x2c
> +#define SIFIVE_SMC_WFI_UNCORE_CG_OFF           0x50
> +
> +#define SIFIVE_SMC_PGPREP_ENA_REQ              BIT(31)
> +#define SIFIVE_SMC_PGPREP_ENA_ACK              BIT(30)
> +#define SIFIVE_SMC_PGPREP_DIS_REQ              BIT(29)
> +#define SIFIVE_SMC_PGPREP_DIS_ACK              BIT(29)
> +#define SIFIVE_SMC_PGPREP_FRONTNOTQ            BIT(19)
> +#define SIFIVE_SMC_PGPREP_CLFPNOTQ             BIT(18)
> +#define SIFIVE_SMC_PGPREP_PMCENAERR            BIT(17)
> +#define SIFIVE_SMC_PGPREP_WAKE_DETECT          BIT(16)
> +#define SIFIVE_SMC_PGPREP_BUSERR               BIT(15)
> +#define SIFIVE_SMC_PGPREP_EARLY_ABORT          BIT(3)
> +#define SIFIVE_SMC_PGPREP_INTERNAL_ABORT       BIT(2)
> +#define SIFIVE_SMC_PGPREP_ENARSP               (SIFIVE_SMC_PGPREP_FRONTNOTQ | \
> +                                                SIFIVE_SMC_PGPREP_CLFPNOTQ | \
> +                                                SIFIVE_SMC_PGPREP_PMCENAERR | \
> +                                                SIFIVE_SMC_PGPREP_WAKE_DETECT | \
> +                                                SIFIVE_SMC_PGPREP_BUSERR)
> +
> +#define SIFIVE_SMC_PGPREP_ABORT                        (SIFIVE_SMC_PGPREP_EARLY_ABORT | \
> +                                                SIFIVE_SMC_PGPREP_INTERNAL_ABORT)
> +
> +#define SIFIVE_SMC_PG_ENA_REQ                  BIT(31)
> +#define SIFIVE_SMC_PG_WARM_RESET               BIT(1)
> +
> +#define SIFIVE_SMC_SYNCPMC_SYNC_REQ            BIT(31)
> +#define SIFIVE_SMC_SYNCPMC_SYNC_WREQ           BIT(30)
> +#define SIFIVE_SMC_SYNCPMC_SYNC_ACK            BIT(29)
> +
> +static struct aclint_mtimer_data smc_sync_timer;
> +static unsigned long smc0_base;
> +
> +static void sifive_smc0_set_pmcsync(char regid, bool write_mode)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_SYNC_PMC_OFF;
> +       u32 v = regid | SIFIVE_SMC_SYNCPMC_SYNC_REQ;
> +
> +       if (write_mode)
> +               v |= SIFIVE_SMC_SYNCPMC_SYNC_WREQ;
> +
> +       writel(v, (void *)addr);
> +       while (!(readl((void *)addr) & SIFIVE_SMC_SYNCPMC_SYNC_ACK));
> +}
> +
> +static u64 sifive_smc0_time_read(volatile u64 *addr)
> +{
> +       u32 lo, hi;
> +
> +       do {
> +               sifive_smc0_set_pmcsync(SIFIVE_SMC_CYCLECOUNT_LO_OFF, false);
> +               sifive_smc0_set_pmcsync(SIFIVE_SMC_CYCLECOUNT_HI_OFF, false);
> +               hi = readl_relaxed((u32 *)addr + 1);
> +               lo = readl_relaxed((u32 *)addr);
> +       } while (hi != readl_relaxed((u32 *)addr + 1));
> +
> +       return ((u64)hi << 32) | (u64)lo;
> +}
> +
> +static void sifive_smc0_set_resumepc(physical_addr_t raddr)
> +{
> +       /* Set resumepc_lo */
> +       writel((u32)raddr, (void *)(smc0_base + SIFIVE_SMC_RESUMEPC_LO_OFF));
> +       /* copy resumepc_lo from SMC to PMC */
> +       sifive_smc0_set_pmcsync(SIFIVE_SMC_RESUMEPC_LO_OFF, true);
> +#if __riscv_xlen > 32
> +       /* Set resumepc_hi */
> +       writel((u32)(raddr >> 32), (void *)(smc0_base + SIFIVE_SMC_RESUMEPC_HI_OFF));
> +       /* copy resumepc_hi from SMC to PMC */
> +       sifive_smc0_set_pmcsync(SIFIVE_SMC_RESUMEPC_HI_OFF, true);
> +#endif
> +}
> +
> +static u32 sifive_smc0_get_pgprep_enarsp(void)
> +{
> +       u32 v = readl((void *)(smc0_base + SIFIVE_SMC_PGPREP_OFF));
> +
> +       return v & SIFIVE_SMC_PGPREP_ENARSP;
> +}
> +
> +static void sifive_smc0_set_pgprep_disreq(void)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_PGPREP_OFF;
> +       u32 v = readl((void *)addr);
> +
> +       writel(v | SIFIVE_SMC_PGPREP_DIS_REQ, (void *)addr);
> +       while (!(readl((void *)addr) & SIFIVE_SMC_PGPREP_DIS_ACK));
> +}
> +
> +static u32 sifive_smc0_set_pgprep_enareq(void)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_PGPREP_OFF;
> +       u32 v = readl((void *)addr);
> +
> +       writel(v | SIFIVE_SMC_PGPREP_ENA_REQ, (void *)addr);
> +       while (!(readl((void *)addr) & SIFIVE_SMC_PGPREP_ENA_ACK));
> +
> +       v = readl((void *)addr);
> +
> +       return v & SIFIVE_SMC_PGPREP_ABORT;
> +}
> +
> +static void sifive_smc0_set_pg_enareq(void)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_PG_OFF;
> +       u32 v = readl((void *)addr);
> +
> +       writel(v | SIFIVE_SMC_PG_ENA_REQ, (void *)addr);
> +}
> +
> +bool sifive_smc0_check_warm_reset(void)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_PG_OFF;
> +
> +       if (!smc0_base)
> +               return false;
> +
> +       sifive_smc0_set_pmcsync(SIFIVE_SMC_PG_OFF, false);
> +
> +       return readl((void *)addr) & SIFIVE_SMC_PG_WARM_RESET ? true : false;
> +}
> +
> +static inline void sifive_smc0_set_cg(bool enable)
> +{
> +       unsigned long addr = smc0_base + SIFIVE_SMC_WFI_UNCORE_CG_OFF;
> +
> +       if (enable)
> +               writel(0, (void *)addr);
> +       else
> +               writel(1, (void *)addr);
> +}
> +
> +static int sifive_smc0_prep(void)
> +{
> +       const struct sbi_domain *dom = &root;
> +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> +       unsigned long i;
> +       int rc;
> +       u32 target;
> +
> +       if (!smc0_base)
> +               return SBI_ENODEV;
> +
> +       /* Prevent all secondary tiles from waking up from PG state */
> +       sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
> +               target = sbi_hartindex_to_hartid(i);
> +               if (target != current_hartid()) {
> +                       rc = sifive_tmc0_set_wakemask_enareq(target);
> +                       if (rc) {
> +                               sbi_printf("Fail to enable wakemask for hart %d\n",
> +                                          target);
> +                               goto fail;
> +                       }
> +               }
> +       }
> +
> +       /* Check if all secondary tiles enter PG state */
> +       sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
> +               target = sbi_hartindex_to_hartid(i);
> +               if (target != current_hartid() &&
> +                   !sifive_tmc0_is_pg(target)) {
> +                       sbi_printf("Hart %d not in the PG state\n", target);
> +                       goto fail;
> +               }
> +       }
> +
> +       rc = sifive_smc0_set_pgprep_enareq();
> +       if (rc) {
> +               sbi_printf("SMC0 error: abort code: 0x%x\n", rc);
> +               goto fail;
> +       }
> +
> +       rc = sifive_smc0_get_pgprep_enarsp();
> +       if (rc) {
> +               sifive_smc0_set_pgprep_disreq();
> +               sbi_printf("SMC0 error: error response code: 0x%x\n", rc);
> +               goto fail;
> +       }
> +
> +       sifive_smc0_set_resumepc(scratch->warmboot_addr);
> +       return SBI_OK;
> +fail:
> +       sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
> +               target = sbi_hartindex_to_hartid(i);
> +               if (target != current_hartid())
> +                       sifive_tmc0_set_wakemask_disreq(target);
> +       }
> +
> +       return SBI_EFAIL;
> +}
> +
> +static int sifive_smc0_enter(void)
> +{
> +       const struct sbi_domain *dom = &root;
> +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> +       unsigned long i;
> +       u32 target, rc;
> +
> +       /* Flush cache and check if there is wake detect or bus error */
> +       if (fdt_cmo_llc_flush_all() &&
> +           sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1))
> +               sifive_cflush();
> +
> +       rc = sifive_smc0_get_pgprep_enarsp();
> +       if (rc) {
> +               sbi_printf("SMC0 error: error response code: 0x%x\n", rc);
> +               rc = SBI_EFAIL;
> +               goto fail;
> +       }
> +
> +       if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CEASE)) {
> +               sifive_smc0_set_pg_enareq();
> +               while (1)
> +                       sifive_cease();
> +       }
> +
> +       rc = SBI_ENOTSUPP;
> +fail:
> +       sifive_smc0_set_pgprep_disreq();
> +       sbi_hartmask_for_each_hartindex(i, dom->possible_harts) {
> +               target = sbi_hartindex_to_hartid(i);
> +               if (target != current_hartid())
> +                       sifive_tmc0_set_wakemask_disreq(target);
> +       }
> +       return rc;
> +}
> +
> +static int sifive_smc0_pg(void)
> +{
> +       int rc;
> +
> +       rc = sifive_smc0_prep();
> +       if (rc)
> +               return rc;
> +
> +       return sifive_smc0_enter();
> +}
> +
> +static int sifive_smc0_system_suspend(u32 sleep_type, unsigned long addr)
> +{
> +       /* Disable the timer interrupt */
> +       sbi_timer_exit(sbi_scratch_thishart_ptr());
> +
> +       return sifive_smc0_pg();
> +}
> +
> +static int sifive_smc0_system_suspend_check(u32 sleep_type)
> +{
> +       return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? SBI_OK : SBI_EINVAL;
> +}
> +
> +static struct sbi_system_suspend_device smc0_sys_susp = {
> +       .name = "Sifive SMC0",
> +       .system_suspend_check = sifive_smc0_system_suspend_check,
> +       .system_suspend = sifive_smc0_system_suspend,
> +};
> +
> +void sifive_smc0_mtime_update(void)
> +{
> +       struct aclint_mtimer_data *mt = aclint_get_mtimer_data();
> +
> +       aclint_mtimer_update(mt, &smc_sync_timer);
> +}
> +
> +static int sifive_smc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
> +{
> +       int rc;
> +       u64 addr;
> +
> +       rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
> +       if (rc)
> +               return rc;
> +
> +       smc0_base = (unsigned long)addr;
> +       smc_sync_timer.time_rd = sifive_smc0_time_read;
> +       smc_sync_timer.mtime_addr = smc0_base + SIFIVE_SMC_CYCLECOUNT_LO_OFF;
> +
> +       sbi_system_suspend_set_device(&smc0_sys_susp);
> +       sifive_smc0_set_cg(true);
> +
> +       return SBI_OK;
> +}
> +
> +static const struct fdt_match sifive_smc0_match[] = {
> +       { .compatible = "sifive,smc0" },
> +       { },
> +};
> +
> +const struct fdt_driver fdt_suspend_sifive_smc0 = {
> +       .match_table = sifive_smc0_match,
> +       .init = sifive_smc0_probe,
> +};
> diff --git a/lib/utils/suspend/objects.mk b/lib/utils/suspend/objects.mk
> index 9c386248..1fb29b5e 100644
> --- a/lib/utils/suspend/objects.mk
> +++ b/lib/utils/suspend/objects.mk
> @@ -9,3 +9,6 @@
>
>  carray-fdt_early_drivers-$(CONFIG_FDT_SUSPEND_RPMI) += fdt_suspend_rpmi
>  libsbiutils-objs-$(CONFIG_FDT_SUSPEND_RPMI) += suspend/fdt_suspend_rpmi.o
> +
> +carray-fdt_early_drivers-$(CONFIG_FDT_SUSPEND_SIFIVE_SMC0) += fdt_suspend_sifive_smc0
> +libsbiutils-objs-$(CONFIG_FDT_SUSPEND_SIFIVE_SMC0) += suspend/fdt_suspend_sifive_smc0.o
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index 837acd79..258988cc 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -55,6 +55,7 @@ CONFIG_FDT_SERIAL_XILINX_UARTLITE=y
>  CONFIG_SERIAL_SEMIHOSTING=y
>  CONFIG_FDT_SUSPEND=y
>  CONFIG_FDT_SUSPEND_RPMI=y
> +CONFIG_FDT_SUSPEND_SIFIVE_SMC0=y
>  CONFIG_FDT_TIMER=y
>  CONFIG_FDT_TIMER_MTIMER=y
>  CONFIG_FDT_TIMER_PLMT=y
> --
> 2.17.1
>


From anup at brainfault.org  Tue Aug 26 04:15:00 2025
From: anup at brainfault.org (Anup Patel)
Date: Tue, 26 Aug 2025 16:45:00 +0530
Subject: [PATCH] lib: sbi: pmu: Improve loop in pmu_ctr_find_hw
In-Reply-To: <20250721160712.8766-1-maherme.dev@gmail.com>
References: <20250721160712.8766-1-maherme.dev@gmail.com>
Message-ID: <CAAhSdy0oeCjUFY35SgGXBdLuxt+Giepec8Y133db7nNxdu8k+g@mail.gmail.com>

On Mon, Jul 21, 2025 at 10:31?PM Manuel Hern?ndez M?ndez
<maherme.dev at gmail.com> wrote:
>
> We do not need to iterate over all values in the loop,
> we can break the loop when we found a valid counter
> that is not started yet.
>
> Signed-off-by: Manuel Hern?ndez M?ndez <maherme.dev at gmail.com>

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup


> ---
>  lib/sbi/sbi_pmu.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c
> index 07a5c544..635cb0c7 100644
> --- a/lib/sbi/sbi_pmu.c
> +++ b/lib/sbi/sbi_pmu.c
> @@ -780,6 +780,7 @@ static int pmu_ctr_find_hw(struct sbi_pmu_hart_state *phs,
>                                 continue;
>                         /* We found a valid counter that is not started yet */
>                         ctr_idx = cbase;
> +                       break;
>                 }
>         }
>
> --
> 2.34.1
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi


From anup at brainfault.org  Tue Aug 26 04:25:09 2025
From: anup at brainfault.org (Anup Patel)
Date: Tue, 26 Aug 2025 16:55:09 +0530
Subject: [PATCH v2] platform: openpiton: Move openpiton platform from fpga
 to generic
In-Reply-To: <20250813104759.33276-1-maherme.dev@gmail.com>
References: <42fb18cc-d579-490f-b7db-89cb8d228ee8@sifive.com> <20250813104759.33276-1-maherme.dev@gmail.com>
Message-ID: <CAAhSdy0vmJuhupsOzpMjsnSZ0CpXkX_fi=ZhWOVfvn31PErnrg@mail.gmail.com>

On Wed, Aug 13, 2025 at 5:01?PM Manuel Hern?ndez M?ndez
<maherme.dev at gmail.com> wrote:
>
> The OpenPiton framework has a generic PMU that is not used by OpenSBI.
> Due to OpenSBI?s build system we cannot directly reuse the generic
> platform functions, so move the OpenPiton platform to generic. Also due
> to the generic platform is where new features are added.
>
> Signed-off-by: Manuel Hern?ndez M?ndez <maherme.dev at gmail.com>

Overall, this movement is in right direction. If you already have DT nodes
for timer, clint, and plic in the OpenPiton FDT passed to OpenSBI then
generic/openhwgroup/openpiton.c can be further simplified but this can
be done as separate patch.

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

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup

> ---
>  platform/fpga/openpiton/Kconfig               | 10 -----
>  platform/fpga/openpiton/configs/defconfig     |  0
>  platform/fpga/openpiton/objects.mk            | 41 ------------------
>  platform/generic/Kconfig                      |  4 ++
>  platform/generic/configs/defconfig            |  1 +
>  platform/generic/openhwgroup/objects.mk       |  8 ++++
>  .../openhwgroup/openpiton.c}                  | 43 ++++++++-----------
>  7 files changed, 31 insertions(+), 76 deletions(-)
>  delete mode 100644 platform/fpga/openpiton/Kconfig
>  delete mode 100644 platform/fpga/openpiton/configs/defconfig
>  delete mode 100644 platform/fpga/openpiton/objects.mk
>  create mode 100644 platform/generic/openhwgroup/objects.mk
>  rename platform/{fpga/openpiton/platform.c => generic/openhwgroup/openpiton.c} (82%)
>
> diff --git a/platform/fpga/openpiton/Kconfig b/platform/fpga/openpiton/Kconfig
> deleted file mode 100644
> index bc9c86ee..00000000
> --- a/platform/fpga/openpiton/Kconfig
> +++ /dev/null
> @@ -1,10 +0,0 @@
> -# SPDX-License-Identifier: BSD-2-Clause
> -
> -config PLATFORM_OPENPITON_FPGA
> -       bool
> -       select FDT
> -       select IPI_MSWI
> -       select IRQCHIP_PLIC
> -       select SERIAL_UART8250
> -       select TIMER_MTIMER
> -       default y
> diff --git a/platform/fpga/openpiton/configs/defconfig b/platform/fpga/openpiton/configs/defconfig
> deleted file mode 100644
> index e69de29b..00000000
> diff --git a/platform/fpga/openpiton/objects.mk b/platform/fpga/openpiton/objects.mk
> deleted file mode 100644
> index 1a0ce0c7..00000000
> --- a/platform/fpga/openpiton/objects.mk
> +++ /dev/null
> @@ -1,41 +0,0 @@
> -#
> -# SPDX-License-Identifier: BSD-2-Clause
> -#
> -# Copyright (c) 2020 Western Digital Corporation or its affiliates.
> -#
> -
> -# Compiler flags
> -platform-cppflags-y =
> -platform-cflags-y =
> -platform-asflags-y =
> -platform-ldflags-y =
> -
> -# Objects to build
> -platform-objs-y += platform.o
> -
> -PLATFORM_RISCV_XLEN = 64
> -
> -# Blobs to build
> -FW_JUMP=n
> -
> -ifeq ($(PLATFORM_RISCV_XLEN), 32)
> - # This needs to be 4MB aligned for 32-bit support
> - FW_JUMP_ADDR=0x80400000
> - else
> - # This needs to be 2MB aligned for 64-bit support
> - FW_JUMP_ADDR=0x80200000
> - endif
> -FW_JUMP_FDT_ADDR=0x82200000
> -
> -# Firmware with payload configuration.
> -FW_PAYLOAD=y
> -
> -ifeq ($(PLATFORM_RISCV_XLEN), 32)
> -# This needs to be 4MB aligned for 32-bit support
> -  FW_PAYLOAD_OFFSET=0x400000
> -else
> -# This needs to be 2MB aligned for 64-bit support
> -  FW_PAYLOAD_OFFSET=0x200000
> -endif
> -FW_PAYLOAD_FDT_ADDR=0x82200000
> -FW_PAYLOAD_ALIGN=0x1000
> diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
> index a24d6ab2..7559a4bd 100644
> --- a/platform/generic/Kconfig
> +++ b/platform/generic/Kconfig
> @@ -36,6 +36,10 @@ config PLATFORM_ANDES_AE350
>         select ANDES_PMA
>         default n
>
> +config PLATFORM_OPENHWGROUP_OPENPITON
> +       bool "OpenHWGroup Openpiton support"
> +       default n
> +
>  config PLATFORM_RENESAS_RZFIVE
>         bool "Renesas RZ/Five support"
>         select ANDES_PMA
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index c7a6531e..4b93d0bc 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -7,6 +7,7 @@ CONFIG_PLATFORM_SOPHGO_SG2042=y
>  CONFIG_PLATFORM_STARFIVE_JH7110=y
>  CONFIG_PLATFORM_THEAD=y
>  CONFIG_PLATFORM_MIPS_P8700=y
> +CONFIG_PLATFORM_OPENHWGROUP_OPENPITON=y
>  CONFIG_FDT_CPPC=y
>  CONFIG_FDT_CPPC_RPMI=y
>  CONFIG_FDT_GPIO=y
> diff --git a/platform/generic/openhwgroup/objects.mk b/platform/generic/openhwgroup/objects.mk
> new file mode 100644
> index 00000000..ab6ca79d
> --- /dev/null
> +++ b/platform/generic/openhwgroup/objects.mk
> @@ -0,0 +1,8 @@
> +#
> +# SPDX-License-Identifier: BSD-2-Clause
> +#
> +# Copyright (c) 2020 Western Digital Corporation or its affiliates.
> +#
> +
> +carray-platform_override_modules-$(CONFIG_PLATFORM_OPENHWGROUP_OPENPITON) += openhwgroup_openpiton
> +platform-objs-$(CONFIG_PLATFORM_OPENHWGROUP_OPENPITON) += openhwgroup/openpiton.o
> diff --git a/platform/fpga/openpiton/platform.c b/platform/generic/openhwgroup/openpiton.c
> similarity index 82%
> rename from platform/fpga/openpiton/platform.c
> rename to platform/generic/openhwgroup/openpiton.c
> index faa299ce..94567abb 100644
> --- a/platform/fpga/openpiton/platform.c
> +++ b/platform/generic/openhwgroup/openpiton.c
> @@ -3,12 +3,7 @@
>   * Copyright (c) 2020 Western Digital Corporation or its affiliates.
>   */
>
> -#include <sbi/riscv_asm.h>
> -#include <sbi/riscv_encoding.h>
> -#include <sbi/riscv_io.h>
> -#include <sbi/sbi_const.h>
> -#include <sbi/sbi_hart.h>
> -#include <sbi/sbi_platform.h>
> +#include <platform_override.h>
>  #include <sbi_utils/fdt/fdt_helper.h>
>  #include <sbi_utils/fdt/fdt_fixup.h>
>  #include <sbi_utils/ipi/aclint_mswi.h>
> @@ -156,25 +151,23 @@ static int openpiton_timer_init(void)
>         return aclint_mtimer_cold_init(&mtimer, NULL);
>  }
>
> -/*
> - * Platform descriptor.
> - */
> -const struct sbi_platform_operations platform_ops = {
> -       .early_init = openpiton_early_init,
> -       .final_init = openpiton_final_init,
> -       .irqchip_init = openpiton_irqchip_init,
> -       .ipi_init = openpiton_ipi_init,
> -       .timer_init = openpiton_timer_init,
> +static int openhwgroup_openpiton_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match)
> +{
> +       generic_platform_ops.early_init = openpiton_early_init;
> +       generic_platform_ops.timer_init = openpiton_timer_init;
> +       generic_platform_ops.ipi_init = openpiton_ipi_init;
> +       generic_platform_ops.irqchip_init = openpiton_irqchip_init;
> +       generic_platform_ops.final_init = openpiton_final_init;
> +
> +       return 0;
> +}
> +
> +static const struct fdt_match openhwgroup_openpiton_match[] = {
> +       { .compatible = "openpiton,cva6platform" },
> +       { },
>  };
>
> -const struct sbi_platform platform = {
> -       .opensbi_version = OPENSBI_VERSION,
> -       .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
> -       .name = "OPENPITON RISC-V",
> -       .features = SBI_PLATFORM_DEFAULT_FEATURES,
> -       .hart_count = OPENPITON_DEFAULT_HART_COUNT,
> -       .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
> -       .heap_size =
> -               SBI_PLATFORM_DEFAULT_HEAP_SIZE(OPENPITON_DEFAULT_HART_COUNT),
> -       .platform_ops_addr = (unsigned long)&platform_ops
> +const struct fdt_driver openhwgroup_openpiton = {
> +       .match_table = openhwgroup_openpiton_match,
> +       .init = openhwgroup_openpiton_platform_init,
>  };
> --
> 2.34.1
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi


From anup at brainfault.org  Tue Aug 26 04:42:35 2025
From: anup at brainfault.org (Anup Patel)
Date: Tue, 26 Aug 2025 17:12:35 +0530
Subject: [PATCH v2] platform: openpiton: Move openpiton platform from fpga
 to generic
In-Reply-To: <CAAhSdy0vmJuhupsOzpMjsnSZ0CpXkX_fi=ZhWOVfvn31PErnrg@mail.gmail.com>
References: <42fb18cc-d579-490f-b7db-89cb8d228ee8@sifive.com>
 <20250813104759.33276-1-maherme.dev@gmail.com> <CAAhSdy0vmJuhupsOzpMjsnSZ0CpXkX_fi=ZhWOVfvn31PErnrg@mail.gmail.com>
Message-ID: <CAAhSdy3weks4BzS0eC1EHkDcCubpx=-6hLoijizONjcx-Mmsyw@mail.gmail.com>

On Tue, Aug 26, 2025 at 4:55?PM Anup Patel <anup at brainfault.org> wrote:
>
> On Wed, Aug 13, 2025 at 5:01?PM Manuel Hern?ndez M?ndez
> <maherme.dev at gmail.com> wrote:
> >
> > The OpenPiton framework has a generic PMU that is not used by OpenSBI.
> > Due to OpenSBI?s build system we cannot directly reuse the generic
> > platform functions, so move the OpenPiton platform to generic. Also due
> > to the generic platform is where new features are added.
> >
> > Signed-off-by: Manuel Hern?ndez M?ndez <maherme.dev at gmail.com>
>
> Overall, this movement is in right direction. If you already have DT nodes
> for timer, clint, and plic in the OpenPiton FDT passed to OpenSBI then
> generic/openhwgroup/openpiton.c can be further simplified but this can
> be done as separate patch.
>
> Reviewed-by: Anup Patel <anup at brainfault.org>
>
> Applied this patch to the riscv/opensbi repo.

I forgot to mention. I have taken care of generic platform compilation
error for RV32 with this patch and also updated documentation to
reflect the platform movement.

Thanks,
Anup

>
> Thanks,
> Anup
>
> > ---
> >  platform/fpga/openpiton/Kconfig               | 10 -----
> >  platform/fpga/openpiton/configs/defconfig     |  0
> >  platform/fpga/openpiton/objects.mk            | 41 ------------------
> >  platform/generic/Kconfig                      |  4 ++
> >  platform/generic/configs/defconfig            |  1 +
> >  platform/generic/openhwgroup/objects.mk       |  8 ++++
> >  .../openhwgroup/openpiton.c}                  | 43 ++++++++-----------
> >  7 files changed, 31 insertions(+), 76 deletions(-)
> >  delete mode 100644 platform/fpga/openpiton/Kconfig
> >  delete mode 100644 platform/fpga/openpiton/configs/defconfig
> >  delete mode 100644 platform/fpga/openpiton/objects.mk
> >  create mode 100644 platform/generic/openhwgroup/objects.mk
> >  rename platform/{fpga/openpiton/platform.c => generic/openhwgroup/openpiton.c} (82%)
> >
> > diff --git a/platform/fpga/openpiton/Kconfig b/platform/fpga/openpiton/Kconfig
> > deleted file mode 100644
> > index bc9c86ee..00000000
> > --- a/platform/fpga/openpiton/Kconfig
> > +++ /dev/null
> > @@ -1,10 +0,0 @@
> > -# SPDX-License-Identifier: BSD-2-Clause
> > -
> > -config PLATFORM_OPENPITON_FPGA
> > -       bool
> > -       select FDT
> > -       select IPI_MSWI
> > -       select IRQCHIP_PLIC
> > -       select SERIAL_UART8250
> > -       select TIMER_MTIMER
> > -       default y
> > diff --git a/platform/fpga/openpiton/configs/defconfig b/platform/fpga/openpiton/configs/defconfig
> > deleted file mode 100644
> > index e69de29b..00000000
> > diff --git a/platform/fpga/openpiton/objects.mk b/platform/fpga/openpiton/objects.mk
> > deleted file mode 100644
> > index 1a0ce0c7..00000000
> > --- a/platform/fpga/openpiton/objects.mk
> > +++ /dev/null
> > @@ -1,41 +0,0 @@
> > -#
> > -# SPDX-License-Identifier: BSD-2-Clause
> > -#
> > -# Copyright (c) 2020 Western Digital Corporation or its affiliates.
> > -#
> > -
> > -# Compiler flags
> > -platform-cppflags-y =
> > -platform-cflags-y =
> > -platform-asflags-y =
> > -platform-ldflags-y =
> > -
> > -# Objects to build
> > -platform-objs-y += platform.o
> > -
> > -PLATFORM_RISCV_XLEN = 64
> > -
> > -# Blobs to build
> > -FW_JUMP=n
> > -
> > -ifeq ($(PLATFORM_RISCV_XLEN), 32)
> > - # This needs to be 4MB aligned for 32-bit support
> > - FW_JUMP_ADDR=0x80400000
> > - else
> > - # This needs to be 2MB aligned for 64-bit support
> > - FW_JUMP_ADDR=0x80200000
> > - endif
> > -FW_JUMP_FDT_ADDR=0x82200000
> > -
> > -# Firmware with payload configuration.
> > -FW_PAYLOAD=y
> > -
> > -ifeq ($(PLATFORM_RISCV_XLEN), 32)
> > -# This needs to be 4MB aligned for 32-bit support
> > -  FW_PAYLOAD_OFFSET=0x400000
> > -else
> > -# This needs to be 2MB aligned for 64-bit support
> > -  FW_PAYLOAD_OFFSET=0x200000
> > -endif
> > -FW_PAYLOAD_FDT_ADDR=0x82200000
> > -FW_PAYLOAD_ALIGN=0x1000
> > diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
> > index a24d6ab2..7559a4bd 100644
> > --- a/platform/generic/Kconfig
> > +++ b/platform/generic/Kconfig
> > @@ -36,6 +36,10 @@ config PLATFORM_ANDES_AE350
> >         select ANDES_PMA
> >         default n
> >
> > +config PLATFORM_OPENHWGROUP_OPENPITON
> > +       bool "OpenHWGroup Openpiton support"
> > +       default n
> > +
> >  config PLATFORM_RENESAS_RZFIVE
> >         bool "Renesas RZ/Five support"
> >         select ANDES_PMA
> > diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> > index c7a6531e..4b93d0bc 100644
> > --- a/platform/generic/configs/defconfig
> > +++ b/platform/generic/configs/defconfig
> > @@ -7,6 +7,7 @@ CONFIG_PLATFORM_SOPHGO_SG2042=y
> >  CONFIG_PLATFORM_STARFIVE_JH7110=y
> >  CONFIG_PLATFORM_THEAD=y
> >  CONFIG_PLATFORM_MIPS_P8700=y
> > +CONFIG_PLATFORM_OPENHWGROUP_OPENPITON=y
> >  CONFIG_FDT_CPPC=y
> >  CONFIG_FDT_CPPC_RPMI=y
> >  CONFIG_FDT_GPIO=y
> > diff --git a/platform/generic/openhwgroup/objects.mk b/platform/generic/openhwgroup/objects.mk
> > new file mode 100644
> > index 00000000..ab6ca79d
> > --- /dev/null
> > +++ b/platform/generic/openhwgroup/objects.mk
> > @@ -0,0 +1,8 @@
> > +#
> > +# SPDX-License-Identifier: BSD-2-Clause
> > +#
> > +# Copyright (c) 2020 Western Digital Corporation or its affiliates.
> > +#
> > +
> > +carray-platform_override_modules-$(CONFIG_PLATFORM_OPENHWGROUP_OPENPITON) += openhwgroup_openpiton
> > +platform-objs-$(CONFIG_PLATFORM_OPENHWGROUP_OPENPITON) += openhwgroup/openpiton.o
> > diff --git a/platform/fpga/openpiton/platform.c b/platform/generic/openhwgroup/openpiton.c
> > similarity index 82%
> > rename from platform/fpga/openpiton/platform.c
> > rename to platform/generic/openhwgroup/openpiton.c
> > index faa299ce..94567abb 100644
> > --- a/platform/fpga/openpiton/platform.c
> > +++ b/platform/generic/openhwgroup/openpiton.c
> > @@ -3,12 +3,7 @@
> >   * Copyright (c) 2020 Western Digital Corporation or its affiliates.
> >   */
> >
> > -#include <sbi/riscv_asm.h>
> > -#include <sbi/riscv_encoding.h>
> > -#include <sbi/riscv_io.h>
> > -#include <sbi/sbi_const.h>
> > -#include <sbi/sbi_hart.h>
> > -#include <sbi/sbi_platform.h>
> > +#include <platform_override.h>
> >  #include <sbi_utils/fdt/fdt_helper.h>
> >  #include <sbi_utils/fdt/fdt_fixup.h>
> >  #include <sbi_utils/ipi/aclint_mswi.h>
> > @@ -156,25 +151,23 @@ static int openpiton_timer_init(void)
> >         return aclint_mtimer_cold_init(&mtimer, NULL);
> >  }
> >
> > -/*
> > - * Platform descriptor.
> > - */
> > -const struct sbi_platform_operations platform_ops = {
> > -       .early_init = openpiton_early_init,
> > -       .final_init = openpiton_final_init,
> > -       .irqchip_init = openpiton_irqchip_init,
> > -       .ipi_init = openpiton_ipi_init,
> > -       .timer_init = openpiton_timer_init,
> > +static int openhwgroup_openpiton_platform_init(const void *fdt, int nodeoff, const struct fdt_match *match)
> > +{
> > +       generic_platform_ops.early_init = openpiton_early_init;
> > +       generic_platform_ops.timer_init = openpiton_timer_init;
> > +       generic_platform_ops.ipi_init = openpiton_ipi_init;
> > +       generic_platform_ops.irqchip_init = openpiton_irqchip_init;
> > +       generic_platform_ops.final_init = openpiton_final_init;
> > +
> > +       return 0;
> > +}
> > +
> > +static const struct fdt_match openhwgroup_openpiton_match[] = {
> > +       { .compatible = "openpiton,cva6platform" },
> > +       { },
> >  };
> >
> > -const struct sbi_platform platform = {
> > -       .opensbi_version = OPENSBI_VERSION,
> > -       .platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
> > -       .name = "OPENPITON RISC-V",
> > -       .features = SBI_PLATFORM_DEFAULT_FEATURES,
> > -       .hart_count = OPENPITON_DEFAULT_HART_COUNT,
> > -       .hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
> > -       .heap_size =
> > -               SBI_PLATFORM_DEFAULT_HEAP_SIZE(OPENPITON_DEFAULT_HART_COUNT),
> > -       .platform_ops_addr = (unsigned long)&platform_ops
> > +const struct fdt_driver openhwgroup_openpiton = {
> > +       .match_table = openhwgroup_openpiton_match,
> > +       .init = openhwgroup_openpiton_platform_init,
> >  };
> > --
> > 2.34.1
> >
> >
> > --
> > opensbi mailing list
> > opensbi at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/opensbi


From anup at brainfault.org  Wed Aug 27 22:00:58 2025
From: anup at brainfault.org (Anup Patel)
Date: Thu, 28 Aug 2025 10:30:58 +0530
Subject: [PATCH] platform: generic: Pack the FDT after applying fixups
In-Reply-To: <20250722233923.1356605-1-samuel.holland@sifive.com>
References: <20250722233923.1356605-1-samuel.holland@sifive.com>
Message-ID: <CAAhSdy1+PRJTQpVHcJ-EtNgxT=15+Q_EGjLZmhU8AzLbRfjVCg@mail.gmail.com>

On Wed, Jul 23, 2025 at 5:09?AM Samuel Holland
<samuel.holland at sifive.com> wrote:
>
> This minimizes the size that will be reserved by the OS for the FDT, and
> it prevents the FDT buffer from containing uninitialized memory, which
> can be important for some simulation platforms and for attestation.
>
> Closes: https://github.com/riscv-software-src/opensbi/issues/388
> Signed-off-by: Samuel Holland <samuel.holland at sifive.com>

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup

> ---
>
>  platform/generic/platform.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/platform/generic/platform.c b/platform/generic/platform.c
> index 47e771ad..889d6905 100644
> --- a/platform/generic/platform.c
> +++ b/platform/generic/platform.c
> @@ -245,6 +245,8 @@ int generic_final_init(bool cold_boot)
>         fdt_fixups(fdt);
>         fdt_domain_fixup(fdt);
>
> +       fdt_pack(fdt);
> +
>         return 0;
>  }
>
> --
> 2.47.2
>
> base-commit: cc546e1a06930c5ebaf6e90a9a28dca4218f1954
> branch: up/fdt-pack
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi


From anup at brainfault.org  Wed Aug 27 22:04:34 2025
From: anup at brainfault.org (Anup Patel)
Date: Thu, 28 Aug 2025 10:34:34 +0530
Subject: [PATCH v2] Fix license to compatible BSD-2-Clause
In-Reply-To: <20250728074334.372355-1-wxjstz@126.com>
References: <20250728074334.372355-1-wxjstz@126.com>
Message-ID: <CAAhSdy14eek151=HMMuYOrMKXY4Zo9GD605m5XjXC1Dj36RwpQ@mail.gmail.com>

On Mon, Jul 28, 2025 at 1:13?PM Xiang W <wxjstz at 126.com> wrote:
>
> OpenSBI is a BSD project. We need to modify some codes to compatible
> with BSD-2-Clause license.
>
> Signed-off-by: Xiang W <wxjstz at 126.com>
> Reviewed-by: Ben Zong-You Xie <ben717 at andestech.com>

LGTM.

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

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup

> ---
> v2 changes:
> - fix typo and reword
>
> Andes Technology agrees to change license.
> We also need the consent of Renesas Electronics Corp.
>
>  .editorconfig                              | 2 +-
>  platform/generic/andes/andes_pma.c         | 2 +-
>  platform/generic/include/andes/andes.h     | 2 +-
>  platform/generic/include/andes/andes_pma.h | 2 +-
>  platform/generic/renesas/rzfive/rzfive.c   | 2 +-
>  5 files changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/.editorconfig b/.editorconfig
> index e66b1ca3..26f90534 100644
> --- a/.editorconfig
> +++ b/.editorconfig
> @@ -1,4 +1,4 @@
> -# SPDX-License-Identifier: GPL-2.0-only
> +# SPDX-License-Identifier: BSD-2-Clause
>  # See here for more information about the format and editor support:
>  # https://editorconfig.org/
>
> diff --git a/platform/generic/andes/andes_pma.c b/platform/generic/andes/andes_pma.c
> index 09e5a30c..eeeb110e 100644
> --- a/platform/generic/andes/andes_pma.c
> +++ b/platform/generic/andes/andes_pma.c
> @@ -1,4 +1,4 @@
> -// SPDX-License-Identifier: GPL-2.0
> +// SPDX-License-Identifier: BSD-2-Clause
>  /*
>   * Copyright (C) 2023 Renesas Electronics Corp.
>   * Copyright (c) 2024 Andes Technology Corporation
> diff --git a/platform/generic/include/andes/andes.h b/platform/generic/include/andes/andes.h
> index 3403a58b..bfedf034 100644
> --- a/platform/generic/include/andes/andes.h
> +++ b/platform/generic/include/andes/andes.h
> @@ -1,4 +1,4 @@
> -/* SPDX-License-Identifier: GPL-2.0 */
> +/* SPDX-License-Identifier: BSD-2-Clause */
>  /*
>   * Copyright (C) 2024 Andes Technology Corporation
>   */
> diff --git a/platform/generic/include/andes/andes_pma.h b/platform/generic/include/andes/andes_pma.h
> index be614964..4a66e1b6 100644
> --- a/platform/generic/include/andes/andes_pma.h
> +++ b/platform/generic/include/andes/andes_pma.h
> @@ -1,4 +1,4 @@
> -/* SPDX-License-Identifier: GPL-2.0 */
> +/* SPDX-License-Identifier: BSD-2-Clause */
>  /*
>   * Copyright (C) 2023 Renesas Electronics Corp.
>   */
> diff --git a/platform/generic/renesas/rzfive/rzfive.c b/platform/generic/renesas/rzfive/rzfive.c
> index 44db3671..6c3da095 100644
> --- a/platform/generic/renesas/rzfive/rzfive.c
> +++ b/platform/generic/renesas/rzfive/rzfive.c
> @@ -1,4 +1,4 @@
> -// SPDX-License-Identifier: GPL-2.0
> +// SPDX-License-Identifier: BSD-2-Clause
>  /*
>   * Copyright (C) 2022 Renesas Electronics Corp.
>   *
> --
> 2.47.2
>


From anup at brainfault.org  Wed Aug 27 22:10:46 2025
From: anup at brainfault.org (Anup Patel)
Date: Thu, 28 Aug 2025 10:40:46 +0530
Subject: [PATCH] dbtr: Add support for icount trigger type
In-Reply-To: <20250724183120.1822667-1-jesse@rivosinc.com>
References: <20250724183120.1822667-1-jesse@rivosinc.com>
Message-ID: <CAAhSdy0EF3c_hFe0cqvC9K5zq7MfCwR1Vgb3p-jUchv3+StQwQ@mail.gmail.com>

On Fri, Jul 25, 2025 at 12:01?AM Jesse Taube <jesse at rivosinc.com> wrote:
>
> The linux kernel needs icount to implement hardware breakpoints.
>
> Signed-off-by: Jesse Taube <jesse at rivosinc.com>

LGTM.

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

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup

> ---
>  include/sbi/riscv_dbtr.h | 44 ++++++++++++++++++++++++++++++++++++++++
>  lib/sbi/sbi_dbtr.c       | 35 ++++++++++++++++++++++++++++++++
>  2 files changed, 79 insertions(+)
>
> diff --git a/include/sbi/riscv_dbtr.h b/include/sbi/riscv_dbtr.h
> index 96c7d3e3..e249eaed 100644
> --- a/include/sbi/riscv_dbtr.h
> +++ b/include/sbi/riscv_dbtr.h
> @@ -122,6 +122,50 @@ enum {
>         RV_DBTR_DECLARE_BIT_MASK(MC, TYPE,    4),
>  };
>
> +
> +/* ICOUNT - Match Control Type Register */
> +enum {
> +       RV_DBTR_DECLARE_BIT(ICOUNT, ACTION,   0),
> +       RV_DBTR_DECLARE_BIT(ICOUNT, U,        6),
> +       RV_DBTR_DECLARE_BIT(ICOUNT, S,        7),
> +       RV_DBTR_DECLARE_BIT(ICOUNT, PENDING,  8),
> +       RV_DBTR_DECLARE_BIT(ICOUNT, M,        9),
> +       RV_DBTR_DECLARE_BIT(ICOUNT, COUNT,   10),
> +       RV_DBTR_DECLARE_BIT(ICOUNT, HIT,     24),
> +       RV_DBTR_DECLARE_BIT(ICOUNT, VU,      25),
> +       RV_DBTR_DECLARE_BIT(ICOUNT, VS,      26),
> +#if __riscv_xlen == 64
> +       RV_DBTR_DECLARE_BIT(ICOUNT, DMODE,   59),
> +       RV_DBTR_DECLARE_BIT(ICOUNT, TYPE,    60),
> +#elif __riscv_xlen == 32
> +       RV_DBTR_DECLARE_BIT(ICOUNT, DMODE,   27),
> +       RV_DBTR_DECLARE_BIT(ICOUNT, TYPE,    28),
> +#else
> +       #error "Unknown __riscv_xlen"
> +#endif
> +};
> +
> +enum {
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, ACTION,   6),
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, U,        1),
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, S,        1),
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, PENDING,  1),
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, M,        1),
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, COUNT,   14),
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, HIT,      1),
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, VU,       1),
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, VS,       1),
> +#if __riscv_xlen == 64
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, DMODE,    1),
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, TYPE,     4),
> +#elif __riscv_xlen == 32
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, DMODE,    1),
> +       RV_DBTR_DECLARE_BIT_MASK(ICOUNT, TYPE,     4),
> +#else
> +       #error "Unknown __riscv_xlen"
> +#endif
> +};
> +
>  /* MC6 - Match Control 6 Type Register */
>  enum {
>         RV_DBTR_DECLARE_BIT(MC6, LOAD,   0),
> diff --git a/lib/sbi/sbi_dbtr.c b/lib/sbi/sbi_dbtr.c
> index a832c7f1..c30c2fd6 100644
> --- a/lib/sbi/sbi_dbtr.c
> +++ b/lib/sbi/sbi_dbtr.c
> @@ -336,6 +336,19 @@ static void dbtr_trigger_setup(struct sbi_dbtr_trigger *trig,
>                 if (__test_bit(RV_DBTR_BIT(MC6, VS), &tdata1))
>                         __set_bit(RV_DBTR_BIT(TS, VS), &trig->state);
>                 break;
> +       case RISCV_DBTR_TRIG_ICOUNT:
> +               if (__test_bit(RV_DBTR_BIT(ICOUNT, U), &tdata1))
> +                       __set_bit(RV_DBTR_BIT(TS, U), &trig->state);
> +
> +               if (__test_bit(RV_DBTR_BIT(ICOUNT, S), &tdata1))
> +                       __set_bit(RV_DBTR_BIT(TS, S), &trig->state);
> +
> +               if (__test_bit(RV_DBTR_BIT(ICOUNT, VU), &tdata1))
> +                       __set_bit(RV_DBTR_BIT(TS, VU), &trig->state);
> +
> +               if (__test_bit(RV_DBTR_BIT(ICOUNT, VS), &tdata1))
> +                       __set_bit(RV_DBTR_BIT(TS, VS), &trig->state);
> +               break;
>         default:
>                 sbi_dprintf("%s: Unknown type (tdata1: 0x%lx Type: %ld)\n",
>                             __func__, tdata1, TDATA1_GET_TYPE(tdata1));
> @@ -379,6 +392,16 @@ static void dbtr_trigger_enable(struct sbi_dbtr_trigger *trig)
>                 update_bit(state & RV_DBTR_BIT_MASK(TS, S),
>                            RV_DBTR_BIT(MC6, S), &trig->tdata1);
>                 break;
> +       case RISCV_DBTR_TRIG_ICOUNT:
> +               update_bit(state & RV_DBTR_BIT_MASK(TS, VU),
> +                          RV_DBTR_BIT(ICOUNT, VU), &trig->tdata1);
> +               update_bit(state & RV_DBTR_BIT_MASK(TS, VS),
> +                          RV_DBTR_BIT(ICOUNT, VS), &trig->tdata1);
> +               update_bit(state & RV_DBTR_BIT_MASK(TS, U),
> +                          RV_DBTR_BIT(ICOUNT, U), &trig->tdata1);
> +               update_bit(state & RV_DBTR_BIT_MASK(TS, S),
> +                          RV_DBTR_BIT(ICOUNT, S), &trig->tdata1);
> +               break;
>         default:
>                 break;
>         }
> @@ -418,6 +441,12 @@ static void dbtr_trigger_disable(struct sbi_dbtr_trigger *trig)
>                 __clear_bit(RV_DBTR_BIT(MC6, U), &trig->tdata1);
>                 __clear_bit(RV_DBTR_BIT(MC6, S), &trig->tdata1);
>                 break;
> +       case RISCV_DBTR_TRIG_ICOUNT:
> +               __clear_bit(RV_DBTR_BIT(ICOUNT, VU), &trig->tdata1);
> +               __clear_bit(RV_DBTR_BIT(ICOUNT, VS), &trig->tdata1);
> +               __clear_bit(RV_DBTR_BIT(ICOUNT, U), &trig->tdata1);
> +               __clear_bit(RV_DBTR_BIT(ICOUNT, S), &trig->tdata1);
> +               break;
>         default:
>                 break;
>         }
> @@ -441,6 +470,7 @@ static int dbtr_trigger_supported(unsigned long type)
>         switch (type) {
>         case RISCV_DBTR_TRIG_MCONTROL:
>         case RISCV_DBTR_TRIG_MCONTROL6:
> +       case RISCV_DBTR_TRIG_ICOUNT:
>                 return 1;
>         default:
>                 break;
> @@ -462,6 +492,11 @@ static int dbtr_trigger_valid(unsigned long type, unsigned long tdata)
>                     !(tdata & RV_DBTR_BIT_MASK(MC6, M)))
>                         return 1;
>                 break;
> +       case RISCV_DBTR_TRIG_ICOUNT:
> +               if (!(tdata & RV_DBTR_BIT_MASK(ICOUNT, DMODE)) &&
> +                   !(tdata & RV_DBTR_BIT_MASK(ICOUNT, M)))
> +                       return 1;
> +               break;
>         default:
>                 break;
>         }
> --
> 2.43.0
>


From anup at brainfault.org  Wed Aug 27 22:23:07 2025
From: anup at brainfault.org (Anup Patel)
Date: Thu, 28 Aug 2025 10:53:07 +0530
Subject: [PATCH v2] dbtr: Fix sbi_dbtr_read_trig to read from CSRs
In-Reply-To: <20250811152947.851208-1-jesse@rivosinc.com>
References: <20250811152947.851208-1-jesse@rivosinc.com>
Message-ID: <CAAhSdy0LQM-+SKTB75SFb+sxnEqDzF4Sm1v2z99ELnTBixLTNQ@mail.gmail.com>

On Tue, Aug 12, 2025 at 3:32?AM Jesse Taube <jesse at rivosinc.com> wrote:
>
> sbi_dbtr_read_trig returned the saved state of tdata{1-3}, when it
> should have returned the updated state read from CSRs.
>
> Update sbi_dbtr_read_trig to return updated state read from CSRs.
>
> Signed-off-by: Jesse Taube <jesse at rivosinc.com>
> ---
> V1 -> V2:
>  - Add back missing cpu_to_lle
> ---
>  lib/sbi/sbi_dbtr.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/lib/sbi/sbi_dbtr.c b/lib/sbi/sbi_dbtr.c
> index a832c7f1..c6b04aab 100644
> --- a/lib/sbi/sbi_dbtr.c
> +++ b/lib/sbi/sbi_dbtr.c
> @@ -529,9 +529,9 @@ int sbi_dbtr_read_trig(unsigned long smode,
>                 xmit = &entry->data;
>                 trig = INDEX_TO_TRIGGER((_idx + trig_idx_base));
>                 xmit->tstate = cpu_to_lle(trig->state);
> -               xmit->tdata1 = cpu_to_lle(trig->tdata1);
> -               xmit->tdata2 = cpu_to_lle(trig->tdata2);
> -               xmit->tdata3 = cpu_to_lle(trig->tdata3);
> +               xmit->tdata1 = cpu_to_lle(csr_read(CSR_TDATA1));
> +               xmit->tdata2 = cpu_to_lle(csr_read(CSR_TDATA2));
> +               xmit->tdata3 = cpu_to_lle(csr_read(CSR_TDATA1));

Typo over here. This should have been:
xmit->tdata3 = cpu_to_lle(csr_read(CSR_TDATA1));

Anyway, this patch is broken because we need to write
CSR_TSELECT before reading CSR_TDATAx.

The following would suffice:

diff --git a/lib/sbi/sbi_dbtr.c b/lib/sbi/sbi_dbtr.c
index c30c2fd6..656a6261 100644
--- a/lib/sbi/sbi_dbtr.c
+++ b/lib/sbi/sbi_dbtr.c
@@ -563,6 +563,10 @@ int sbi_dbtr_read_trig(unsigned long smode,
        for_each_trig_entry(shmem_base, trig_count, typeof(*entry), entry) {
                xmit = &entry->data;
                trig = INDEX_TO_TRIGGER((_idx + trig_idx_base));
+               csr_write(CSR_TSELECT, trig->index);
+               trig->tdata1 = csr_read(CSR_TDATA1);
+               trig->tdata2 = csr_read(CSR_TDATA2);
+               trig->tdata3 = csr_read(CSR_TDATA3);
                xmit->tstate = cpu_to_lle(trig->state);
                xmit->tdata1 = cpu_to_lle(trig->tdata1);
                xmit->tdata2 = cpu_to_lle(trig->tdata2);

I have taken care of the above at the time of merging this patch.

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup


From anup at brainfault.org  Wed Aug 27 22:32:05 2025
From: anup at brainfault.org (Anup Patel)
Date: Thu, 28 Aug 2025 11:02:05 +0530
Subject: [PATCH v3] generic: mips: support harts to boot from mips_warm_boot
In-Reply-To: <20250723204010.9927-1-cfu@mips.com>
References: <20250723204010.9927-1-cfu@mips.com>
Message-ID: <CAAhSdy2VRE_bfqhae+ZCxwH-rZnmm+uL+nfYAzTXEn=C84L80Q@mail.gmail.com>

On Thu, Jul 24, 2025 at 2:10?AM Chao-ying Fu <icebergfu at gmail.com> wrote:
>
> We program reset base for harts (other than hart 0) to boot at
> mips_warm_boot that jumps to _start_warm. This helps to skip some code
> sequence to speed up.
>
> Signed-off-by: Chao-ying Fu <cfu at mips.com>
> ---
>  platform/generic/mips/mips_warm_boot.S | 20 ++++++++++++++++++++
>  platform/generic/mips/objects.mk       |  2 +-
>  platform/generic/mips/p8700.c          |  5 +++++
>  3 files changed, 26 insertions(+), 1 deletion(-)
>  create mode 100644 platform/generic/mips/mips_warm_boot.S
>
> diff --git a/platform/generic/mips/mips_warm_boot.S b/platform/generic/mips/mips_warm_boot.S
> new file mode 100644
> index 0000000..25cdb83
> --- /dev/null
> +++ b/platform/generic/mips/mips_warm_boot.S
> @@ -0,0 +1,20 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 MIPS
> + *
> + */
> +       .text
> +       .align  12
> +       .globl  mips_warm_boot
> +mips_warm_boot:
> +       j       _start_warm
> +       .align  2
> +nmi_vector:
> +       j       _start_warm
> +       .align  2
> +cacheerr_vector:
> +       j       _start_warm
> +       .align  2
> +debugexc_vector:
> +       j       _start_warm

nmi_vector, cacheerr_vector, and debugexc_vector are not used
anywhere so I have dropped these at the time of merging. Please
send separate patches to add these when they are being used
somewhere.

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

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup

> diff --git a/platform/generic/mips/objects.mk b/platform/generic/mips/objects.mk
> index bbbc15a..a08c4c6 100644
> --- a/platform/generic/mips/objects.mk
> +++ b/platform/generic/mips/objects.mk
> @@ -4,5 +4,5 @@
>
>  ifeq ($(PLATFORM_RISCV_XLEN), 64)
>  carray-platform_override_modules-$(CONFIG_PLATFORM_MIPS_P8700) += mips_p8700
> -platform-objs-$(CONFIG_PLATFORM_MIPS_P8700) += mips/p8700.o
> +platform-objs-$(CONFIG_PLATFORM_MIPS_P8700) += mips/p8700.o mips/mips_warm_boot.o
>  endif
> diff --git a/platform/generic/mips/p8700.c b/platform/generic/mips/p8700.c
> index 888a45c..d3e015b 100644
> --- a/platform/generic/mips/p8700.c
> +++ b/platform/generic/mips/p8700.c
> @@ -16,6 +16,8 @@
>  #include <mips/p8700.h>
>  #include <mips/mips-cm.h>
>
> +extern void mips_warm_boot(void);
> +
>  static unsigned long mips_csr_read_num(int csr_num)
>  {
>  #define switchcase_csr_read(__csr_num, __val)          \
> @@ -150,6 +152,9 @@ static int mips_hart_start(u32 hartid, ulong saddr)
>         if (hartid == 0)
>                 return SBI_ENOTSUPP;
>
> +       /* Change reset base to mips_warm_boot */
> +       write_gcr_co_reset_base(hartid, (unsigned long)mips_warm_boot, local_p);
> +
>         if (cpu_hart(hartid) == 0) {
>                 /* Ensure its coherency is disabled */
>                 write_gcr_co_coherence(hartid, 0, local_p);
> --
> 2.47.1
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi


From jrtc27 at jrtc27.com  Wed Aug 27 23:20:38 2025
From: jrtc27 at jrtc27.com (Jessica Clarke)
Date: Thu, 28 Aug 2025 07:20:38 +0100
Subject: [PATCH v3] generic: mips: support harts to boot from
 mips_warm_boot
In-Reply-To: <CAAhSdy2VRE_bfqhae+ZCxwH-rZnmm+uL+nfYAzTXEn=C84L80Q@mail.gmail.com>
References: <20250723204010.9927-1-cfu@mips.com>
 <CAAhSdy2VRE_bfqhae+ZCxwH-rZnmm+uL+nfYAzTXEn=C84L80Q@mail.gmail.com>
Message-ID: <98E5DC08-1B1A-4F27-A520-4281A4C6B436@jrtc27.com>

On 28 Aug 2025, at 06:32, Anup Patel <anup at brainfault.org> wrote:
> On Thu, Jul 24, 2025 at 2:10?AM Chao-ying Fu <icebergfu at gmail.com> wrote:
>> 
>> We program reset base for harts (other than hart 0) to boot at
>> mips_warm_boot that jumps to _start_warm. This helps to skip some code
>> sequence to speed up.
>> 
>> Signed-off-by: Chao-ying Fu <cfu at mips.com>
>> ---
>> platform/generic/mips/mips_warm_boot.S | 20 ++++++++++++++++++++
>> platform/generic/mips/objects.mk       |  2 +-
>> platform/generic/mips/p8700.c          |  5 +++++
>> 3 files changed, 26 insertions(+), 1 deletion(-)
>> create mode 100644 platform/generic/mips/mips_warm_boot.S
>> 
>> diff --git a/platform/generic/mips/mips_warm_boot.S b/platform/generic/mips/mips_warm_boot.S
>> new file mode 100644
>> index 0000000..25cdb83
>> --- /dev/null
>> +++ b/platform/generic/mips/mips_warm_boot.S
>> @@ -0,0 +1,20 @@
>> +/*
>> + * SPDX-License-Identifier: BSD-2-Clause
>> + *
>> + * Copyright (c) 2025 MIPS
>> + *
>> + */
>> +       .text
>> +       .align  12
>> +       .globl  mips_warm_boot
>> +mips_warm_boot:
>> +       j       _start_warm
>> +       .align  2
>> +nmi_vector:
>> +       j       _start_warm
>> +       .align  2
>> +cacheerr_vector:
>> +       j       _start_warm
>> +       .align  2
>> +debugexc_vector:
>> +       j       _start_warm
> 
> nmi_vector, cacheerr_vector, and debugexc_vector are not used
> anywhere so I have dropped these at the time of merging. Please
> send separate patches to add these when they are being used
> somewhere.
> 
> Reviewed-by: Anup Patel <anup at brainfault.org>
> 
> Applied this patch to the riscv/opensbi repo.

Uh I?m pretty sure this is a reset vector, and each label is naming the
different entries in the vector, much like for mtvec.MODE=Vectored, and
therefore the result of deleting those vector entries is that, if any
of those cases occur, it will end up running whatever random code
happens to be after the first entry.

I?ve noticed you are quite eager to modify people?s patches before
applying them. Reformatting is one thing, but deleting assembly code is
another that I think goes too far. Please be more considerate of the
fact that you may not be correct in your interpretation, and so it is
not appropriate to unilaterally commit whatever unreviewed changes you
think are best, especially when it comes to vendor-specific code for
which you haven?t read any of the corresponding manuals.

Jessica



From jrtc27 at jrtc27.com  Wed Aug 27 23:47:07 2025
From: jrtc27 at jrtc27.com (Jessica Clarke)
Date: Thu, 28 Aug 2025 07:47:07 +0100
Subject: [PATCH v3] generic: mips: support harts to boot from
 mips_warm_boot
In-Reply-To: <98E5DC08-1B1A-4F27-A520-4281A4C6B436@jrtc27.com>
References: <20250723204010.9927-1-cfu@mips.com>
 <CAAhSdy2VRE_bfqhae+ZCxwH-rZnmm+uL+nfYAzTXEn=C84L80Q@mail.gmail.com>
 <98E5DC08-1B1A-4F27-A520-4281A4C6B436@jrtc27.com>
Message-ID: <1A02827E-2E3E-4064-985C-4FBCD1F69019@jrtc27.com>

On 28 Aug 2025, at 07:20, Jessica Clarke <jrtc27 at jrtc27.com> wrote:
> On 28 Aug 2025, at 06:32, Anup Patel <anup at brainfault.org> wrote:
>> On Thu, Jul 24, 2025 at 2:10?AM Chao-ying Fu <icebergfu at gmail.com> wrote:
>>> 
>>> We program reset base for harts (other than hart 0) to boot at
>>> mips_warm_boot that jumps to _start_warm. This helps to skip some code
>>> sequence to speed up.
>>> 
>>> Signed-off-by: Chao-ying Fu <cfu at mips.com>
>>> ---
>>> platform/generic/mips/mips_warm_boot.S | 20 ++++++++++++++++++++
>>> platform/generic/mips/objects.mk       |  2 +-
>>> platform/generic/mips/p8700.c          |  5 +++++
>>> 3 files changed, 26 insertions(+), 1 deletion(-)
>>> create mode 100644 platform/generic/mips/mips_warm_boot.S
>>> 
>>> diff --git a/platform/generic/mips/mips_warm_boot.S b/platform/generic/mips/mips_warm_boot.S
>>> new file mode 100644
>>> index 0000000..25cdb83
>>> --- /dev/null
>>> +++ b/platform/generic/mips/mips_warm_boot.S
>>> @@ -0,0 +1,20 @@
>>> +/*
>>> + * SPDX-License-Identifier: BSD-2-Clause
>>> + *
>>> + * Copyright (c) 2025 MIPS
>>> + *
>>> + */
>>> +       .text
>>> +       .align  12
>>> +       .globl  mips_warm_boot
>>> +mips_warm_boot:
>>> +       j       _start_warm
>>> +       .align  2
>>> +nmi_vector:
>>> +       j       _start_warm
>>> +       .align  2
>>> +cacheerr_vector:
>>> +       j       _start_warm
>>> +       .align  2
>>> +debugexc_vector:
>>> +       j       _start_warm
>> 
>> nmi_vector, cacheerr_vector, and debugexc_vector are not used
>> anywhere so I have dropped these at the time of merging. Please
>> send separate patches to add these when they are being used
>> somewhere.
>> 
>> Reviewed-by: Anup Patel <anup at brainfault.org>
>> 
>> Applied this patch to the riscv/opensbi repo.
> 
> Uh I?m pretty sure this is a reset vector, and each label is naming the
> different entries in the vector, much like for mtvec.MODE=Vectored, and
> therefore the result of deleting those vector entries is that, if any
> of those cases occur, it will end up running whatever random code
> happens to be after the first entry.
> 
> I?ve noticed you are quite eager to modify people?s patches before
> applying them. Reformatting is one thing, but deleting assembly code is
> another that I think goes too far. Please be more considerate of the
> fact that you may not be correct in your interpretation, and so it is
> not appropriate to unilaterally commit whatever unreviewed changes you
> think are best, especially when it comes to vendor-specific code for
> which you haven?t read any of the corresponding manuals.

Especially since you keep the author intact, don?t add any kind of
Co-authored-by and don?t document any of the changes you have made
between the author?s Signed-of-by and yours. This means it looks like
it?s the submitter?s fault that there?s a bug in the commit, when in
reality they submitted a correct patch and you broke it. That?s not a
particularly nice thing to have done to one?s work.

Might I suggest, if the goal is to avoid the author needing to submit a
vN+1, at least confirm with the author that your intended fixes are
correct before folding them into the patch you commit? And, for more
minor cases, document that you?ve made changes, whether in the Linux
kernel committer style that states what you?ve actually done, or at
least by adding your own Co-authored-by to state you?ve done something
unspecified.

Jessica



From nick.hu at sifive.com  Thu Aug 28 04:47:41 2025
From: nick.hu at sifive.com (Nick Hu)
Date: Thu, 28 Aug 2025 19:47:41 +0800
Subject: [PATCH v4 09/11] platform: sifive: Add SiFive TMC0 driver
In-Reply-To: <CAAhSdy2RzuFFcz87a_7N6UXCXYxkV=khhAa7jb2NpjceN5ijBw@mail.gmail.com>
References: <20250820033250.544-1-nick.hu@sifive.com> <20250820033250.544-10-nick.hu@sifive.com>
 <CAAhSdy2RzuFFcz87a_7N6UXCXYxkV=khhAa7jb2NpjceN5ijBw@mail.gmail.com>
Message-ID: <CAKddAkD_e8aUVOUMGheQ75L5d0LwX7NVDBAYBVrWdzM0sN2c5Q@mail.gmail.com>

On Tue, Aug 26, 2025 at 4:52?PM Anup Patel <anup at brainfault.org> wrote:
>
> On Wed, Aug 20, 2025 at 9:03?AM Nick Hu <nick.hu at sifive.com> wrote:
> >
> > The SiFive TMC0 controls the tile power domains on SiFive platform. The
> > CPU enters the low power state via the `CEASE` instruction after
> > configuring the TMC0. Any devices that inside the tile power domain will
> > be power gated, including the private cache. Therefore flushing the
> > private cache before entering the low power state.
> >
> > Co-developed-by: Vincent Chen <vincent.chen at sifive.com>
> > Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
> > Signed-off-by: Nick Hu <nick.hu at sifive.com>
> > Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
> > ---
> >  include/sbi_utils/hsm/fdt_hsm_sifive_inst.h   |  20 +
> >  include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h   |  16 +
> >  lib/utils/hsm/Kconfig                         |   5 +
> >  lib/utils/hsm/fdt_hsm_sifive_tmc0.c           | 380 ++++++++++++++++++
> >  lib/utils/hsm/objects.mk                      |   2 +
> >  platform/generic/Kconfig                      |   5 +
> >  platform/generic/configs/defconfig            |   2 +
> >  platform/generic/sifive/objects.mk            |   3 +
> >  platform/generic/sifive/sifive_dev_platform.c |  57 +++
> >  9 files changed, 490 insertions(+)
> >  create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
> >  create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> >  create mode 100644 lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> >  create mode 100644 platform/generic/sifive/sifive_dev_platform.c
> >
> > diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h b/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
> > new file mode 100644
> > index 00000000..de8aba19
> > --- /dev/null
> > +++ b/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
> > @@ -0,0 +1,20 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2025 SiFive Inc.
> > + */
> > +
> > +#ifndef __FDT_HSM_SIFIVE_INST_H__
> > +#define __FDT_HSM_SIFIVE_INST_H__
> > +
> > +static inline void sifive_cease(void)
> > +{
> > +       __asm__ __volatile__(".insn 0x30500073" ::: "memory");
> > +}
> > +
> > +static inline void sifive_cflush(void)
> > +{
> > +       __asm__ __volatile__(".insn 0xfc000073" ::: "memory");
> > +}
> > +
> > +#endif
> > diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> > new file mode 100644
> > index 00000000..4ba048b9
> > --- /dev/null
> > +++ b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> > @@ -0,0 +1,16 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2025 SiFive Inc.
> > + */
> > +
> > +#ifndef __FDT_HSM_SIFIVE_TMC0_H__
> > +#define __FDT_HSM_SIFIVE_TMC0_H__
> > +
> > +#ifdef CONFIG_FDT_HSM_SIFIVE_TMC0
> > +int fdt_hsm_sifive_tmc0_cold_init(void);
> > +#else
> > +static inline int fdt_hsm_sifive_tmc0_cold_init(void) { return 0; }
> > +#endif
> > +
> > +#endif
> > diff --git a/lib/utils/hsm/Kconfig b/lib/utils/hsm/Kconfig
> > index 1ad7958f..3e6f8909 100644
> > --- a/lib/utils/hsm/Kconfig
> > +++ b/lib/utils/hsm/Kconfig
> > @@ -14,6 +14,11 @@ config FDT_HSM_RPMI
> >         depends on FDT_MAILBOX && RPMI_MAILBOX
> >         default n
> >
> > +config FDT_HSM_SIFIVE_TMC0
> > +       bool "FDT SiFive TMC v0 driver"
> > +       depends on PLATFORM_SIFIVE_DEV
> > +       default n
> > +
> >  endif
> >
> >  endmenu
> > diff --git a/lib/utils/hsm/fdt_hsm_sifive_tmc0.c b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> > new file mode 100644
> > index 00000000..83f86c88
> > --- /dev/null
> > +++ b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> > @@ -0,0 +1,380 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2025 SiFive
> > + */
> > +
> > +#include <libfdt.h>
> > +#include <sbi/riscv_asm.h>
> > +#include <sbi/riscv_io.h>
> > +#include <sbi/sbi_bitops.h>
> > +#include <sbi/sbi_console.h>
> > +#include <sbi/sbi_error.h>
> > +#include <sbi/sbi_hart.h>
> > +#include <sbi/sbi_heap.h>
> > +#include <sbi/sbi_hsm.h>
> > +#include <sbi/sbi_ipi.h>
> > +#include <sbi_utils/cache/fdt_cmo_helper.h>
> > +#include <sbi_utils/fdt/fdt_driver.h>
> > +#include <sbi_utils/fdt/fdt_helper.h>
> > +#include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
> > +#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
> > +#include <sbi_utils/ipi/aclint_mswi.h>
> > +
> > +struct sifive_tmc0 {
> > +       unsigned long reg;
> > +       struct sbi_dlist node;
> > +       u32 id;
> > +};
> > +
> > +static SBI_LIST_HEAD(tmc0_list);
> > +static unsigned long tmc0_offset;
> > +
> > +#define tmc0_ptr_get(__scratch)                                \
> > +       sbi_scratch_read_type((__scratch), struct sifive_tmc0 *, tmc0_offset)
> > +
> > +#define tmc0_ptr_set(__scratch, __tmc0)                        \
> > +       sbi_scratch_write_type((__scratch), struct sifive_tmc0 *, tmc0_offset, (__tmc0))
> > +
> > +/* TMC.PGPREP */
> > +#define SIFIVE_TMC_PGPREP_OFF                  0x0
> > +#define SIFIVE_TMC_PGPREP_ENA_REQ              BIT(31)
> > +#define SIFIVE_TMC_PGPREP_ENA_ACK              BIT(30)
> > +#define SIFIVE_TMC_PGPREP_DIS_REQ              BIT(29)
> > +#define SIFIVE_TMC_PGPREP_DIS_ACK              BIT(28)
> > +#define SIFIVE_TMC_PGPREP_CLFPNOTQ             BIT(18)
> > +#define SIFIVE_TMC_PGPREP_PMCENAERR            BIT(17)
> > +#define SIFIVE_TMC_PGPREP_PMCDENY              BIT(16)
> > +#define SIFIVE_TMC_PGPREP_BUSERR               BIT(15)
> > +#define SIFIVE_TMC_PGPREP_WAKE_DETECT          BIT(12)
> > +#define SIFIVE_TMC_PGPREP_INTERNAL_ABORT       BIT(2)
> > +#define SIFIVE_TMC_PGPREP_ENARSP               (SIFIVE_TMC_PGPREP_CLFPNOTQ | \
> > +                                                SIFIVE_TMC_PGPREP_PMCENAERR | \
> > +                                                SIFIVE_TMC_PGPREP_PMCDENY | \
> > +                                                SIFIVE_TMC_PGPREP_BUSERR | \
> > +                                                SIFIVE_TMC_PGPREP_WAKE_DETECT)
> > +
> > +/* TMC.PG */
> > +#define SIFIVE_TMC_PG_OFF                      0x4
> > +#define SIFIVE_TMC_PG_ENA_REQ                  BIT(31)
> > +#define SIFIVE_TMC_PG_ENA_ACK                  BIT(30)
> > +#define SIFIVE_TMC_PG_DIS_REQ                  BIT(29)
> > +#define SIFIVE_TMC_PG_DIS_ACK                  BIT(28)
> > +#define SIFIVE_TMC_PG_PMC_ENA_ERR              BIT(17)
> > +#define SIFIVE_TMC_PG_PMC_DENY                 BIT(16)
> > +#define SIFIVE_TMC_PG_BUS_ERR                  BIT(15)
> > +#define SIFIVE_TMC_PG_MASTNOTQ                 BIT(14)
> > +#define SIFIVE_TMC_PG_WARM_RESET               BIT(1)
> > +#define SIFIVE_TMC_PG_ENARSP                   (SIFIVE_TMC_PG_PMC_ENA_ERR | \
> > +                                                SIFIVE_TMC_PG_PMC_DENY | \
> > +                                                SIFIVE_TMC_PG_BUS_ERR | \
> > +                                                SIFIVE_TMC_PG_MASTNOTQ)
> > +
> > +/* TMC.RESUMEPC */
> > +#define SIFIVE_TMC_RESUMEPC_LO                 0x10
> > +#define SIFIVE_TMC_RESUMEPC_HI                 0x14
> > +
> > +/* TMC.WAKEMASK */
> > +#define SIFIVE_TMC_WAKE_MASK_OFF               0x20
> > +#define SIFIVE_TMC_WAKE_MASK_WREQ              BIT(31)
> > +#define SIFIVE_TMC_WAKE_MASK_ACK               BIT(30)
> > +
> > +static void sifive_tmc0_set_resumepc(physical_addr_t addr)
> > +{
> > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > +
> > +       writel((u32)addr, (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_LO));
> > +#if __riscv_xlen > 32
> > +       writel((u32)(addr >> 32), (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_HI));
> > +#endif
> > +}
> > +
> > +static u32 sifive_tmc0_set_pgprep_enareq(void)
> > +{
> > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> > +       u32 v = readl((void *)reg);
> > +
> > +       writel(v | SIFIVE_TMC_PGPREP_ENA_REQ, (void *)reg);
> > +       while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_ENA_ACK));
> > +
> > +       v = readl((void *)reg);
> > +       return v & SIFIVE_TMC_PGPREP_INTERNAL_ABORT;
> > +}
> > +
> > +static void sifive_tmc0_set_pgprep_disreq(void)
> > +{
> > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> > +       u32 v = readl((void *)reg);
> > +
> > +       writel(v | SIFIVE_TMC_PGPREP_DIS_REQ, (void *)reg);
> > +       while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_DIS_ACK));
> > +}
> > +
> > +static u32 sifive_tmc0_get_pgprep_enarsp(void)
> > +{
> > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> > +       u32 v = readl((void *)reg);
> > +
> > +       return v & SIFIVE_TMC_PGPREP_ENARSP;
> > +}
> > +
> > +static void sifive_tmc0_set_pg_enareq(void)
> > +{
> > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PG_OFF;
> > +       u32 v = readl((void *)reg);
> > +
> > +       writel(v | SIFIVE_TMC_PG_ENA_REQ, (void *)reg);
> > +}
> > +
> > +static int sifive_tmc0_prep(void)
> > +{
> > +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> > +       u32 rc;
> > +
> > +       if (!tmc0_ptr_get(scratch))
> > +               return SBI_ENODEV;
> > +
> > +       rc = sifive_tmc0_set_pgprep_enareq();
> > +       if (rc) {
> > +               sbi_printf("TMC0 error: Internal Abort (Wake detect)\n");
> > +               goto fail;
> > +       }
> > +
> > +       rc = sifive_tmc0_get_pgprep_enarsp();
> > +       if (rc) {
> > +               sifive_tmc0_set_pgprep_disreq();
> > +               sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
> > +               goto fail;
> > +       }
> > +
> > +       sifive_tmc0_set_resumepc(scratch->warmboot_addr);
> > +
> > +       return SBI_OK;
> > +
> > +fail:
> > +       return SBI_EFAIL;
> > +}
> > +
> > +static int sifive_tmc0_enter(void)
> > +{
> > +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> > +       u32 rc;
> > +
> > +       /* Flush cache and check if there is wake detect or bus error */
> > +       if (fdt_cmo_private_flc_flush_all() &&
> > +           sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1))
> > +               sifive_cflush();
> > +
> > +       rc = sifive_tmc0_get_pgprep_enarsp();
> > +       if (rc) {
> > +               sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
> > +               goto fail;
> > +       }
> > +
> > +       if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CEASE)) {
> > +               sifive_tmc0_set_pg_enareq();
> > +               while (1)
> > +                       sifive_cease();
> > +       }
> > +
> > +       rc = SBI_ENOTSUPP;
> > +fail:
> > +       sifive_tmc0_set_pgprep_disreq();
> > +       return rc;
> > +}
> > +
> > +static int sifive_tmc0_tile_pg(void)
> > +{
> > +       int rc;
> > +
> > +       rc = sifive_tmc0_prep();
> > +       if (rc)
> > +               return rc;
> > +
> > +       return sifive_tmc0_enter();
> > +}
> > +
> > +static struct sifive_tmc0 *sifive_tmc0_find(u32 id)
> > +{
> > +       struct sifive_tmc0 *tmc0;
> > +
> > +       sbi_list_for_each_entry(tmc0, &tmc0_list, node) {
> > +               if (tmc0->id == id)
> > +                       return tmc0;
> > +       }
> > +
> > +       return NULL;
> > +}
> > +
> > +static int sifive_tmc0_add(struct sifive_tmc0 *tmc0)
> > +{
> > +       if (!tmc0)
> > +               return SBI_ENODEV;
> > +
> > +       if (sifive_tmc0_find(tmc0->id))
> > +               return SBI_EALREADY;
> > +
> > +       sbi_list_add(&tmc0->node, &tmc0_list);
> > +
> > +       return SBI_OK;
> > +}
> > +
> > +static int sifive_tmc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
> > +{
> > +       struct sifive_tmc0 *tmc0;
> > +       int rc;
> > +       u64 addr;
> > +
> > +       tmc0 = sbi_zalloc(sizeof(*tmc0));
> > +       if (!tmc0)
> > +               return SBI_ENOMEM;
> > +
> > +       rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
> > +       if (rc)
> > +               goto free_tmc0;
> > +
> > +       tmc0->reg = (unsigned long)addr;
> > +       tmc0->id = nodeoff;
> > +
> > +       rc = sifive_tmc0_add(tmc0);
> > +       if (rc)
> > +               goto free_tmc0;
> > +
> > +       return SBI_OK;
> > +
> > +free_tmc0:
> > +       sbi_free(tmc0);
> > +       return rc;
> > +}
> > +
> > +static const struct fdt_match sifive_tmc0_match[] = {
> > +       { .compatible = "sifive,tmc0" },
> > +       { },
> > +};
> > +
> > +const struct fdt_driver fdt_hsm_sifive_tmc0 = {
> > +       .match_table = sifive_tmc0_match,
> > +       .init = sifive_tmc0_probe,
> > +};
> > +
> > +static const struct fdt_driver *const fdt_hsm_sifive_tmc0_drivers[] = {
> > +       &fdt_hsm_sifive_tmc0,
> > +       NULL
> > +};
> > +
> > +static int fdt_sifive_tmc0_get(const void *fdt, int noff, struct sifive_tmc0 **out)
> > +{
> > +       struct sifive_tmc0 *tmc0;
> > +       int rc;
> > +
> > +       noff = fdt_node_offset_by_phandle(fdt, noff);
> > +       if (noff < 0)
> > +               return noff;
> > +
> > +       rc = fdt_driver_init_by_offset(fdt, noff, fdt_hsm_sifive_tmc0_drivers);
> > +       if (rc)
> > +               return rc;
> > +
> > +       tmc0 = sifive_tmc0_find(noff);
> > +       if (!tmc0)
> > +               return SBI_EFAIL;
> > +
> > +       if (out)
> > +               *out = tmc0;
> > +
> > +       return SBI_OK;
> > +}
> > +
> > +static int fdt_sifive_tmc0_cold_init(const void *fdt)
> > +{
> > +       struct sbi_scratch *scratch;
> > +       struct sifive_tmc0 *tmc0;
> > +       const fdt32_t *val;
> > +       int cpus_off, cpu_off, rc;
> > +       u32 hartid;
> > +
> > +       cpus_off = fdt_path_offset(fdt, "/cpus");
> > +       if (cpus_off < 0)
> > +               return SBI_ENOENT;
> > +
> > +       fdt_for_each_subnode(cpu_off, fdt, cpus_off) {
> > +               rc = fdt_parse_hart_id(fdt, cpu_off, &hartid);
> > +               if (rc)
> > +                       continue;
> > +
> > +               val = fdt_getprop(fdt, cpu_off, "power-domains", NULL);
> > +               if (!val)
> > +                       return SBI_ENOENT;
> > +
> > +               rc = fdt_sifive_tmc0_get(fdt, fdt32_to_cpu(val[0]), &tmc0);
> > +               if (rc)
> > +                       return rc;
> > +
> > +               scratch = sbi_hartid_to_scratch(hartid);
> > +               if (!scratch)
> > +                       continue;
> > +
> > +               tmc0_ptr_set(scratch, tmc0);
> > +       }
> > +
> > +       return SBI_OK;
> > +}
> > +
> > +static int sifive_tmc0_start(u32 hartid, ulong saddr)
> > +{
> > +       struct sbi_ipi_device *clint = aclint_mswi_get();
> > +
> > +       /*
> > +        * In system suspend, the IMSIC will be reset in SiFive platform so
> > +        * we use the CLINT IPI as the wake event.
> > +        */
> > +       if (clint && clint->ipi_send)
> > +               clint->ipi_send(sbi_hartid_to_hartindex(hartid));
> > +       else
> > +               sbi_ipi_raw_send(sbi_hartid_to_hartindex(hartid));
> > +
> > +       return SBI_OK;
> > +}
> > +
> > +static int sifive_tmc0_stop(void)
> > +{
> > +       unsigned long mie = csr_read(CSR_MIE);
> > +       int rc;
> > +       // Set IPI as wake up source
>
> Please don't use c++ style "//" comments.
>
Will fix it in the next version

> > +       csr_set(CSR_MIE, MIP_MEIP | MIP_MSIP);
> > +
> > +       rc = sifive_tmc0_tile_pg();
> > +       if (rc) {
> > +               csr_write(CSR_MIE, mie);
> > +               return rc;
> > +       }
> > +
> > +       return SBI_OK;
> > +}
> > +
> > +static struct sbi_hsm_device tmc0_hsm_dev = {
> > +       .name = "SiFive TMC0",
> > +       .hart_start = sifive_tmc0_start,
> > +       .hart_stop = sifive_tmc0_stop,
> > +};
> > +
> > +int fdt_hsm_sifive_tmc0_cold_init(void)
> > +{
> > +       int rc;
> > +
> > +       tmc0_offset = sbi_scratch_alloc_type_offset(struct sifive_tmc0 *);
> > +       if (!tmc0_offset)
> > +               return SBI_ENOMEM;
> > +
> > +       rc = fdt_sifive_tmc0_cold_init(fdt_get_address());
> > +       if (rc)
> > +               return rc;
> > +
> > +       sbi_hsm_set_device(&tmc0_hsm_dev);
> > +
> > +       return SBI_OK;
> > +}
>
> Why can't the SiFive TMC driver probe as fdt_early_driver ?
>
Yes, it can. This requires updating the logic for binding the TMC to
the corresponding CPU.
In the current implementation, we iterate over each CPU DT node to
probe the TMC driver via its power-domains property and then bind the
TMC to that CPU.

If the TMC driver is registered as an fdt_early_driver, we instead
need to iterate over each CPU node during every TMC driver probe and
bind the TMC to the CPU whose power-domains property references the
current TMC node.

> > diff --git a/lib/utils/hsm/objects.mk b/lib/utils/hsm/objects.mk
> > index c13d81f7..04f4a208 100644
> > --- a/lib/utils/hsm/objects.mk
> > +++ b/lib/utils/hsm/objects.mk
> > @@ -9,3 +9,5 @@
> >
> >  carray-fdt_early_drivers-$(CONFIG_FDT_HSM_RPMI) += fdt_hsm_rpmi
> >  libsbiutils-objs-$(CONFIG_FDT_HSM_RPMI) += hsm/fdt_hsm_rpmi.o
> > +
> > +libsbiutils-objs-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += hsm/fdt_hsm_sifive_tmc0.o
> > diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig
> > index a24d6ab2..20c25a83 100644
> > --- a/platform/generic/Kconfig
> > +++ b/platform/generic/Kconfig
> > @@ -43,6 +43,11 @@ config PLATFORM_RENESAS_RZFIVE
> >         select ANDES_PMU
> >         default n
> >
> > +config PLATFORM_SIFIVE_DEV
> > +       bool "SiFive development platform support"
> > +       depends on FDT_CACHE
> > +       default n
> > +
> >  config PLATFORM_SIFIVE_FU540
> >         bool "SiFive FU540 support"
> >         default n
> > diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> > index 6b219cfb..837acd79 100644
> > --- a/platform/generic/configs/defconfig
> > +++ b/platform/generic/configs/defconfig
> > @@ -1,6 +1,7 @@
> >  CONFIG_PLATFORM_ALLWINNER_D1=y
> >  CONFIG_PLATFORM_ANDES_AE350=y
> >  CONFIG_PLATFORM_RENESAS_RZFIVE=y
> > +CONFIG_PLATFORM_SIFIVE_DEV=y
> >  CONFIG_PLATFORM_SIFIVE_FU540=y
> >  CONFIG_PLATFORM_SIFIVE_FU740=y
> >  CONFIG_PLATFORM_SOPHGO_SG2042=y
> > @@ -17,6 +18,7 @@ CONFIG_FDT_GPIO_SIFIVE=y
> >  CONFIG_FDT_GPIO_STARFIVE=y
> >  CONFIG_FDT_HSM=y
> >  CONFIG_FDT_HSM_RPMI=y
> > +CONFIG_FDT_HSM_SIFIVE_TMC0=y
> >  CONFIG_FDT_I2C=y
> >  CONFIG_FDT_I2C_SIFIVE=y
> >  CONFIG_FDT_I2C_DW=y
> > diff --git a/platform/generic/sifive/objects.mk b/platform/generic/sifive/objects.mk
> > index d75e444a..d32e1273 100644
> > --- a/platform/generic/sifive/objects.mk
> > +++ b/platform/generic/sifive/objects.mk
> > @@ -2,6 +2,9 @@
> >  # SPDX-License-Identifier: BSD-2-Clause
> >  #
> >
> > +carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_DEV) += sifive_dev_platform
> > +platform-objs-$(CONFIG_PLATFORM_SIFIVE_DEV) += sifive/sifive_dev_platform.o
> > +
> >  carray-platform_override_modules-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive_fu540
> >  platform-objs-$(CONFIG_PLATFORM_SIFIVE_FU540) += sifive/fu540.o
> >
> > diff --git a/platform/generic/sifive/sifive_dev_platform.c b/platform/generic/sifive/sifive_dev_platform.c
> > new file mode 100644
> > index 00000000..48774492
> > --- /dev/null
> > +++ b/platform/generic/sifive/sifive_dev_platform.c
> > @@ -0,0 +1,57 @@
> > +/*
> > + * SPDX-License-Identifier: BSD-2-Clause
> > + *
> > + * Copyright (c) 2025 SiFive Inc.
> > + */
> > +
> > +#include <platform_override.h>
> > +#include <sbi/sbi_ipi.h>
> > +#include <sbi_utils/cache/fdt_cmo_helper.h>
> > +#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
> > +#include <sbi_utils/ipi/aclint_mswi.h>
> > +
> > +static int sifive_early_init(bool cold_boot)
> > +{
> > +       int rc;
> > +
> > +       rc = generic_early_init(cold_boot);
> > +       if (rc)
> > +               return rc;
> > +
> > +       if (cold_boot) {
> > +               rc = fdt_hsm_sifive_tmc0_cold_init();
> > +               if (rc)
> > +                       return rc;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int sifive_final_init(bool cold_boot)
> > +{
> > +       struct sbi_ipi_device *clint = aclint_mswi_get();
> > +
> > +       if (clint && clint->ipi_clear)
> > +               clint->ipi_clear();
> > +
> > +       return generic_final_init(cold_boot);
> > +}
> > +
> > +static int sifive_platform_init(const void *fdt, int nodeoff,
> > +                               const struct fdt_match *match)
> > +{
> > +       generic_platform_ops.early_init = sifive_early_init;
> > +       generic_platform_ops.final_init = sifive_final_init;
> > +
> > +       return 0;
> > +}
> > +
> > +static const struct fdt_match sifive_dev_platform_match[] = {
> > +       { .compatible = "sifive-dev" },
> > +       { },
> > +};
> > +
> > +const struct fdt_driver sifive_dev_platform = {
> > +       .match_table = sifive_dev_platform_match,
> > +       .init = sifive_platform_init,
> > +};
> > --
> > 2.17.1
> >
>
> Regards,
> Anup


From apatel at ventanamicro.com  Thu Aug 28 08:05:19 2025
From: apatel at ventanamicro.com (Anup Patel)
Date: Thu, 28 Aug 2025 20:35:19 +0530
Subject: [PATCH v3] generic: mips: support harts to boot from mips_warm_boot
In-Reply-To: <1A02827E-2E3E-4064-985C-4FBCD1F69019@jrtc27.com>
References: <20250723204010.9927-1-cfu@mips.com> <CAAhSdy2VRE_bfqhae+ZCxwH-rZnmm+uL+nfYAzTXEn=C84L80Q@mail.gmail.com>
 <98E5DC08-1B1A-4F27-A520-4281A4C6B436@jrtc27.com> <1A02827E-2E3E-4064-985C-4FBCD1F69019@jrtc27.com>
Message-ID: <CAK9=C2VsMKawQHHKFznyqDrb3TBHr-KuFrv6WdAru0ZQZ_Rwog@mail.gmail.com>

On Thu, Aug 28, 2025 at 12:17?PM Jessica Clarke <jrtc27 at jrtc27.com> wrote:
>
> On 28 Aug 2025, at 07:20, Jessica Clarke <jrtc27 at jrtc27.com> wrote:
> > On 28 Aug 2025, at 06:32, Anup Patel <anup at brainfault.org> wrote:
> >> On Thu, Jul 24, 2025 at 2:10?AM Chao-ying Fu <icebergfu at gmail.com> wrote:
> >>>
> >>> We program reset base for harts (other than hart 0) to boot at
> >>> mips_warm_boot that jumps to _start_warm. This helps to skip some code
> >>> sequence to speed up.
> >>>
> >>> Signed-off-by: Chao-ying Fu <cfu at mips.com>
> >>> ---
> >>> platform/generic/mips/mips_warm_boot.S | 20 ++++++++++++++++++++
> >>> platform/generic/mips/objects.mk       |  2 +-
> >>> platform/generic/mips/p8700.c          |  5 +++++
> >>> 3 files changed, 26 insertions(+), 1 deletion(-)
> >>> create mode 100644 platform/generic/mips/mips_warm_boot.S
> >>>
> >>> diff --git a/platform/generic/mips/mips_warm_boot.S b/platform/generic/mips/mips_warm_boot.S
> >>> new file mode 100644
> >>> index 0000000..25cdb83
> >>> --- /dev/null
> >>> +++ b/platform/generic/mips/mips_warm_boot.S
> >>> @@ -0,0 +1,20 @@
> >>> +/*
> >>> + * SPDX-License-Identifier: BSD-2-Clause
> >>> + *
> >>> + * Copyright (c) 2025 MIPS
> >>> + *
> >>> + */
> >>> +       .text
> >>> +       .align  12
> >>> +       .globl  mips_warm_boot
> >>> +mips_warm_boot:
> >>> +       j       _start_warm
> >>> +       .align  2
> >>> +nmi_vector:
> >>> +       j       _start_warm
> >>> +       .align  2
> >>> +cacheerr_vector:
> >>> +       j       _start_warm
> >>> +       .align  2
> >>> +debugexc_vector:
> >>> +       j       _start_warm
> >>
> >> nmi_vector, cacheerr_vector, and debugexc_vector are not used
> >> anywhere so I have dropped these at the time of merging. Please
> >> send separate patches to add these when they are being used
> >> somewhere.
> >>
> >> Reviewed-by: Anup Patel <anup at brainfault.org>
> >>
> >> Applied this patch to the riscv/opensbi repo.
> >
> > Uh I?m pretty sure this is a reset vector, and each label is naming the
> > different entries in the vector, much like for mtvec.MODE=Vectored, and
> > therefore the result of deleting those vector entries is that, if any
> > of those cases occur, it will end up running whatever random code
> > happens to be after the first entry.
> >
> > I?ve noticed you are quite eager to modify people?s patches before
> > applying them. Reformatting is one thing, but deleting assembly code is
> > another that I think goes too far. Please be more considerate of the
> > fact that you may not be correct in your interpretation, and so it is
> > not appropriate to unilaterally commit whatever unreviewed changes you
> > think are best, especially when it comes to vendor-specific code for
> > which you haven?t read any of the corresponding manuals.
>
> Especially since you keep the author intact, don?t add any kind of
> Co-authored-by and don?t document any of the changes you have made
> between the author?s Signed-of-by and yours. This means it looks like
> it?s the submitter?s fault that there?s a bug in the commit, when in
> reality they submitted a correct patch and you broke it. That?s not a
> particularly nice thing to have done to one?s work.
>
> Might I suggest, if the goal is to avoid the author needing to submit a
> vN+1, at least confirm with the author that your intended fixes are
> correct before folding them into the patch you commit? And, for more
> minor cases, document that you?ve made changes, whether in the Linux
> kernel committer style that states what you?ve actually done, or at
> least by adding your own Co-authored-by to state you?ve done something
> unspecified.
>

I don't mind adding Co-developed-by and more comments about
my changes.

Regards,
Anup


From icebergfu at gmail.com  Mon Aug 25 17:06:09 2025
From: icebergfu at gmail.com (Chao-ying Fu)
Date: Mon, 25 Aug 2025 17:06:09 -0700
Subject: [PATCH v3] generic: mips: support harts to boot from mips_warm_boot
In-Reply-To: <CAK9=C2VsMKawQHHKFznyqDrb3TBHr-KuFrv6WdAru0ZQZ_Rwog@mail.gmail.com>
References: <20250723204010.9927-1-cfu@mips.com> <CAAhSdy2VRE_bfqhae+ZCxwH-rZnmm+uL+nfYAzTXEn=C84L80Q@mail.gmail.com>
 <98E5DC08-1B1A-4F27-A520-4281A4C6B436@jrtc27.com> <1A02827E-2E3E-4064-985C-4FBCD1F69019@jrtc27.com>
 <CAK9=C2VsMKawQHHKFznyqDrb3TBHr-KuFrv6WdAru0ZQZ_Rwog@mail.gmail.com>
Message-ID: <CAM1rFzGfKs=7SckwafFvZM=-bc7DYGcjiGn9Z6SEiKyEEwyi-A@mail.gmail.com>

On Thu, Aug 28, 2025 at 8:05?AM Anup Patel <apatel at ventanamicro.com> wrote:
>
> On Thu, Aug 28, 2025 at 12:17?PM Jessica Clarke <jrtc27 at jrtc27.com> wrote:
> >
> > On 28 Aug 2025, at 07:20, Jessica Clarke <jrtc27 at jrtc27.com> wrote:
> > > On 28 Aug 2025, at 06:32, Anup Patel <anup at brainfault.org> wrote:
> > >> On Thu, Jul 24, 2025 at 2:10?AM Chao-ying Fu <icebergfu at gmail.com> wrote:
> > >>>
> > >>> We program reset base for harts (other than hart 0) to boot at
> > >>> mips_warm_boot that jumps to _start_warm. This helps to skip some code
> > >>> sequence to speed up.
> > >>>
> > >>> Signed-off-by: Chao-ying Fu <cfu at mips.com>
> > >>> ---
> > >>> platform/generic/mips/mips_warm_boot.S | 20 ++++++++++++++++++++
> > >>> platform/generic/mips/objects.mk       |  2 +-
> > >>> platform/generic/mips/p8700.c          |  5 +++++
> > >>> 3 files changed, 26 insertions(+), 1 deletion(-)
> > >>> create mode 100644 platform/generic/mips/mips_warm_boot.S
> > >>>
> > >>> diff --git a/platform/generic/mips/mips_warm_boot.S b/platform/generic/mips/mips_warm_boot.S
> > >>> new file mode 100644
> > >>> index 0000000..25cdb83
> > >>> --- /dev/null
> > >>> +++ b/platform/generic/mips/mips_warm_boot.S
> > >>> @@ -0,0 +1,20 @@
> > >>> +/*
> > >>> + * SPDX-License-Identifier: BSD-2-Clause
> > >>> + *
> > >>> + * Copyright (c) 2025 MIPS
> > >>> + *
> > >>> + */
> > >>> +       .text
> > >>> +       .align  12
> > >>> +       .globl  mips_warm_boot
> > >>> +mips_warm_boot:
> > >>> +       j       _start_warm
> > >>> +       .align  2
> > >>> +nmi_vector:
> > >>> +       j       _start_warm
> > >>> +       .align  2
> > >>> +cacheerr_vector:
> > >>> +       j       _start_warm
> > >>> +       .align  2
> > >>> +debugexc_vector:
> > >>> +       j       _start_warm
> > >>
> > >> nmi_vector, cacheerr_vector, and debugexc_vector are not used
> > >> anywhere so I have dropped these at the time of merging. Please
> > >> send separate patches to add these when they are being used
> > >> somewhere.
> > >>
> > >> Reviewed-by: Anup Patel <anup at brainfault.org>
> > >>
> > >> Applied this patch to the riscv/opensbi repo.
> > >
> > > Uh I?m pretty sure this is a reset vector, and each label is naming the
> > > different entries in the vector, much like for mtvec.MODE=Vectored, and
> > > therefore the result of deleting those vector entries is that, if any
> > > of those cases occur, it will end up running whatever random code
> > > happens to be after the first entry.
> > >
> > > I?ve noticed you are quite eager to modify people?s patches before
> > > applying them. Reformatting is one thing, but deleting assembly code is
> > > another that I think goes too far. Please be more considerate of the
> > > fact that you may not be correct in your interpretation, and so it is
> > > not appropriate to unilaterally commit whatever unreviewed changes you
> > > think are best, especially when it comes to vendor-specific code for
> > > which you haven?t read any of the corresponding manuals.
> >
> > Especially since you keep the author intact, don?t add any kind of
> > Co-authored-by and don?t document any of the changes you have made
> > between the author?s Signed-of-by and yours. This means it looks like
> > it?s the submitter?s fault that there?s a bug in the commit, when in
> > reality they submitted a correct patch and you broke it. That?s not a
> > particularly nice thing to have done to one?s work.
> >
> > Might I suggest, if the goal is to avoid the author needing to submit a
> > vN+1, at least confirm with the author that your intended fixes are
> > correct before folding them into the patch you commit? And, for more
> > minor cases, document that you?ve made changes, whether in the Linux
> > kernel committer style that states what you?ve actually done, or at
> > least by adding your own Co-authored-by to state you?ve done something
> > unspecified.
> >
>
> I don't mind adding Co-developed-by and more comments about
> my changes.
>
> Regards,
> Anup

Hi All,

  We will see if we need to add support for NMI, cache error, and
debug exceptions later. The previous patch just treats them the same
as "reset" and lets them jump to the same entry: _start_warm.

  Thanks a lot for reviewing and merging our patches!

Regards,
Chao-ying


From apatel at ventanamicro.com  Sat Aug 30 04:01:57 2025
From: apatel at ventanamicro.com (Anup Patel)
Date: Sat, 30 Aug 2025 16:31:57 +0530
Subject: [PATCH v4 09/11] platform: sifive: Add SiFive TMC0 driver
In-Reply-To: <CAKddAkD_e8aUVOUMGheQ75L5d0LwX7NVDBAYBVrWdzM0sN2c5Q@mail.gmail.com>
References: <20250820033250.544-1-nick.hu@sifive.com> <20250820033250.544-10-nick.hu@sifive.com>
 <CAAhSdy2RzuFFcz87a_7N6UXCXYxkV=khhAa7jb2NpjceN5ijBw@mail.gmail.com> <CAKddAkD_e8aUVOUMGheQ75L5d0LwX7NVDBAYBVrWdzM0sN2c5Q@mail.gmail.com>
Message-ID: <CAK9=C2Wwr9VbCET8q2udbdUFZjdmDhfGbD53EzWW-cBw=0wfWw@mail.gmail.com>

On Thu, Aug 28, 2025 at 10:53?PM Nick Hu <nick.hu at sifive.com> wrote:
>
> On Tue, Aug 26, 2025 at 4:52?PM Anup Patel <anup at brainfault.org> wrote:
> >
> > On Wed, Aug 20, 2025 at 9:03?AM Nick Hu <nick.hu at sifive.com> wrote:
> > >
> > > The SiFive TMC0 controls the tile power domains on SiFive platform. The
> > > CPU enters the low power state via the `CEASE` instruction after
> > > configuring the TMC0. Any devices that inside the tile power domain will
> > > be power gated, including the private cache. Therefore flushing the
> > > private cache before entering the low power state.
> > >
> > > Co-developed-by: Vincent Chen <vincent.chen at sifive.com>
> > > Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
> > > Signed-off-by: Nick Hu <nick.hu at sifive.com>
> > > Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
> > > ---
> > >  include/sbi_utils/hsm/fdt_hsm_sifive_inst.h   |  20 +
> > >  include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h   |  16 +
> > >  lib/utils/hsm/Kconfig                         |   5 +
> > >  lib/utils/hsm/fdt_hsm_sifive_tmc0.c           | 380 ++++++++++++++++++
> > >  lib/utils/hsm/objects.mk                      |   2 +
> > >  platform/generic/Kconfig                      |   5 +
> > >  platform/generic/configs/defconfig            |   2 +
> > >  platform/generic/sifive/objects.mk            |   3 +
> > >  platform/generic/sifive/sifive_dev_platform.c |  57 +++
> > >  9 files changed, 490 insertions(+)
> > >  create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
> > >  create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> > >  create mode 100644 lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> > >  create mode 100644 platform/generic/sifive/sifive_dev_platform.c
> > >
> > > diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h b/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
> > > new file mode 100644
> > > index 00000000..de8aba19
> > > --- /dev/null
> > > +++ b/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
> > > @@ -0,0 +1,20 @@
> > > +/*
> > > + * SPDX-License-Identifier: BSD-2-Clause
> > > + *
> > > + * Copyright (c) 2025 SiFive Inc.
> > > + */
> > > +
> > > +#ifndef __FDT_HSM_SIFIVE_INST_H__
> > > +#define __FDT_HSM_SIFIVE_INST_H__
> > > +
> > > +static inline void sifive_cease(void)
> > > +{
> > > +       __asm__ __volatile__(".insn 0x30500073" ::: "memory");
> > > +}
> > > +
> > > +static inline void sifive_cflush(void)
> > > +{
> > > +       __asm__ __volatile__(".insn 0xfc000073" ::: "memory");
> > > +}
> > > +
> > > +#endif
> > > diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> > > new file mode 100644
> > > index 00000000..4ba048b9
> > > --- /dev/null
> > > +++ b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> > > @@ -0,0 +1,16 @@
> > > +/*
> > > + * SPDX-License-Identifier: BSD-2-Clause
> > > + *
> > > + * Copyright (c) 2025 SiFive Inc.
> > > + */
> > > +
> > > +#ifndef __FDT_HSM_SIFIVE_TMC0_H__
> > > +#define __FDT_HSM_SIFIVE_TMC0_H__
> > > +
> > > +#ifdef CONFIG_FDT_HSM_SIFIVE_TMC0
> > > +int fdt_hsm_sifive_tmc0_cold_init(void);
> > > +#else
> > > +static inline int fdt_hsm_sifive_tmc0_cold_init(void) { return 0; }
> > > +#endif
> > > +
> > > +#endif
> > > diff --git a/lib/utils/hsm/Kconfig b/lib/utils/hsm/Kconfig
> > > index 1ad7958f..3e6f8909 100644
> > > --- a/lib/utils/hsm/Kconfig
> > > +++ b/lib/utils/hsm/Kconfig
> > > @@ -14,6 +14,11 @@ config FDT_HSM_RPMI
> > >         depends on FDT_MAILBOX && RPMI_MAILBOX
> > >         default n
> > >
> > > +config FDT_HSM_SIFIVE_TMC0
> > > +       bool "FDT SiFive TMC v0 driver"
> > > +       depends on PLATFORM_SIFIVE_DEV
> > > +       default n
> > > +
> > >  endif
> > >
> > >  endmenu
> > > diff --git a/lib/utils/hsm/fdt_hsm_sifive_tmc0.c b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> > > new file mode 100644
> > > index 00000000..83f86c88
> > > --- /dev/null
> > > +++ b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> > > @@ -0,0 +1,380 @@
> > > +/*
> > > + * SPDX-License-Identifier: BSD-2-Clause
> > > + *
> > > + * Copyright (c) 2025 SiFive
> > > + */
> > > +
> > > +#include <libfdt.h>
> > > +#include <sbi/riscv_asm.h>
> > > +#include <sbi/riscv_io.h>
> > > +#include <sbi/sbi_bitops.h>
> > > +#include <sbi/sbi_console.h>
> > > +#include <sbi/sbi_error.h>
> > > +#include <sbi/sbi_hart.h>
> > > +#include <sbi/sbi_heap.h>
> > > +#include <sbi/sbi_hsm.h>
> > > +#include <sbi/sbi_ipi.h>
> > > +#include <sbi_utils/cache/fdt_cmo_helper.h>
> > > +#include <sbi_utils/fdt/fdt_driver.h>
> > > +#include <sbi_utils/fdt/fdt_helper.h>
> > > +#include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
> > > +#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
> > > +#include <sbi_utils/ipi/aclint_mswi.h>
> > > +
> > > +struct sifive_tmc0 {
> > > +       unsigned long reg;
> > > +       struct sbi_dlist node;
> > > +       u32 id;
> > > +};
> > > +
> > > +static SBI_LIST_HEAD(tmc0_list);
> > > +static unsigned long tmc0_offset;
> > > +
> > > +#define tmc0_ptr_get(__scratch)                                \
> > > +       sbi_scratch_read_type((__scratch), struct sifive_tmc0 *, tmc0_offset)
> > > +
> > > +#define tmc0_ptr_set(__scratch, __tmc0)                        \
> > > +       sbi_scratch_write_type((__scratch), struct sifive_tmc0 *, tmc0_offset, (__tmc0))
> > > +
> > > +/* TMC.PGPREP */
> > > +#define SIFIVE_TMC_PGPREP_OFF                  0x0
> > > +#define SIFIVE_TMC_PGPREP_ENA_REQ              BIT(31)
> > > +#define SIFIVE_TMC_PGPREP_ENA_ACK              BIT(30)
> > > +#define SIFIVE_TMC_PGPREP_DIS_REQ              BIT(29)
> > > +#define SIFIVE_TMC_PGPREP_DIS_ACK              BIT(28)
> > > +#define SIFIVE_TMC_PGPREP_CLFPNOTQ             BIT(18)
> > > +#define SIFIVE_TMC_PGPREP_PMCENAERR            BIT(17)
> > > +#define SIFIVE_TMC_PGPREP_PMCDENY              BIT(16)
> > > +#define SIFIVE_TMC_PGPREP_BUSERR               BIT(15)
> > > +#define SIFIVE_TMC_PGPREP_WAKE_DETECT          BIT(12)
> > > +#define SIFIVE_TMC_PGPREP_INTERNAL_ABORT       BIT(2)
> > > +#define SIFIVE_TMC_PGPREP_ENARSP               (SIFIVE_TMC_PGPREP_CLFPNOTQ | \
> > > +                                                SIFIVE_TMC_PGPREP_PMCENAERR | \
> > > +                                                SIFIVE_TMC_PGPREP_PMCDENY | \
> > > +                                                SIFIVE_TMC_PGPREP_BUSERR | \
> > > +                                                SIFIVE_TMC_PGPREP_WAKE_DETECT)
> > > +
> > > +/* TMC.PG */
> > > +#define SIFIVE_TMC_PG_OFF                      0x4
> > > +#define SIFIVE_TMC_PG_ENA_REQ                  BIT(31)
> > > +#define SIFIVE_TMC_PG_ENA_ACK                  BIT(30)
> > > +#define SIFIVE_TMC_PG_DIS_REQ                  BIT(29)
> > > +#define SIFIVE_TMC_PG_DIS_ACK                  BIT(28)
> > > +#define SIFIVE_TMC_PG_PMC_ENA_ERR              BIT(17)
> > > +#define SIFIVE_TMC_PG_PMC_DENY                 BIT(16)
> > > +#define SIFIVE_TMC_PG_BUS_ERR                  BIT(15)
> > > +#define SIFIVE_TMC_PG_MASTNOTQ                 BIT(14)
> > > +#define SIFIVE_TMC_PG_WARM_RESET               BIT(1)
> > > +#define SIFIVE_TMC_PG_ENARSP                   (SIFIVE_TMC_PG_PMC_ENA_ERR | \
> > > +                                                SIFIVE_TMC_PG_PMC_DENY | \
> > > +                                                SIFIVE_TMC_PG_BUS_ERR | \
> > > +                                                SIFIVE_TMC_PG_MASTNOTQ)
> > > +
> > > +/* TMC.RESUMEPC */
> > > +#define SIFIVE_TMC_RESUMEPC_LO                 0x10
> > > +#define SIFIVE_TMC_RESUMEPC_HI                 0x14
> > > +
> > > +/* TMC.WAKEMASK */
> > > +#define SIFIVE_TMC_WAKE_MASK_OFF               0x20
> > > +#define SIFIVE_TMC_WAKE_MASK_WREQ              BIT(31)
> > > +#define SIFIVE_TMC_WAKE_MASK_ACK               BIT(30)
> > > +
> > > +static void sifive_tmc0_set_resumepc(physical_addr_t addr)
> > > +{
> > > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > > +
> > > +       writel((u32)addr, (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_LO));
> > > +#if __riscv_xlen > 32
> > > +       writel((u32)(addr >> 32), (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_HI));
> > > +#endif
> > > +}
> > > +
> > > +static u32 sifive_tmc0_set_pgprep_enareq(void)
> > > +{
> > > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> > > +       u32 v = readl((void *)reg);
> > > +
> > > +       writel(v | SIFIVE_TMC_PGPREP_ENA_REQ, (void *)reg);
> > > +       while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_ENA_ACK));
> > > +
> > > +       v = readl((void *)reg);
> > > +       return v & SIFIVE_TMC_PGPREP_INTERNAL_ABORT;
> > > +}
> > > +
> > > +static void sifive_tmc0_set_pgprep_disreq(void)
> > > +{
> > > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> > > +       u32 v = readl((void *)reg);
> > > +
> > > +       writel(v | SIFIVE_TMC_PGPREP_DIS_REQ, (void *)reg);
> > > +       while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_DIS_ACK));
> > > +}
> > > +
> > > +static u32 sifive_tmc0_get_pgprep_enarsp(void)
> > > +{
> > > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> > > +       u32 v = readl((void *)reg);
> > > +
> > > +       return v & SIFIVE_TMC_PGPREP_ENARSP;
> > > +}
> > > +
> > > +static void sifive_tmc0_set_pg_enareq(void)
> > > +{
> > > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PG_OFF;
> > > +       u32 v = readl((void *)reg);
> > > +
> > > +       writel(v | SIFIVE_TMC_PG_ENA_REQ, (void *)reg);
> > > +}
> > > +
> > > +static int sifive_tmc0_prep(void)
> > > +{
> > > +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> > > +       u32 rc;
> > > +
> > > +       if (!tmc0_ptr_get(scratch))
> > > +               return SBI_ENODEV;
> > > +
> > > +       rc = sifive_tmc0_set_pgprep_enareq();
> > > +       if (rc) {
> > > +               sbi_printf("TMC0 error: Internal Abort (Wake detect)\n");
> > > +               goto fail;
> > > +       }
> > > +
> > > +       rc = sifive_tmc0_get_pgprep_enarsp();
> > > +       if (rc) {
> > > +               sifive_tmc0_set_pgprep_disreq();
> > > +               sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
> > > +               goto fail;
> > > +       }
> > > +
> > > +       sifive_tmc0_set_resumepc(scratch->warmboot_addr);
> > > +
> > > +       return SBI_OK;
> > > +
> > > +fail:
> > > +       return SBI_EFAIL;
> > > +}
> > > +
> > > +static int sifive_tmc0_enter(void)
> > > +{
> > > +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> > > +       u32 rc;
> > > +
> > > +       /* Flush cache and check if there is wake detect or bus error */
> > > +       if (fdt_cmo_private_flc_flush_all() &&
> > > +           sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1))
> > > +               sifive_cflush();
> > > +
> > > +       rc = sifive_tmc0_get_pgprep_enarsp();
> > > +       if (rc) {
> > > +               sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
> > > +               goto fail;
> > > +       }
> > > +
> > > +       if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CEASE)) {
> > > +               sifive_tmc0_set_pg_enareq();
> > > +               while (1)
> > > +                       sifive_cease();
> > > +       }
> > > +
> > > +       rc = SBI_ENOTSUPP;
> > > +fail:
> > > +       sifive_tmc0_set_pgprep_disreq();
> > > +       return rc;
> > > +}
> > > +
> > > +static int sifive_tmc0_tile_pg(void)
> > > +{
> > > +       int rc;
> > > +
> > > +       rc = sifive_tmc0_prep();
> > > +       if (rc)
> > > +               return rc;
> > > +
> > > +       return sifive_tmc0_enter();
> > > +}
> > > +
> > > +static struct sifive_tmc0 *sifive_tmc0_find(u32 id)
> > > +{
> > > +       struct sifive_tmc0 *tmc0;
> > > +
> > > +       sbi_list_for_each_entry(tmc0, &tmc0_list, node) {
> > > +               if (tmc0->id == id)
> > > +                       return tmc0;
> > > +       }
> > > +
> > > +       return NULL;
> > > +}
> > > +
> > > +static int sifive_tmc0_add(struct sifive_tmc0 *tmc0)
> > > +{
> > > +       if (!tmc0)
> > > +               return SBI_ENODEV;
> > > +
> > > +       if (sifive_tmc0_find(tmc0->id))
> > > +               return SBI_EALREADY;
> > > +
> > > +       sbi_list_add(&tmc0->node, &tmc0_list);
> > > +
> > > +       return SBI_OK;
> > > +}
> > > +
> > > +static int sifive_tmc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
> > > +{
> > > +       struct sifive_tmc0 *tmc0;
> > > +       int rc;
> > > +       u64 addr;
> > > +
> > > +       tmc0 = sbi_zalloc(sizeof(*tmc0));
> > > +       if (!tmc0)
> > > +               return SBI_ENOMEM;
> > > +
> > > +       rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
> > > +       if (rc)
> > > +               goto free_tmc0;
> > > +
> > > +       tmc0->reg = (unsigned long)addr;
> > > +       tmc0->id = nodeoff;
> > > +
> > > +       rc = sifive_tmc0_add(tmc0);
> > > +       if (rc)
> > > +               goto free_tmc0;
> > > +
> > > +       return SBI_OK;
> > > +
> > > +free_tmc0:
> > > +       sbi_free(tmc0);
> > > +       return rc;
> > > +}
> > > +
> > > +static const struct fdt_match sifive_tmc0_match[] = {
> > > +       { .compatible = "sifive,tmc0" },
> > > +       { },
> > > +};
> > > +
> > > +const struct fdt_driver fdt_hsm_sifive_tmc0 = {
> > > +       .match_table = sifive_tmc0_match,
> > > +       .init = sifive_tmc0_probe,
> > > +};
> > > +
> > > +static const struct fdt_driver *const fdt_hsm_sifive_tmc0_drivers[] = {
> > > +       &fdt_hsm_sifive_tmc0,
> > > +       NULL
> > > +};
> > > +
> > > +static int fdt_sifive_tmc0_get(const void *fdt, int noff, struct sifive_tmc0 **out)
> > > +{
> > > +       struct sifive_tmc0 *tmc0;
> > > +       int rc;
> > > +
> > > +       noff = fdt_node_offset_by_phandle(fdt, noff);
> > > +       if (noff < 0)
> > > +               return noff;
> > > +
> > > +       rc = fdt_driver_init_by_offset(fdt, noff, fdt_hsm_sifive_tmc0_drivers);
> > > +       if (rc)
> > > +               return rc;
> > > +
> > > +       tmc0 = sifive_tmc0_find(noff);
> > > +       if (!tmc0)
> > > +               return SBI_EFAIL;
> > > +
> > > +       if (out)
> > > +               *out = tmc0;
> > > +
> > > +       return SBI_OK;
> > > +}
> > > +
> > > +static int fdt_sifive_tmc0_cold_init(const void *fdt)
> > > +{
> > > +       struct sbi_scratch *scratch;
> > > +       struct sifive_tmc0 *tmc0;
> > > +       const fdt32_t *val;
> > > +       int cpus_off, cpu_off, rc;
> > > +       u32 hartid;
> > > +
> > > +       cpus_off = fdt_path_offset(fdt, "/cpus");
> > > +       if (cpus_off < 0)
> > > +               return SBI_ENOENT;
> > > +
> > > +       fdt_for_each_subnode(cpu_off, fdt, cpus_off) {
> > > +               rc = fdt_parse_hart_id(fdt, cpu_off, &hartid);
> > > +               if (rc)
> > > +                       continue;
> > > +
> > > +               val = fdt_getprop(fdt, cpu_off, "power-domains", NULL);
> > > +               if (!val)
> > > +                       return SBI_ENOENT;
> > > +
> > > +               rc = fdt_sifive_tmc0_get(fdt, fdt32_to_cpu(val[0]), &tmc0);
> > > +               if (rc)
> > > +                       return rc;
> > > +
> > > +               scratch = sbi_hartid_to_scratch(hartid);
> > > +               if (!scratch)
> > > +                       continue;
> > > +
> > > +               tmc0_ptr_set(scratch, tmc0);
> > > +       }
> > > +
> > > +       return SBI_OK;
> > > +}
> > > +
> > > +static int sifive_tmc0_start(u32 hartid, ulong saddr)
> > > +{
> > > +       struct sbi_ipi_device *clint = aclint_mswi_get();
> > > +
> > > +       /*
> > > +        * In system suspend, the IMSIC will be reset in SiFive platform so
> > > +        * we use the CLINT IPI as the wake event.
> > > +        */
> > > +       if (clint && clint->ipi_send)
> > > +               clint->ipi_send(sbi_hartid_to_hartindex(hartid));
> > > +       else
> > > +               sbi_ipi_raw_send(sbi_hartid_to_hartindex(hartid));
> > > +
> > > +       return SBI_OK;
> > > +}
> > > +
> > > +static int sifive_tmc0_stop(void)
> > > +{
> > > +       unsigned long mie = csr_read(CSR_MIE);
> > > +       int rc;
> > > +       // Set IPI as wake up source
> >
> > Please don't use c++ style "//" comments.
> >
> Will fix it in the next version
>
> > > +       csr_set(CSR_MIE, MIP_MEIP | MIP_MSIP);
> > > +
> > > +       rc = sifive_tmc0_tile_pg();
> > > +       if (rc) {
> > > +               csr_write(CSR_MIE, mie);
> > > +               return rc;
> > > +       }
> > > +
> > > +       return SBI_OK;
> > > +}
> > > +
> > > +static struct sbi_hsm_device tmc0_hsm_dev = {
> > > +       .name = "SiFive TMC0",
> > > +       .hart_start = sifive_tmc0_start,
> > > +       .hart_stop = sifive_tmc0_stop,
> > > +};
> > > +
> > > +int fdt_hsm_sifive_tmc0_cold_init(void)
> > > +{
> > > +       int rc;
> > > +
> > > +       tmc0_offset = sbi_scratch_alloc_type_offset(struct sifive_tmc0 *);
> > > +       if (!tmc0_offset)
> > > +               return SBI_ENOMEM;
> > > +
> > > +       rc = fdt_sifive_tmc0_cold_init(fdt_get_address());
> > > +       if (rc)
> > > +               return rc;
> > > +
> > > +       sbi_hsm_set_device(&tmc0_hsm_dev);
> > > +
> > > +       return SBI_OK;
> > > +}
> >
> > Why can't the SiFive TMC driver probe as fdt_early_driver ?
> >
> Yes, it can. This requires updating the logic for binding the TMC to
> the corresponding CPU.
> In the current implementation, we iterate over each CPU DT node to
> probe the TMC driver via its power-domains property and then bind the
> TMC to that CPU.
>
> If the TMC driver is registered as an fdt_early_driver, we instead
> need to iterate over each CPU node during every TMC driver probe and
> bind the TMC to the CPU whose power-domains property references the
> current TMC node.

I think it's better to have the TMC driver as an fdt_early_driver.
If required you can add helper routines to parse power-domain
from the CPU DT node.

Regards,
Anup


