[PATCH v2 4/4] lib/utils: Add memory-mapped stimecmp support

Xiang W wxjstz at 126.com
Tue May 27 22:53:53 PDT 2025


Some platforms has a memory-mapped stimecmp similar to sstc. This
patch get the address of stimecmp by adding it to the reg-names of
the 'thead,c900-aclint-mtimer' node in the device tree, and triggers
the timer interrupt through the memory-mapped stimecmp in
sbi_timer_event_start if it exists.

Tested on Milk-V melse.

Signed-off-by: Xiang W <wxjstz at 126.com>
---
 include/sbi_utils/fdt/fdt_helper.h      |  1 +
 include/sbi_utils/timer/aclint_mtimer.h |  2 ++
 lib/utils/fdt/fdt_helper.c              | 21 +++++++++++++++++++--
 lib/utils/ipi/fdt_ipi_mswi.c            |  2 +-
 lib/utils/timer/aclint_mtimer.c         |  7 ++++---
 lib/utils/timer/fdt_timer_mtimer.c      |  8 ++++++--
 6 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/include/sbi_utils/fdt/fdt_helper.h b/include/sbi_utils/fdt/fdt_helper.h
index 04c850cc..2f4ea255 100644
--- a/include/sbi_utils/fdt/fdt_helper.h
+++ b/include/sbi_utils/fdt/fdt_helper.h
@@ -98,6 +98,7 @@ int fdt_parse_aclint_node(const void *fdt, int nodeoffset,
 			  bool for_timer, bool allow_regname,
 			  unsigned long *out_addr1, unsigned long *out_size1,
 			  unsigned long *out_addr2, unsigned long *out_size2,
+			  unsigned long *out_addr3, unsigned long *out_size3,
 			  u32 *out_first_hartid, u32 *out_hart_count);
 
 int fdt_parse_plmt_node(const void *fdt, int nodeoffset, unsigned long *plmt_base,
diff --git a/include/sbi_utils/timer/aclint_mtimer.h b/include/sbi_utils/timer/aclint_mtimer.h
index a245e13e..d88ab9ce 100644
--- a/include/sbi_utils/timer/aclint_mtimer.h
+++ b/include/sbi_utils/timer/aclint_mtimer.h
@@ -31,6 +31,8 @@ struct aclint_mtimer_data {
 	unsigned long mtime_size;
 	unsigned long mtimecmp_addr;
 	unsigned long mtimecmp_size;
+	unsigned long stimecmp_addr;
+	unsigned long stimecmp_size;
 	u32 first_hartid;
 	u32 hart_count;
 	bool has_64bit_mmio;
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c
index b2d91fdf..bbfbbaea 100644
--- a/lib/utils/fdt/fdt_helper.c
+++ b/lib/utils/fdt/fdt_helper.c
@@ -909,7 +909,9 @@ static int fdt_get_aclint_addr_size_by_name(const void *fdt, int nodeoffset,
 					    unsigned long *out_addr1,
 					    unsigned long *out_size1,
 					    unsigned long *out_addr2,
-					    unsigned long *out_size2)
+					    unsigned long *out_size2,
+					    unsigned long *out_addr3,
+					    unsigned long *out_size3)
 {
 	int rc;
 	uint64_t reg_addr, reg_size;
@@ -921,6 +923,15 @@ static int fdt_get_aclint_addr_size_by_name(const void *fdt, int nodeoffset,
 	*out_addr1 = reg_addr;
 	*out_size1 = reg_size;
 
+	if (out_addr3 && out_size3) {
+		rc = fdt_get_node_addr_size_by_name(fdt, nodeoffset, "stimecmp",
+						    &reg_addr, &reg_size);
+		if (rc < 0 || !reg_size)
+			reg_addr = reg_size = 0;
+		*out_addr3 = reg_addr;
+		*out_size3 = reg_size;
+	}
+
 	rc = fdt_get_node_addr_size_by_name(fdt, nodeoffset, "mtimecmp",
 					    &reg_addr, &reg_size);
 	if (rc < 0 || !reg_size)
@@ -963,6 +974,7 @@ int fdt_parse_aclint_node(const void *fdt, int nodeoffset,
 			  bool for_timer, bool allow_regname,
 			  unsigned long *out_addr1, unsigned long *out_size1,
 			  unsigned long *out_addr2, unsigned long *out_size2,
+			  unsigned long *out_addr3, unsigned long *out_size3,
 			  u32 *out_first_hartid, u32 *out_hart_count)
 {
 	const fdt32_t *val;
@@ -975,11 +987,16 @@ int fdt_parse_aclint_node(const void *fdt, int nodeoffset,
 	    !out_first_hartid || !out_hart_count)
 		return SBI_EINVAL;
 
+	if (out_addr3)
+		*out_addr3 = 0;
+	if (out_size3)
+		*out_size3 = 0;
 	if (for_timer && allow_regname && out_addr2 && out_size2 &&
 	    fdt_getprop(fdt, nodeoffset, "reg-names", NULL))
 		rc = fdt_get_aclint_addr_size_by_name(fdt, nodeoffset,
 						      out_addr1, out_size1,
-						      out_addr2, out_size2);
+						      out_addr2, out_size2,
+						      out_addr3, out_size3);
 	else
 		rc = fdt_get_aclint_addr_size(fdt, nodeoffset,
 					      out_addr1, out_size1,
diff --git a/lib/utils/ipi/fdt_ipi_mswi.c b/lib/utils/ipi/fdt_ipi_mswi.c
index aa37d0d0..3a8da253 100644
--- a/lib/utils/ipi/fdt_ipi_mswi.c
+++ b/lib/utils/ipi/fdt_ipi_mswi.c
@@ -25,7 +25,7 @@ static int ipi_mswi_cold_init(const void *fdt, int nodeoff,
 		return SBI_ENOMEM;
 
 	rc = fdt_parse_aclint_node(fdt, nodeoff, false, false,
-				   &ms->addr, &ms->size, NULL, NULL,
+				   &ms->addr, &ms->size, NULL, NULL, NULL, NULL,
 				   &ms->first_hartid, &ms->hart_count);
 	if (rc) {
 		sbi_free(ms);
diff --git a/lib/utils/timer/aclint_mtimer.c b/lib/utils/timer/aclint_mtimer.c
index ad4c10b3..ed9be1c0 100644
--- a/lib/utils/timer/aclint_mtimer.c
+++ b/lib/utils/timer/aclint_mtimer.c
@@ -80,10 +80,11 @@ static void mtimer_event_start(u64 next_event)
 	if (!mt)
 		return;
 
-	/* Program MTIMER Time Compare */
-	time_cmp = (void *)mt->mtimecmp_addr;
+	/* Program Time Compare */
+	time_cmp = (void *)(mt->stimecmp_addr ? mt->stimecmp_addr
+					      : mt->mtimecmp_addr);
 	mt->time_wr(true, next_event,
-		    &time_cmp[target_hart - mt->first_hartid]);
+		&time_cmp[target_hart - mt->first_hartid]);
 }
 
 static void mtimer_event_stop(void)
diff --git a/lib/utils/timer/fdt_timer_mtimer.c b/lib/utils/timer/fdt_timer_mtimer.c
index 224534d8..7af77a70 100644
--- a/lib/utils/timer/fdt_timer_mtimer.c
+++ b/lib/utils/timer/fdt_timer_mtimer.c
@@ -34,7 +34,7 @@ static int timer_mtimer_cold_init(const void *fdt, int nodeoff,
 				  const struct fdt_match *match)
 {
 	int rc;
-	unsigned long addr[2], size[2];
+	unsigned long addr[3], size[3];
 	struct timer_mtimer_node *mtn, *n;
 	struct aclint_mtimer_data *mt;
 	const struct timer_mtimer_quirks *quirks = match->data;
@@ -46,7 +46,9 @@ static int timer_mtimer_cold_init(const void *fdt, int nodeoff,
 	mt = &mtn->data;
 
 	rc = fdt_parse_aclint_node(fdt, nodeoff, true, !is_clint,
-				   &addr[0], &size[0], &addr[1], &size[1],
+				   &addr[0], &size[0],
+				   &addr[1], &size[1],
+				   &addr[2], &size[2],
 				   &mt->first_hartid, &mt->hart_count);
 	if (rc) {
 		sbi_free(mtn);
@@ -81,6 +83,8 @@ static int timer_mtimer_cold_init(const void *fdt, int nodeoff,
 		mt->mtime_size = size[0];
 		mt->mtimecmp_addr = addr[1];
 		mt->mtimecmp_size = size[1];
+		mt->stimecmp_addr = addr[2];
+		mt->stimecmp_size = size[2];
 	}
 
 	/* Apply additional quirks */
-- 
2.47.2




More information about the opensbi mailing list