public inbox for opensbi@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver
@ 2025-10-20  6:34 Nick Hu
  2025-10-20  6:34 ` [PATCH v7 01/12] lib: utils: Add cache flush library Nick Hu
                   ` (12 more replies)
  0 siblings, 13 replies; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi
  Cc: Nick Hu, Samuel Holland, Anup Patel, Vincent Chen, Andy Chiu,
	Cyan Yang, Yong-Xuan Wang

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 v7:
- Update the change log of PATCH 9 and PATCH 12 because the TMC0 and SMC0 are moved to the
  lib/utils/hsm and lib/utils/suspend.
- Add new commit to Extend the sbi_ipi_raw_send() to use all available IPI device in
  PATCH 8 and use it in PATCH 9
- Add `system_resume` callback for system suspend
- Since the SMC0 driver need the `aplic_reinit_all()`, update the
  SMC0 Kconfig option to depend upon the APLIC Kconfig option
- Link to v6: https://lore.kernel.org/r/20250905-cache-upstream-v6-0-6a6da629c961@sifive.com

Changes in v6:
- Rename the aplic_restore() to aplic_reinit_all()
- Remove fdt_hsm_sifive_tmc0_cold_init() from TMC0 header file
- Remove the sifive_dev_platform.c
- Add a dummy inline flavor of fdt_cmo_init() for the case where CONFIG_FDT_CACHE is disabled
- Link to v5: https://lore.kernel.org/r/20250902-cache-upstream-v5-0-af60a067f47a@sifive.com

Changes in v5:
- Put the SiFive TMC0 driver to the fdt_early_driver
- Fix the format of the comments in SiFive TMC0 driver

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: sbi: Extends sbi_ipi_raw_send() to use all available IPI devices
  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

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

To: opensbi@lists.infradead.org

---
Nick Hu (11):
      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/irqchip: Add APLIC restore function
      lib: sbi: Extends sbi_ipi_raw_send() to use all available IPI devices
      lib: utils/hsm: Add SiFive TMC0 driver
      lib: utils/timer: Expose timer update function
      lib: sbi: Add system_resume callback for restoring the system
      lib: utils/suspend: Add SiFive SMC0 driver

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

 include/sbi/sbi_hart.h                      |   4 +
 include/sbi/sbi_ipi.h                       |   2 +-
 include/sbi/sbi_system.h                    |   7 +
 include/sbi_utils/cache/cache.h             |  69 ++++++
 include/sbi_utils/cache/fdt_cache.h         |  34 +++
 include/sbi_utils/cache/fdt_cmo_helper.h    |  40 +++
 include/sbi_utils/hsm/fdt_hsm_sifive_inst.h |  20 ++
 include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h |  14 ++
 include/sbi_utils/irqchip/aplic.h           |   3 +
 include/sbi_utils/timer/aclint_mtimer.h     |   5 +
 lib/sbi/sbi_hart.c                          |   2 +
 lib/sbi/sbi_hsm.c                           |   7 +-
 lib/sbi/sbi_ipi.c                           |  16 +-
 lib/sbi/sbi_system.c                        |  17 ++
 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         | 367 ++++++++++++++++++++++++++++
 lib/utils/hsm/objects.mk                    |   3 +
 lib/utils/irqchip/aplic.c                   | 164 +++++++------
 lib/utils/suspend/Kconfig                   |   4 +
 lib/utils/suspend/fdt_suspend_sifive_smc0.c | 318 ++++++++++++++++++++++++
 lib/utils/suspend/objects.mk                |   3 +
 lib/utils/timer/aclint_mtimer.c             |  28 ++-
 platform/generic/andes/ae350.c              |   2 +-
 platform/generic/configs/defconfig          |   4 +
 platform/generic/platform.c                 |   3 +-
 33 files changed, 1520 insertions(+), 83 deletions(-)
---
base-commit: e3eb59a396ac55975e3debecfc5b71418eb62248
change-id: 20250829-cache-upstream-93730838a1a6

Best regards,
-- 
Nick Hu <nick.hu@sifive.com>


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

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v7 01/12] lib: utils: Add cache flush library
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-20  6:34 ` [PATCH v7 02/12] lib: utils: Add FDT cache library Nick Hu
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Nick Hu, Samuel Holland, Anup Patel

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@sifive.com>
Reviewed-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Anup Patel <anup@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(+)

diff --git a/include/sbi_utils/cache/cache.h b/include/sbi_utils/cache/cache.h
new file mode 100644
index 0000000000000000000000000000000000000000..70d9286f9a0a63b8fe13827925163db84f88bdc2
--- /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 901ba564610ce8619f585b31cca3e9eadc358b31..5a5b3b1e0f1c0ce2f638593bcf186b617803110d 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 0000000000000000000000000000000000000000..24aa41bcf966cd42c719d995fa2f9f6ab62ad904
--- /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 0000000000000000000000000000000000000000..6bc3d10e9347e03ad08dcf86f36b77846446e71b
--- /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 0000000000000000000000000000000000000000..21d30ce8e18236eb90d666b884e10918a9a8fa0b
--- /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.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v7 02/12] lib: utils: Add FDT cache library
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
  2025-10-20  6:34 ` [PATCH v7 01/12] lib: utils: Add cache flush library Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-20  6:34 ` [PATCH v7 03/12] utils: cache: Add SiFive ccache controller Nick Hu
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Vincent Chen, Andy Chiu, Nick Hu, Samuel Holland, Anup Patel

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@sifive.com>
Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Co-developed-by: Andy Chiu <andy.chiu@sifive.com>
Signed-off-by: Andy Chiu <andy.chiu@sifive.com>
Signed-off-by: Nick Hu <nick.hu@sifive.com>
Reviewed-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Anup Patel <anup@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(+)

diff --git a/include/sbi_utils/cache/fdt_cache.h b/include/sbi_utils/cache/fdt_cache.h
new file mode 100644
index 0000000000000000000000000000000000000000..b377d6f502ff1496497172a7e09f3cca239003a9
--- /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 24aa41bcf966cd42c719d995fa2f9f6ab62ad904..106021762f33229e66bf91c648c3c9febc4d325c 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 0000000000000000000000000000000000000000..e1c6f67cf6fab5232982a9479931f70b8b0d595c
--- /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 0000000000000000000000000000000000000000..c1b1791c553a69a809a0930081fbff8952d30c74
--- /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 21d30ce8e18236eb90d666b884e10918a9a8fa0b..2fcf9666592700ff7c1fb924c5b9ea2de722fc2a 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 fb90bb3e3c561fa169d8aeb6aed80f5146f0254f..7107e225cdd78287a296ca898c33659ecc89c969 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -9,6 +9,7 @@ CONFIG_PLATFORM_STARFIVE_JH7110=y
 CONFIG_PLATFORM_THEAD=y
 CONFIG_PLATFORM_MIPS_P8700=y
 CONFIG_PLATFORM_OPENHWGROUP_OPENPITON=y
+CONFIG_FDT_CACHE=y
 CONFIG_FDT_CPPC=y
 CONFIG_FDT_CPPC_RPMI=y
 CONFIG_FDT_GPIO=y

-- 
2.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v7 03/12] utils: cache: Add SiFive ccache controller
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
  2025-10-20  6:34 ` [PATCH v7 01/12] lib: utils: Add cache flush library Nick Hu
  2025-10-20  6:34 ` [PATCH v7 02/12] lib: utils: Add FDT cache library Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-20  6:34 ` [PATCH v7 04/12] lib: utils/cache: Add fdt cmo helpers Nick Hu
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Vincent Chen, Samuel Holland, Nick Hu, Anup Patel

From: Vincent Chen <vincent.chen@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@sifive.com>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Co-developed-by: Nick Hu <nick.hu@sifive.com>
Signed-off-by: Nick Hu <nick.hu@sifive.com>
Reviewed-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Anup Patel <anup@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(+)

diff --git a/lib/utils/cache/Kconfig b/lib/utils/cache/Kconfig
index 106021762f33229e66bf91c648c3c9febc4d325c..1c7abdc9ad93319569807b4e25623cac871c6ce3 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 0000000000000000000000000000000000000000..b641ed163421bb046c70332299defaa9675b62f5
--- /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 2fcf9666592700ff7c1fb924c5b9ea2de722fc2a..a343eb8c4bd495a1596845c1fd02420277023430 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 7107e225cdd78287a296ca898c33659ecc89c969..86decbd0755e74c658b23e0097d103ded25a10d1 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -10,6 +10,7 @@ CONFIG_PLATFORM_THEAD=y
 CONFIG_PLATFORM_MIPS_P8700=y
 CONFIG_PLATFORM_OPENHWGROUP_OPENPITON=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.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v7 04/12] lib: utils/cache: Add fdt cmo helpers
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
                   ` (2 preceding siblings ...)
  2025-10-20  6:34 ` [PATCH v7 03/12] utils: cache: Add SiFive ccache controller Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-28  5:54   ` Anup Patel
  2025-10-20  6:34 ` [PATCH v7 05/12] lib: sbi: Add SiFive proprietary xsfcflushdlone Nick Hu
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Nick Hu, Samuel Holland, Anup Patel

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@sifive.com>
Reviewed-by: Samuel Holland <samuel.holland@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
---
 include/sbi_utils/cache/fdt_cmo_helper.h |  40 +++++++++++
 lib/utils/cache/fdt_cmo_helper.c         | 112 +++++++++++++++++++++++++++++++
 lib/utils/cache/objects.mk               |   1 +
 platform/generic/platform.c              |   3 +-
 4 files changed, 155 insertions(+), 1 deletion(-)

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 0000000000000000000000000000000000000000..a6a28db9ede2722d8261d2e077eeb7710cff0893
--- /dev/null
+++ b/include/sbi_utils/cache/fdt_cmo_helper.h
@@ -0,0 +1,40 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#ifndef __FDT_CMO_HELPER_H__
+#define __FDT_CMO_HELPER_H__
+
+#ifdef CONFIG_FDT_CACHE
+/**
+ * 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);
+
+#else
+
+static inline int fdt_cmo_init(bool cold_boot) { return 0; }
+
+#endif /* CONFIG_FDT_CACHE */
+#endif /* __FDT_CMO_HELPER_H__ */
diff --git a/lib/utils/cache/fdt_cmo_helper.c b/lib/utils/cache/fdt_cmo_helper.c
new file mode 100644
index 0000000000000000000000000000000000000000..6d2e853dd735735092c57db2398f97a64de3ab5e
--- /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 a343eb8c4bd495a1596845c1fd02420277023430..6829a966784732127d93180b3eb46ed24de5bc7d 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 91140958a0f4294428221c91fe2792eb6b1b02d5..e66f99fa8a88d1badd3843305e34486a548bf465 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>
@@ -230,7 +231,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.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v7 05/12] lib: sbi: Add SiFive proprietary xsfcflushdlone
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
                   ` (3 preceding siblings ...)
  2025-10-20  6:34 ` [PATCH v7 04/12] lib: utils/cache: Add fdt cmo helpers Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-20  6:34 ` [PATCH v7 06/12] lib: sbi: Add SiFive proprietary xsfcease Nick Hu
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Cyan Yang, Anup Patel, Nick Hu

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

Reviewed-by: Cyan Yang <cyan.yang@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Nick Hu <nick.hu@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 82b19dcfd4582b39e1dafb6bdb41d2fbe77dc419..fdcf400aa8c494cd941c412294bd0c118c5ec2af 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 1b50f67198d5c2416b3db988c4ac05eba6b9cd53..4159dff54387f677d4fddcf115ebc9f9ed9be86d 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.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v7 06/12] lib: sbi: Add SiFive proprietary xsfcease
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
                   ` (4 preceding siblings ...)
  2025-10-20  6:34 ` [PATCH v7 05/12] lib: sbi: Add SiFive proprietary xsfcflushdlone Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-20  6:34 ` [PATCH v7 07/12] lib: utils/irqchip: Add APLIC restore function Nick Hu
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Cyan Yang, Anup Patel, Nick Hu

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

Reviewed-by: Cyan Yang <cyan.yang@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Nick Hu <nick.hu@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 fdcf400aa8c494cd941c412294bd0c118c5ec2af..ff682fb4579291cd9e5fb36ca5ab392aa376d37f 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 4159dff54387f677d4fddcf115ebc9f9ed9be86d..de1358180f208dd9ca9bf2feeb43ab648999847e 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.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v7 07/12] lib: utils/irqchip: Add APLIC restore function
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
                   ` (5 preceding siblings ...)
  2025-10-20  6:34 ` [PATCH v7 06/12] lib: sbi: Add SiFive proprietary xsfcease Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-20  6:34 ` [PATCH v7 08/12] lib: sbi: Extends sbi_ipi_raw_send() to use all available IPI devices Nick Hu
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Yong-Xuan Wang, Cyan Yang, Anup Patel, Nick Hu

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.

Reviewed-by: Yong-Xuan Wang <yongxuan.wang@sifive.com>
Reviewed-by: Cyan Yang <cyan.yang@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Nick Hu <nick.hu@sifive.com>
---
 include/sbi_utils/irqchip/aplic.h |   3 +
 lib/utils/irqchip/aplic.c         | 164 ++++++++++++++++++++++----------------
 2 files changed, 99 insertions(+), 68 deletions(-)

diff --git a/include/sbi_utils/irqchip/aplic.h b/include/sbi_utils/irqchip/aplic.h
index e31f48a45019e1874e3223e3fb232f553890d06d..cbfcd3fd17bc09a644bf47e7d2716123c25a305e 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_reinit_all(void);
+
 #endif
diff --git a/lib/utils/irqchip/aplic.c b/lib/utils/irqchip/aplic.c
index efaaf0ca5b0e672e71a954d84029b0792ea539c0..8d0db1681583a397bbcec65c5033229752b080df 100644
--- a/lib/utils/irqchip/aplic.c
+++ b/lib/utils/irqchip/aplic.c
@@ -115,6 +115,90 @@
 #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)
+{
+	struct aplic_delegate_data *deleg;
+	u32 i, j, tmp;
+	int locked;
+
+	/* 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 */
+	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 && !locked) {
+		aplic_writel_msicfg(&aplic->msicfg_smode,
+				    (void *)(aplic->addr + APLIC_SMSICFGADDR),
+				    (void *)(aplic->addr + APLIC_SMSICFGADDRH));
+	}
+}
+
+void aplic_reinit_all(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)
 {
@@ -163,10 +247,9 @@ static int aplic_check_msicfg(struct aplic_msicfg_data *msicfg)
 
 int aplic_cold_irqchip_init(struct aplic_data *aplic)
 {
-	int rc, locked;
-	u32 i, j, tmp;
+	int rc;
 	struct aplic_delegate_data *deleg;
-	u32 first_deleg_irq, last_deleg_irq;
+	u32 first_deleg_irq, last_deleg_irq, i;
 
 	/* Sanity checks */
 	if (!aplic ||
@@ -184,82 +267,24 @@ int aplic_cold_irqchip_init(struct aplic_data *aplic)
 			return rc;
 	}
 
-	/* Set domain configuration to 0 */
-	writel(0, (void *)(aplic->addr + APLIC_DOMAINCFG));
+	/* Init the APLIC registers */
+	aplic_init(aplic);
 
-	/* 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 */
+	/*
+	 * 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 */
-	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 && !locked) {
-		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) &&
@@ -275,5 +300,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.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v7 08/12] lib: sbi: Extends sbi_ipi_raw_send() to use all available IPI devices
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
                   ` (6 preceding siblings ...)
  2025-10-20  6:34 ` [PATCH v7 07/12] lib: utils/irqchip: Add APLIC restore function Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-28  4:59   ` Anup Patel
  2025-10-20  6:34 ` [PATCH v7 09/12] lib: utils/hsm: Add SiFive TMC0 driver Nick Hu
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Anup Patel, Nick Hu

A platform may contain multiple IPI devices. In certain use cases,
such as power management, it may be necessary to send an IPI through a
specific device to wake up a CPU. For example, if an IMSIC is powered
down and reset, the core cannot receive IPIs from it, so the wake-up must
instead be triggered through the CLINT.

Suggested-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Nick Hu <nick.hu@sifive.com>
---
 include/sbi/sbi_ipi.h          |  2 +-
 lib/sbi/sbi_hsm.c              |  2 +-
 lib/sbi/sbi_ipi.c              | 16 +++++++++++++---
 platform/generic/andes/ae350.c |  2 +-
 4 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/include/sbi/sbi_ipi.h b/include/sbi/sbi_ipi.h
index 26d1b66b7cfffbaa6f7cadd0fab8c810adfb1811..2c231041662bfb55b2f962ca48d724cf6aa53f6d 100644
--- a/include/sbi/sbi_ipi.h
+++ b/include/sbi/sbi_ipi.h
@@ -88,7 +88,7 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
 
 void sbi_ipi_process(void);
 
-int sbi_ipi_raw_send(u32 hartindex);
+int sbi_ipi_raw_send(u32 hartindex, bool all_devices);
 
 void sbi_ipi_raw_clear(bool all_devices);
 
diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
index bb274b33d6ee5e3db9953f4b591502e4522d99d1..0d97b43e0cd8f7b4fc97407ef01007485e3f5a24 100644
--- a/lib/sbi/sbi_hsm.c
+++ b/lib/sbi/sbi_hsm.c
@@ -364,7 +364,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
 	   (hsm_device_has_hart_secondary_boot() && !init_count)) {
 		rc = hsm_device_hart_start(hartid, scratch->warmboot_addr);
 	} else {
-		rc = sbi_ipi_raw_send(hartindex);
+		rc = sbi_ipi_raw_send(hartindex, true);
 	}
 
 	if (!rc)
diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c
index ed9ccffb6c96cdfa1151a22d07c2bfc8181769bd..5b2d2f72eeb918a8877b4b8fbf201f2b9628f069 100644
--- a/lib/sbi/sbi_ipi.c
+++ b/lib/sbi/sbi_ipi.c
@@ -88,7 +88,7 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartindex,
 	 */
 	if (!__atomic_fetch_or(&ipi_data->ipi_type,
 				BIT(event), __ATOMIC_RELAXED))
-		ret = sbi_ipi_raw_send(remote_hartindex);
+		ret = sbi_ipi_raw_send(remote_hartindex, false);
 
 	sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_SENT);
 
@@ -271,8 +271,10 @@ void sbi_ipi_process(void)
 	}
 }
 
-int sbi_ipi_raw_send(u32 hartindex)
+int sbi_ipi_raw_send(u32 hartindex, bool all_devices)
 {
+	struct sbi_ipi_device_node *entry;
+
 	if (!ipi_dev || !ipi_dev->ipi_send)
 		return SBI_EINVAL;
 
@@ -287,7 +289,15 @@ int sbi_ipi_raw_send(u32 hartindex)
 	 */
 	wmb();
 
-	ipi_dev->ipi_send(hartindex);
+	if (all_devices) {
+		sbi_list_for_each_entry(entry, &ipi_dev_node_list, head) {
+			if (entry->dev->ipi_send)
+				entry->dev->ipi_send(hartindex);
+		}
+	} else {
+		ipi_dev->ipi_send(hartindex);
+	}
+
 	return 0;
 }
 
diff --git a/platform/generic/andes/ae350.c b/platform/generic/andes/ae350.c
index f06e207d80f58703098ef805a14e1f8764c2cb16..0808065745af21f5d65f0114ca33a23949280296 100644
--- a/platform/generic/andes/ae350.c
+++ b/platform/generic/andes/ae350.c
@@ -35,7 +35,7 @@ static int ae350_hart_start(u32 hartid, ulong saddr)
 	 * 2) the target hart is non-sleepable 25-series hart0
 	 */
 	if (!sbi_init_count(hartindex) || (is_andes(25) && hartid == 0))
-		return sbi_ipi_raw_send(hartindex);
+		return sbi_ipi_raw_send(hartindex, false);
 
 	/* Write wakeup command to the sleep hart */
 	smu_set_command(&smu, WAKEUP_CMD, hartid);

-- 
2.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v7 09/12] lib: utils/hsm: Add SiFive TMC0 driver
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
                   ` (7 preceding siblings ...)
  2025-10-20  6:34 ` [PATCH v7 08/12] lib: sbi: Extends sbi_ipi_raw_send() to use all available IPI devices Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-28  5:00   ` Anup Patel
  2025-10-20  6:34 ` [PATCH v7 10/12] lib: utils/timer: Expose timer update function Nick Hu
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Vincent Chen, Cyan Yang, Nick Hu

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@sifive.com>
Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
Reviewed-by: Cyan Yang <cyan.yang@sifive.com>
Signed-off-by: Nick Hu <nick.hu@sifive.com>
---
 include/sbi_utils/hsm/fdt_hsm_sifive_inst.h |  20 ++
 lib/utils/hsm/Kconfig                       |   5 +
 lib/utils/hsm/fdt_hsm_sifive_tmc0.c         | 310 ++++++++++++++++++++++++++++
 lib/utils/hsm/objects.mk                    |   3 +
 platform/generic/configs/defconfig          |   1 +
 5 files changed, 339 insertions(+)

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 0000000000000000000000000000000000000000..de8aba190fd782e497e6f71662e734fac7b076fe
--- /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/lib/utils/hsm/Kconfig b/lib/utils/hsm/Kconfig
index 1ad7958fb582a3ee561dfaec4afd738054b58906..5861b064aa35c14a8b3f78e61a4e27ae0482258e 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 FDT_CACHE
+	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 0000000000000000000000000000000000000000..8b08a7d1bf025f033ee0ebbe02fb97c70d0afeef
--- /dev/null
+++ b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
@@ -0,0 +1,310 @@
+/*
+ * 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>
+
+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 int sifive_tmc0_start(u32 hartid, ulong saddr)
+{
+	/*
+	 * In system suspend, the IMSIC will be reset in SiFive platform so
+	 * we use the CLINT IPI as the wake event.
+	 */
+	sbi_ipi_raw_send(sbi_hartid_to_hartindex(hartid), true);
+
+	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,
+};
+
+static int sifive_tmc0_bind_cpu(struct sifive_tmc0 *tmc0)
+{
+	const void *fdt = fdt_get_address();
+	struct sbi_scratch *scratch;
+	int cpus_off, cpu_off, rc;
+	const fdt32_t *val;
+	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;
+
+		scratch = sbi_hartid_to_scratch(hartid);
+		if (!scratch)
+			continue;
+
+		val = fdt_getprop(fdt, cpu_off, "power-domains", NULL);
+		if (!val)
+			return SBI_ENOENT;
+
+		if (tmc0->id == fdt32_to_cpu(val[0])) {
+			tmc0_ptr_set(scratch, tmc0);
+			return SBI_OK;
+		}
+	}
+
+	return SBI_ENODEV;
+}
+
+static int sifive_tmc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
+{
+	struct sifive_tmc0 *tmc0;
+	u64 addr;
+	int rc;
+
+	if (!tmc0_offset) {
+		tmc0_offset = sbi_scratch_alloc_type_offset(struct sifive_tmc0 *);
+		if (!tmc0_offset)
+			return SBI_ENOMEM;
+
+		sbi_hsm_set_device(&tmc0_hsm_dev);
+	}
+
+	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 = fdt_get_phandle(fdt_get_address(), nodeoff);
+
+	rc = sifive_tmc0_bind_cpu(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,
+};
diff --git a/lib/utils/hsm/objects.mk b/lib/utils/hsm/objects.mk
index c13d81f78dd69ceb37cf83b19b10bc95c3dcfaff..6fbae628aa615e8ddcd41d01973303f2e36100d1 100644
--- a/lib/utils/hsm/objects.mk
+++ b/lib/utils/hsm/objects.mk
@@ -9,3 +9,6 @@
 
 carray-fdt_early_drivers-$(CONFIG_FDT_HSM_RPMI) += fdt_hsm_rpmi
 libsbiutils-objs-$(CONFIG_FDT_HSM_RPMI) += hsm/fdt_hsm_rpmi.o
+
+carray-fdt_early_drivers-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += fdt_hsm_sifive_tmc0
+libsbiutils-objs-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += hsm/fdt_hsm_sifive_tmc0.o
\ No newline at end of file
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 86decbd0755e74c658b23e0097d103ded25a10d1..897d552813121f22c812e9760d2b144f41141c49 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -19,6 +19,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

-- 
2.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v7 10/12] lib: utils/timer: Expose timer update function
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
                   ` (8 preceding siblings ...)
  2025-10-20  6:34 ` [PATCH v7 09/12] lib: utils/hsm: Add SiFive TMC0 driver Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-20  6:34 ` [PATCH v7 11/12] lib: sbi: Add system_resume callback for restoring the system Nick Hu
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Cyan Yang, Anup Patel, Nick Hu

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

Reviewed-by: Cyan Yang <cyan.yang@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Nick Hu <nick.hu@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 a245e13e285f2ad658fce7db6366fe8b7bae8c2a..f8d2e5b4c210164c8a737e82643e5e49807753c4 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 3db3c3be2575e4ddd0180c90f254f7733b7c1daa..fd6189aaa52ad92ca28330fcf0f701ac0b8c337f 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.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v7 11/12] lib: sbi: Add system_resume callback for restoring the system
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
                   ` (9 preceding siblings ...)
  2025-10-20  6:34 ` [PATCH v7 10/12] lib: utils/timer: Expose timer update function Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-28  5:01   ` Anup Patel
  2025-10-20  6:34 ` [PATCH v7 12/12] lib: utils/suspend: Add SiFive SMC0 driver Nick Hu
  2025-10-28  6:02 ` [PATCH v7 00/12] Add SiFive TMC0 and " Anup Patel
  12 siblings, 1 reply; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Anup Patel, Nick Hu

The last core who performs the system suspend is responsible for
restoring the system after waking up. Add the system_resume callback for
restoring the system from suspend.

Suggested-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Nick Hu <nick.hu@sifive.com>
---
 include/sbi/sbi_system.h |  7 +++++++
 lib/sbi/sbi_hsm.c        |  5 ++++-
 lib/sbi/sbi_system.c     | 17 +++++++++++++++++
 3 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/include/sbi/sbi_system.h b/include/sbi/sbi_system.h
index 0fdcc98cce5dac43583e68ffa8c98e79fd95dad4..f48a019a06b6957b5ab9cb4b9ef795a899a34ff9 100644
--- a/include/sbi/sbi_system.h
+++ b/include/sbi/sbi_system.h
@@ -69,11 +69,18 @@ struct sbi_system_suspend_device {
 	 *     return from system_suspend() may ignore this parameter.
 	 */
 	int (*system_suspend)(u32 sleep_type, unsigned long mmode_resume_addr);
+
+	/**
+	 * Resume the system from system suspend
+	 */
+	void (*system_resume)(void);
 };
 
 const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void);
 void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev);
 void sbi_system_suspend_test_enable(void);
+void sbi_system_resume(void);
+bool sbi_system_is_suspended(void);
 bool sbi_system_suspend_supported(u32 sleep_type);
 int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque);
 
diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
index 0d97b43e0cd8f7b4fc97407ef01007485e3f5a24..0a355f9c2372075aaf303cba2aa5683993c4c079 100644
--- a/lib/sbi/sbi_hsm.c
+++ b/lib/sbi/sbi_hsm.c
@@ -455,7 +455,10 @@ void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
 					 SBI_HSM_STATE_RESUME_PENDING))
 		sbi_hart_hang();
 
-	hsm_device_hart_resume();
+	if (sbi_system_is_suspended())
+		sbi_system_resume();
+	else
+		hsm_device_hart_resume();
 }
 
 void __noreturn sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch,
diff --git a/lib/sbi/sbi_system.c b/lib/sbi/sbi_system.c
index cd0f4ba42bbe67e606bc821870716f7342eaf0d2..5500b05d22882bd43d84a1b715529cd8a26bee3f 100644
--- a/lib/sbi/sbi_system.c
+++ b/lib/sbi/sbi_system.c
@@ -87,6 +87,7 @@ void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
 }
 
 static const struct sbi_system_suspend_device *suspend_dev = NULL;
+static bool system_suspended;
 
 const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void)
 {
@@ -137,6 +138,19 @@ bool sbi_system_suspend_supported(u32 sleep_type)
 	       suspend_dev->system_suspend_check(sleep_type) == 0;
 }
 
+bool sbi_system_is_suspended(void)
+{
+	return system_suspended;
+}
+
+void sbi_system_resume(void)
+{
+	if (suspend_dev && suspend_dev->system_resume)
+		suspend_dev->system_resume();
+
+	system_suspended = false;
+}
+
 int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
 {
 	struct sbi_domain *dom = sbi_domain_thishart_ptr();
@@ -189,11 +203,14 @@ int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
 	__sbi_hsm_suspend_non_ret_save(scratch);
 
 	/* Suspend */
+	system_suspended = true;
 	ret = suspend_dev->system_suspend(sleep_type, scratch->warmboot_addr);
 	if (ret != SBI_OK) {
 		if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_SUSPENDED,
 					       SBI_HSM_STATE_STARTED))
 			sbi_hart_hang();
+
+		system_suspended = false;
 		return ret;
 	}
 

-- 
2.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v7 12/12] lib: utils/suspend: Add SiFive SMC0 driver
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
                   ` (10 preceding siblings ...)
  2025-10-20  6:34 ` [PATCH v7 11/12] lib: sbi: Add system_resume callback for restoring the system Nick Hu
@ 2025-10-20  6:34 ` Nick Hu
  2025-10-28  6:02 ` [PATCH v7 00/12] Add SiFive TMC0 and " Anup Patel
  12 siblings, 0 replies; 18+ messages in thread
From: Nick Hu @ 2025-10-20  6:34 UTC (permalink / raw)
  To: opensbi; +Cc: Cyan Yang, Anup Patel, Nick Hu

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.

Reviewed-by: Cyan Yang <cyan.yang@sifive.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Nick Hu <nick.hu@sifive.com>
---
 include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h |  14 ++
 lib/utils/hsm/fdt_hsm_sifive_tmc0.c         |  57 +++++
 lib/utils/suspend/Kconfig                   |   4 +
 lib/utils/suspend/fdt_suspend_sifive_smc0.c | 318 ++++++++++++++++++++++++++++
 lib/utils/suspend/objects.mk                |   3 +
 platform/generic/configs/defconfig          |   1 +
 6 files changed, 397 insertions(+)

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 0000000000000000000000000000000000000000..06cfb390f6af32f11856d869caf52b212aceb9b0
--- /dev/null
+++ b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
@@ -0,0 +1,14 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 SiFive Inc.
+ */
+
+#ifndef __FDT_HSM_SIFIVE_TMC0_H__
+#define __FDT_HSM_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);
+
+#endif
diff --git a/lib/utils/hsm/fdt_hsm_sifive_tmc0.c b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
index 8b08a7d1bf025f033ee0ebbe02fb97c70d0afeef..2690a638d6e83ddf546f4958c4f8543b981e31dc 100644
--- a/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
+++ b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
@@ -18,6 +18,7 @@
 #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>
 
 struct sifive_tmc0 {
 	unsigned long reg;
@@ -77,6 +78,62 @@ 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 void sifive_tmc0_set_resumepc(physical_addr_t addr)
 {
 	struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
diff --git a/lib/utils/suspend/Kconfig b/lib/utils/suspend/Kconfig
index 2cbea75c265fa1995c7ee7a5f5f9e0b7369418fc..6c09d95253d2cd5a57c5f2676f8e65dddd8676f0 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 && IRQCHIP_APLIC
+	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 0000000000000000000000000000000000000000..7a23e68bf2b1494c01fe2cad56d4977a9e7aaf4a
--- /dev/null
+++ b/lib/utils/suspend/fdt_suspend_sifive_smc0.c
@@ -0,0 +1,318 @@
+/*
+ * 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/irqchip/aplic.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);
+}
+
+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 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_system_suspend_check(u32 sleep_type)
+{
+	return sleep_type == SBI_SUSP_SLEEP_TYPE_SUSPEND ? SBI_OK : SBI_EINVAL;
+}
+
+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 void sifive_smc0_system_resume(void)
+{
+	aplic_reinit_all();
+	sifive_smc0_mtime_update();
+}
+
+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,
+	.system_resume = sifive_smc0_system_resume,
+};
+
+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 9c386248be3074e1cb0a037903926a4fda982cd1..1fb29b5e794123986bc7167bb92504bcf4d3eb09 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 897d552813121f22c812e9760d2b144f41141c49..554c5e1bc69243b572e570a1bd3221b3c3fd1db0 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -56,6 +56,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.34.1


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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v7 08/12] lib: sbi: Extends sbi_ipi_raw_send() to use all available IPI devices
  2025-10-20  6:34 ` [PATCH v7 08/12] lib: sbi: Extends sbi_ipi_raw_send() to use all available IPI devices Nick Hu
@ 2025-10-28  4:59   ` Anup Patel
  0 siblings, 0 replies; 18+ messages in thread
From: Anup Patel @ 2025-10-28  4:59 UTC (permalink / raw)
  To: Nick Hu; +Cc: opensbi

On Mon, Oct 20, 2025 at 11:57 AM Nick Hu <nick.hu@sifive.com> wrote:
>
> A platform may contain multiple IPI devices. In certain use cases,
> such as power management, it may be necessary to send an IPI through a
> specific device to wake up a CPU. For example, if an IMSIC is powered
> down and reset, the core cannot receive IPIs from it, so the wake-up must
> instead be triggered through the CLINT.
>
> Suggested-by: Anup Patel <anup@brainfault.org>
> Signed-off-by: Nick Hu <nick.hu@sifive.com>

LGTM.

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

Regards,
Anup

> ---
>  include/sbi/sbi_ipi.h          |  2 +-
>  lib/sbi/sbi_hsm.c              |  2 +-
>  lib/sbi/sbi_ipi.c              | 16 +++++++++++++---
>  platform/generic/andes/ae350.c |  2 +-
>  4 files changed, 16 insertions(+), 6 deletions(-)
>
> diff --git a/include/sbi/sbi_ipi.h b/include/sbi/sbi_ipi.h
> index 26d1b66b7cfffbaa6f7cadd0fab8c810adfb1811..2c231041662bfb55b2f962ca48d724cf6aa53f6d 100644
> --- a/include/sbi/sbi_ipi.h
> +++ b/include/sbi/sbi_ipi.h
> @@ -88,7 +88,7 @@ int sbi_ipi_send_halt(ulong hmask, ulong hbase);
>
>  void sbi_ipi_process(void);
>
> -int sbi_ipi_raw_send(u32 hartindex);
> +int sbi_ipi_raw_send(u32 hartindex, bool all_devices);
>
>  void sbi_ipi_raw_clear(bool all_devices);
>
> diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
> index bb274b33d6ee5e3db9953f4b591502e4522d99d1..0d97b43e0cd8f7b4fc97407ef01007485e3f5a24 100644
> --- a/lib/sbi/sbi_hsm.c
> +++ b/lib/sbi/sbi_hsm.c
> @@ -364,7 +364,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
>            (hsm_device_has_hart_secondary_boot() && !init_count)) {
>                 rc = hsm_device_hart_start(hartid, scratch->warmboot_addr);
>         } else {
> -               rc = sbi_ipi_raw_send(hartindex);
> +               rc = sbi_ipi_raw_send(hartindex, true);
>         }
>
>         if (!rc)
> diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c
> index ed9ccffb6c96cdfa1151a22d07c2bfc8181769bd..5b2d2f72eeb918a8877b4b8fbf201f2b9628f069 100644
> --- a/lib/sbi/sbi_ipi.c
> +++ b/lib/sbi/sbi_ipi.c
> @@ -88,7 +88,7 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 remote_hartindex,
>          */
>         if (!__atomic_fetch_or(&ipi_data->ipi_type,
>                                 BIT(event), __ATOMIC_RELAXED))
> -               ret = sbi_ipi_raw_send(remote_hartindex);
> +               ret = sbi_ipi_raw_send(remote_hartindex, false);
>
>         sbi_pmu_ctr_incr_fw(SBI_PMU_FW_IPI_SENT);
>
> @@ -271,8 +271,10 @@ void sbi_ipi_process(void)
>         }
>  }
>
> -int sbi_ipi_raw_send(u32 hartindex)
> +int sbi_ipi_raw_send(u32 hartindex, bool all_devices)
>  {
> +       struct sbi_ipi_device_node *entry;
> +
>         if (!ipi_dev || !ipi_dev->ipi_send)
>                 return SBI_EINVAL;
>
> @@ -287,7 +289,15 @@ int sbi_ipi_raw_send(u32 hartindex)
>          */
>         wmb();
>
> -       ipi_dev->ipi_send(hartindex);
> +       if (all_devices) {
> +               sbi_list_for_each_entry(entry, &ipi_dev_node_list, head) {
> +                       if (entry->dev->ipi_send)
> +                               entry->dev->ipi_send(hartindex);
> +               }
> +       } else {
> +               ipi_dev->ipi_send(hartindex);
> +       }
> +
>         return 0;
>  }
>
> diff --git a/platform/generic/andes/ae350.c b/platform/generic/andes/ae350.c
> index f06e207d80f58703098ef805a14e1f8764c2cb16..0808065745af21f5d65f0114ca33a23949280296 100644
> --- a/platform/generic/andes/ae350.c
> +++ b/platform/generic/andes/ae350.c
> @@ -35,7 +35,7 @@ static int ae350_hart_start(u32 hartid, ulong saddr)
>          * 2) the target hart is non-sleepable 25-series hart0
>          */
>         if (!sbi_init_count(hartindex) || (is_andes(25) && hartid == 0))
> -               return sbi_ipi_raw_send(hartindex);
> +               return sbi_ipi_raw_send(hartindex, false);
>
>         /* Write wakeup command to the sleep hart */
>         smu_set_command(&smu, WAKEUP_CMD, hartid);
>
> --
> 2.34.1
>

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

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v7 09/12] lib: utils/hsm: Add SiFive TMC0 driver
  2025-10-20  6:34 ` [PATCH v7 09/12] lib: utils/hsm: Add SiFive TMC0 driver Nick Hu
@ 2025-10-28  5:00   ` Anup Patel
  0 siblings, 0 replies; 18+ messages in thread
From: Anup Patel @ 2025-10-28  5:00 UTC (permalink / raw)
  To: Nick Hu; +Cc: opensbi, Vincent Chen, Cyan Yang

On Mon, Oct 20, 2025 at 11:57 AM Nick Hu <nick.hu@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@sifive.com>
> Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
> Reviewed-by: Cyan Yang <cyan.yang@sifive.com>
> Signed-off-by: Nick Hu <nick.hu@sifive.com>

LGTM.

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

Regards,
Anup

> ---
>  include/sbi_utils/hsm/fdt_hsm_sifive_inst.h |  20 ++
>  lib/utils/hsm/Kconfig                       |   5 +
>  lib/utils/hsm/fdt_hsm_sifive_tmc0.c         | 310 ++++++++++++++++++++++++++++
>  lib/utils/hsm/objects.mk                    |   3 +
>  platform/generic/configs/defconfig          |   1 +
>  5 files changed, 339 insertions(+)
>
> 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 0000000000000000000000000000000000000000..de8aba190fd782e497e6f71662e734fac7b076fe
> --- /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/lib/utils/hsm/Kconfig b/lib/utils/hsm/Kconfig
> index 1ad7958fb582a3ee561dfaec4afd738054b58906..5861b064aa35c14a8b3f78e61a4e27ae0482258e 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 FDT_CACHE
> +       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 0000000000000000000000000000000000000000..8b08a7d1bf025f033ee0ebbe02fb97c70d0afeef
> --- /dev/null
> +++ b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> @@ -0,0 +1,310 @@
> +/*
> + * 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>
> +
> +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 int sifive_tmc0_start(u32 hartid, ulong saddr)
> +{
> +       /*
> +        * In system suspend, the IMSIC will be reset in SiFive platform so
> +        * we use the CLINT IPI as the wake event.
> +        */
> +       sbi_ipi_raw_send(sbi_hartid_to_hartindex(hartid), true);
> +
> +       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,
> +};
> +
> +static int sifive_tmc0_bind_cpu(struct sifive_tmc0 *tmc0)
> +{
> +       const void *fdt = fdt_get_address();
> +       struct sbi_scratch *scratch;
> +       int cpus_off, cpu_off, rc;
> +       const fdt32_t *val;
> +       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;
> +
> +               scratch = sbi_hartid_to_scratch(hartid);
> +               if (!scratch)
> +                       continue;
> +
> +               val = fdt_getprop(fdt, cpu_off, "power-domains", NULL);
> +               if (!val)
> +                       return SBI_ENOENT;
> +
> +               if (tmc0->id == fdt32_to_cpu(val[0])) {
> +                       tmc0_ptr_set(scratch, tmc0);
> +                       return SBI_OK;
> +               }
> +       }
> +
> +       return SBI_ENODEV;
> +}
> +
> +static int sifive_tmc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
> +{
> +       struct sifive_tmc0 *tmc0;
> +       u64 addr;
> +       int rc;
> +
> +       if (!tmc0_offset) {
> +               tmc0_offset = sbi_scratch_alloc_type_offset(struct sifive_tmc0 *);
> +               if (!tmc0_offset)
> +                       return SBI_ENOMEM;
> +
> +               sbi_hsm_set_device(&tmc0_hsm_dev);
> +       }
> +
> +       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 = fdt_get_phandle(fdt_get_address(), nodeoff);
> +
> +       rc = sifive_tmc0_bind_cpu(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,
> +};
> diff --git a/lib/utils/hsm/objects.mk b/lib/utils/hsm/objects.mk
> index c13d81f78dd69ceb37cf83b19b10bc95c3dcfaff..6fbae628aa615e8ddcd41d01973303f2e36100d1 100644
> --- a/lib/utils/hsm/objects.mk
> +++ b/lib/utils/hsm/objects.mk
> @@ -9,3 +9,6 @@
>
>  carray-fdt_early_drivers-$(CONFIG_FDT_HSM_RPMI) += fdt_hsm_rpmi
>  libsbiutils-objs-$(CONFIG_FDT_HSM_RPMI) += hsm/fdt_hsm_rpmi.o
> +
> +carray-fdt_early_drivers-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += fdt_hsm_sifive_tmc0
> +libsbiutils-objs-$(CONFIG_FDT_HSM_SIFIVE_TMC0) += hsm/fdt_hsm_sifive_tmc0.o
> \ No newline at end of file
> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> index 86decbd0755e74c658b23e0097d103ded25a10d1..897d552813121f22c812e9760d2b144f41141c49 100644
> --- a/platform/generic/configs/defconfig
> +++ b/platform/generic/configs/defconfig
> @@ -19,6 +19,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
>
> --
> 2.34.1
>
>
> --
> opensbi mailing list
> opensbi@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi

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

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v7 11/12] lib: sbi: Add system_resume callback for restoring the system
  2025-10-20  6:34 ` [PATCH v7 11/12] lib: sbi: Add system_resume callback for restoring the system Nick Hu
@ 2025-10-28  5:01   ` Anup Patel
  0 siblings, 0 replies; 18+ messages in thread
From: Anup Patel @ 2025-10-28  5:01 UTC (permalink / raw)
  To: Nick Hu; +Cc: opensbi

On Mon, Oct 20, 2025 at 11:57 AM Nick Hu <nick.hu@sifive.com> wrote:
>
> The last core who performs the system suspend is responsible for
> restoring the system after waking up. Add the system_resume callback for
> restoring the system from suspend.
>
> Suggested-by: Anup Patel <anup@brainfault.org>
> Signed-off-by: Nick Hu <nick.hu@sifive.com>

LGTM.

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

Regards,
Anup

> ---
>  include/sbi/sbi_system.h |  7 +++++++
>  lib/sbi/sbi_hsm.c        |  5 ++++-
>  lib/sbi/sbi_system.c     | 17 +++++++++++++++++
>  3 files changed, 28 insertions(+), 1 deletion(-)
>
> diff --git a/include/sbi/sbi_system.h b/include/sbi/sbi_system.h
> index 0fdcc98cce5dac43583e68ffa8c98e79fd95dad4..f48a019a06b6957b5ab9cb4b9ef795a899a34ff9 100644
> --- a/include/sbi/sbi_system.h
> +++ b/include/sbi/sbi_system.h
> @@ -69,11 +69,18 @@ struct sbi_system_suspend_device {
>          *     return from system_suspend() may ignore this parameter.
>          */
>         int (*system_suspend)(u32 sleep_type, unsigned long mmode_resume_addr);
> +
> +       /**
> +        * Resume the system from system suspend
> +        */
> +       void (*system_resume)(void);
>  };
>
>  const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void);
>  void sbi_system_suspend_set_device(struct sbi_system_suspend_device *dev);
>  void sbi_system_suspend_test_enable(void);
> +void sbi_system_resume(void);
> +bool sbi_system_is_suspended(void);
>  bool sbi_system_suspend_supported(u32 sleep_type);
>  int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque);
>
> diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
> index 0d97b43e0cd8f7b4fc97407ef01007485e3f5a24..0a355f9c2372075aaf303cba2aa5683993c4c079 100644
> --- a/lib/sbi/sbi_hsm.c
> +++ b/lib/sbi/sbi_hsm.c
> @@ -455,7 +455,10 @@ void sbi_hsm_hart_resume_start(struct sbi_scratch *scratch)
>                                          SBI_HSM_STATE_RESUME_PENDING))
>                 sbi_hart_hang();
>
> -       hsm_device_hart_resume();
> +       if (sbi_system_is_suspended())
> +               sbi_system_resume();
> +       else
> +               hsm_device_hart_resume();
>  }
>
>  void __noreturn sbi_hsm_hart_resume_finish(struct sbi_scratch *scratch,
> diff --git a/lib/sbi/sbi_system.c b/lib/sbi/sbi_system.c
> index cd0f4ba42bbe67e606bc821870716f7342eaf0d2..5500b05d22882bd43d84a1b715529cd8a26bee3f 100644
> --- a/lib/sbi/sbi_system.c
> +++ b/lib/sbi/sbi_system.c
> @@ -87,6 +87,7 @@ void __noreturn sbi_system_reset(u32 reset_type, u32 reset_reason)
>  }
>
>  static const struct sbi_system_suspend_device *suspend_dev = NULL;
> +static bool system_suspended;
>
>  const struct sbi_system_suspend_device *sbi_system_suspend_get_device(void)
>  {
> @@ -137,6 +138,19 @@ bool sbi_system_suspend_supported(u32 sleep_type)
>                suspend_dev->system_suspend_check(sleep_type) == 0;
>  }
>
> +bool sbi_system_is_suspended(void)
> +{
> +       return system_suspended;
> +}
> +
> +void sbi_system_resume(void)
> +{
> +       if (suspend_dev && suspend_dev->system_resume)
> +               suspend_dev->system_resume();
> +
> +       system_suspended = false;
> +}
> +
>  int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
>  {
>         struct sbi_domain *dom = sbi_domain_thishart_ptr();
> @@ -189,11 +203,14 @@ int sbi_system_suspend(u32 sleep_type, ulong resume_addr, ulong opaque)
>         __sbi_hsm_suspend_non_ret_save(scratch);
>
>         /* Suspend */
> +       system_suspended = true;
>         ret = suspend_dev->system_suspend(sleep_type, scratch->warmboot_addr);
>         if (ret != SBI_OK) {
>                 if (!sbi_hsm_hart_change_state(scratch, SBI_HSM_STATE_SUSPENDED,
>                                                SBI_HSM_STATE_STARTED))
>                         sbi_hart_hang();
> +
> +               system_suspended = false;
>                 return ret;
>         }
>
>
> --
> 2.34.1
>

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

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v7 04/12] lib: utils/cache: Add fdt cmo helpers
  2025-10-20  6:34 ` [PATCH v7 04/12] lib: utils/cache: Add fdt cmo helpers Nick Hu
@ 2025-10-28  5:54   ` Anup Patel
  0 siblings, 0 replies; 18+ messages in thread
From: Anup Patel @ 2025-10-28  5:54 UTC (permalink / raw)
  To: Nick Hu; +Cc: opensbi, Samuel Holland

On Mon, Oct 20, 2025 at 11:56 AM Nick Hu <nick.hu@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@sifive.com>
> Reviewed-by: Samuel Holland <samuel.holland@sifive.com>
> Reviewed-by: Anup Patel <anup@brainfault.org>
> ---
>  include/sbi_utils/cache/fdt_cmo_helper.h |  40 +++++++++++
>  lib/utils/cache/fdt_cmo_helper.c         | 112 +++++++++++++++++++++++++++++++
>  lib/utils/cache/objects.mk               |   1 +
>  platform/generic/platform.c              |   3 +-
>  4 files changed, 155 insertions(+), 1 deletion(-)
>
> 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 0000000000000000000000000000000000000000..a6a28db9ede2722d8261d2e077eeb7710cff0893
> --- /dev/null
> +++ b/include/sbi_utils/cache/fdt_cmo_helper.h
> @@ -0,0 +1,40 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2025 SiFive Inc.
> + */
> +
> +#ifndef __FDT_CMO_HELPER_H__
> +#define __FDT_CMO_HELPER_H__
> +
> +#ifdef CONFIG_FDT_CACHE
> +/**
> + * 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);
> +
> +#else
> +
> +static inline int fdt_cmo_init(bool cold_boot) { return 0; }
> +
> +#endif /* CONFIG_FDT_CACHE */
> +#endif /* __FDT_CMO_HELPER_H__ */
> diff --git a/lib/utils/cache/fdt_cmo_helper.c b/lib/utils/cache/fdt_cmo_helper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..6d2e853dd735735092c57db2398f97a64de3ab5e
> --- /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;

The "next-level-cache" property might be absent in CPU DT nodes
so fdt_next_cache_get() must return SBI_ENOENT when it is
absent.

Also, over here we must handle "rc == SBI_ENOENT" as special
case as follows:

diff --git a/lib/utils/cache/fdt_cmo_helper.c b/lib/utils/cache/fdt_cmo_helper.c
index 6d2e853d..d87bab76 100644
--- a/lib/utils/cache/fdt_cmo_helper.c
+++ b/lib/utils/cache/fdt_cmo_helper.c
@@ -62,8 +62,10 @@ static int fdt_cmo_cold_init(const void *fdt)
                        continue;

                rc = fdt_next_cache_get(fdt, cpu_offset, &dev);
-               if (rc)
+               if (rc && rc != SBI_ENOENT)
                        return rc;
+               if (rc == SBI_ENOENT)
+                       dev = NULL;

                set_hart_flc(scratch, dev);
        }

I will take care of the above at the time of merging this series.

Regards,
Anup

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

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver
  2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
                   ` (11 preceding siblings ...)
  2025-10-20  6:34 ` [PATCH v7 12/12] lib: utils/suspend: Add SiFive SMC0 driver Nick Hu
@ 2025-10-28  6:02 ` Anup Patel
  12 siblings, 0 replies; 18+ messages in thread
From: Anup Patel @ 2025-10-28  6:02 UTC (permalink / raw)
  To: Nick Hu
  Cc: opensbi, Samuel Holland, Vincent Chen, Andy Chiu, Cyan Yang,
	Yong-Xuan Wang

On Mon, Oct 20, 2025 at 11:56 AM Nick Hu <nick.hu@sifive.com> wrote:
>
> 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 v7:
> - Update the change log of PATCH 9 and PATCH 12 because the TMC0 and SMC0 are moved to the
>   lib/utils/hsm and lib/utils/suspend.
> - Add new commit to Extend the sbi_ipi_raw_send() to use all available IPI device in
>   PATCH 8 and use it in PATCH 9
> - Add `system_resume` callback for system suspend
> - Since the SMC0 driver need the `aplic_reinit_all()`, update the
>   SMC0 Kconfig option to depend upon the APLIC Kconfig option
> - Link to v6: https://lore.kernel.org/r/20250905-cache-upstream-v6-0-6a6da629c961@sifive.com
>
> Changes in v6:
> - Rename the aplic_restore() to aplic_reinit_all()
> - Remove fdt_hsm_sifive_tmc0_cold_init() from TMC0 header file
> - Remove the sifive_dev_platform.c
> - Add a dummy inline flavor of fdt_cmo_init() for the case where CONFIG_FDT_CACHE is disabled
> - Link to v5: https://lore.kernel.org/r/20250902-cache-upstream-v5-0-af60a067f47a@sifive.com
>
> Changes in v5:
> - Put the SiFive TMC0 driver to the fdt_early_driver
> - Fix the format of the comments in SiFive TMC0 driver
>
> 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: sbi: Extends sbi_ipi_raw_send() to use all available IPI devices
>   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
>

Applied this series to the riscv/opensbi repo.

Thanks,
Anup

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

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2025-10-28  6:02 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-20  6:34 [PATCH v7 00/12] Add SiFive TMC0 and SMC0 driver Nick Hu
2025-10-20  6:34 ` [PATCH v7 01/12] lib: utils: Add cache flush library Nick Hu
2025-10-20  6:34 ` [PATCH v7 02/12] lib: utils: Add FDT cache library Nick Hu
2025-10-20  6:34 ` [PATCH v7 03/12] utils: cache: Add SiFive ccache controller Nick Hu
2025-10-20  6:34 ` [PATCH v7 04/12] lib: utils/cache: Add fdt cmo helpers Nick Hu
2025-10-28  5:54   ` Anup Patel
2025-10-20  6:34 ` [PATCH v7 05/12] lib: sbi: Add SiFive proprietary xsfcflushdlone Nick Hu
2025-10-20  6:34 ` [PATCH v7 06/12] lib: sbi: Add SiFive proprietary xsfcease Nick Hu
2025-10-20  6:34 ` [PATCH v7 07/12] lib: utils/irqchip: Add APLIC restore function Nick Hu
2025-10-20  6:34 ` [PATCH v7 08/12] lib: sbi: Extends sbi_ipi_raw_send() to use all available IPI devices Nick Hu
2025-10-28  4:59   ` Anup Patel
2025-10-20  6:34 ` [PATCH v7 09/12] lib: utils/hsm: Add SiFive TMC0 driver Nick Hu
2025-10-28  5:00   ` Anup Patel
2025-10-20  6:34 ` [PATCH v7 10/12] lib: utils/timer: Expose timer update function Nick Hu
2025-10-20  6:34 ` [PATCH v7 11/12] lib: sbi: Add system_resume callback for restoring the system Nick Hu
2025-10-28  5:01   ` Anup Patel
2025-10-20  6:34 ` [PATCH v7 12/12] lib: utils/suspend: Add SiFive SMC0 driver Nick Hu
2025-10-28  6:02 ` [PATCH v7 00/12] Add SiFive TMC0 and " Anup Patel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox