summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sbi/riscv_encoding.h4
-rw-r--r--include/sbi/sbi_hart.h4
-rw-r--r--lib/sbi/sbi_hart.c28
-rw-r--r--lib/sbi/sbi_timer.c25
4 files changed, 57 insertions, 4 deletions
diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h
index a9772a67..7cfbaced 100644
--- a/include/sbi/riscv_encoding.h
+++ b/include/sbi/riscv_encoding.h
@@ -324,6 +324,10 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
+/* Sstc extension */
+#define CSR_STIMECMP 0x14D
+#define CSR_STIMECMPH 0x15D
+
/* Supervisor Protection and Translation */
#define CSR_SATP 0x180
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h
index be3ad9fa..1d093742 100644
--- a/include/sbi/sbi_hart.h
+++ b/include/sbi/sbi_hart.h
@@ -30,9 +30,11 @@ enum sbi_hart_features {
SBI_HART_HAS_MENVCFG = (1 << 6),
/** HART has mstateen CSR **/
SBI_HART_HAS_SMSTATEEN = (1 << 7),
+ /** HART has SSTC extension implemented in hardware */
+ SBI_HART_HAS_SSTC = (1 << 8),
/** Last index of Hart features*/
- SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_SMSTATEEN,
+ SBI_HART_HAS_LAST_FEATURE = SBI_HART_HAS_SSTC,
};
struct sbi_scratch;
diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c
index 891fa183..a50b6e4b 100644
--- a/lib/sbi/sbi_hart.c
+++ b/lib/sbi/sbi_hart.c
@@ -147,6 +147,22 @@ static void mstatus_init(struct sbi_scratch *scratch)
menvcfg_val |= ENVCFG_PBMTE;
#endif
+ /*
+ * The spec doesn't explicitly describe the reset value of menvcfg.
+ * Enable access to stimecmp if sstc extension is present in the
+ * hardware.
+ */
+ if (sbi_hart_has_feature(scratch, SBI_HART_HAS_SSTC)) {
+#if __riscv_xlen == 32
+ unsigned long menvcfgh_val;
+ menvcfgh_val = csr_read(CSR_MENVCFGH);
+ menvcfgh_val |= ENVCFGH_STCE;
+ csr_write(CSR_MENVCFGH, menvcfgh_val);
+#else
+ menvcfg_val |= ENVCFG_STCE;
+#endif
+ }
+
csr_write(CSR_MENVCFG, menvcfg_val);
}
@@ -367,6 +383,8 @@ static inline char *sbi_hart_feature_id2string(unsigned long feature)
break;
case SBI_HART_HAS_AIA:
fstr = "aia";
+ case SBI_HART_HAS_SSTC:
+ fstr = "sstc";
break;
case SBI_HART_HAS_MENVCFG:
fstr = "menvcfg";
@@ -610,6 +628,16 @@ __aia_skip:
if (!trap.cause)
hfeatures->features |= SBI_HART_HAS_MENVCFG;
+ /**
+ * Detect if hart supports stimecmp CSR(Sstc extension) and menvcfg is
+ * implemented.
+ */
+ if (hfeatures->features & SBI_HART_HAS_MENVCFG) {
+ csr_read_allowed(CSR_STIMECMP, (unsigned long)&trap);
+ if (!trap.cause)
+ hfeatures->features |= SBI_HART_HAS_SSTC;
+ }
+
/* Detect if hart supports mstateen CSRs */
val = csr_read_allowed(CSR_MSTATEEN0, (unsigned long)&trap);
if (!trap.cause)
diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c
index acdba922..bf0f375a 100644
--- a/lib/sbi/sbi_timer.c
+++ b/lib/sbi/sbi_timer.c
@@ -124,16 +124,35 @@ void sbi_timer_set_delta_upper(ulong delta_upper)
void sbi_timer_event_start(u64 next_event)
{
sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SET_TIMER);
- if (timer_dev && timer_dev->timer_event_start)
+
+ /**
+ * Update the stimecmp directly if available. This allows
+ * the older software to leverage sstc extension on newer hardware.
+ */
+ if (sbi_hart_has_feature(sbi_scratch_thishart_ptr(), SBI_HART_HAS_SSTC)) {
+#if __riscv_xlen == 32
+ csr_write(CSR_STIMECMP, next_event & 0xFFFFFFFF);
+ csr_write(CSR_STIMECMPH, next_event >> 32);
+#else
+ csr_write(CSR_STIMECMP, next_event);
+#endif
+ } else if (timer_dev && timer_dev->timer_event_start) {
timer_dev->timer_event_start(next_event);
- csr_clear(CSR_MIP, MIP_STIP);
+ csr_clear(CSR_MIP, MIP_STIP);
+ }
csr_set(CSR_MIE, MIP_MTIP);
}
void sbi_timer_process(void)
{
csr_clear(CSR_MIE, MIP_MTIP);
- csr_set(CSR_MIP, MIP_STIP);
+ /*
+ * If sstc extension is available, supervisor can receive the timer
+ * directly without M-mode come in between. This function should
+ * only invoked if M-mode programs the timer for its own purpose.
+ */
+ if (!sbi_hart_has_feature(sbi_scratch_thishart_ptr(), SBI_HART_HAS_SSTC))
+ csr_set(CSR_MIP, MIP_STIP);
}
const struct sbi_timer_device *sbi_timer_get_device(void)