[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",
+ ®_addr, ®_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",
®_addr, ®_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