summaryrefslogtreecommitdiff
path: root/lib/utils
diff options
context:
space:
mode:
Diffstat (limited to 'lib/utils')
-rw-r--r--lib/utils/ipi/fdt_ipi_clint.c10
-rw-r--r--lib/utils/sys/clint.c142
-rw-r--r--lib/utils/timer/fdt_timer_clint.c9
3 files changed, 110 insertions, 51 deletions
diff --git a/lib/utils/ipi/fdt_ipi_clint.c b/lib/utils/ipi/fdt_ipi_clint.c
index 05b66c6..c4ac0df 100644
--- a/lib/utils/ipi/fdt_ipi_clint.c
+++ b/lib/utils/ipi/fdt_ipi_clint.c
@@ -11,6 +11,8 @@
#include <sbi_utils/ipi/fdt_ipi.h>
#include <sbi_utils/sys/clint.h>
+static struct clint_data clint_ipi;
+
static int ipi_clint_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
@@ -26,7 +28,13 @@ static int ipi_clint_cold_init(void *fdt, int nodeoff,
if (rc)
return rc;
- return clint_cold_ipi_init(addr, max_hartid + 1);
+ /* TODO: We should figure-out CLINT has_64bit_mmio from DT node */
+ clint_ipi.addr = addr;
+ clint_ipi.first_hartid = 0;
+ clint_ipi.hart_count = max_hartid + 1;
+ clint_ipi.has_64bit_mmio = TRUE;
+
+ return clint_cold_ipi_init(&clint_ipi);
}
static const struct fdt_match ipi_clint_match[] = {
diff --git a/lib/utils/sys/clint.c b/lib/utils/sys/clint.c
index 22ba088..7a392aa 100644
--- a/lib/utils/sys/clint.c
+++ b/lib/utils/sys/clint.c
@@ -10,57 +10,70 @@
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_io.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hartmask.h>
#include <sbi_utils/sys/clint.h>
-static u32 clint_ipi_hart_count;
-static volatile void *clint_ipi_base;
-static volatile u32 *clint_ipi;
+#define CLINT_IPI_OFF 0
+#define CLINT_TIME_CMP_OFF 0x4000
+#define CLINT_TIME_VAL_OFF 0xbff8
+
+static struct clint_data *clint_ipi_hartid2data[SBI_HARTMASK_MAX_BITS];
void clint_ipi_send(u32 target_hart)
{
- if (clint_ipi_hart_count <= target_hart)
+ struct clint_data *clint;
+
+ if (SBI_HARTMASK_MAX_BITS <= target_hart)
+ return;
+ clint = clint_ipi_hartid2data[target_hart];
+ if (!clint)
return;
/* Set CLINT IPI */
- writel(1, &clint_ipi[target_hart]);
+ writel(1, &clint->ipi[target_hart - clint->first_hartid]);
}
void clint_ipi_clear(u32 target_hart)
{
- if (clint_ipi_hart_count <= target_hart)
+ struct clint_data *clint;
+
+ if (SBI_HARTMASK_MAX_BITS <= target_hart)
+ return;
+ clint = clint_ipi_hartid2data[target_hart];
+ if (!clint)
return;
/* Clear CLINT IPI */
- writel(0, &clint_ipi[target_hart]);
+ writel(0, &clint->ipi[target_hart - clint->first_hartid]);
}
int clint_warm_ipi_init(void)
{
- u32 hartid = current_hartid();
-
- if (!clint_ipi_base)
- return -1;
-
- /* Clear CLINT IPI */
- clint_ipi_clear(hartid);
+ /* Clear CLINT IPI for current HART */
+ clint_ipi_clear(current_hartid());
return 0;
}
-int clint_cold_ipi_init(unsigned long base, u32 hart_count)
+int clint_cold_ipi_init(struct clint_data *clint)
{
- /* Figure-out CLINT IPI register address */
- clint_ipi_hart_count = hart_count;
- clint_ipi_base = (void *)base;
- clint_ipi = (u32 *)clint_ipi_base;
+ u32 i;
+
+ if (!clint)
+ return SBI_EINVAL;
+
+ /* Initialize private data */
+ clint->ipi = (void *)clint->addr;
+
+ /* Update IPI hartid table */
+ for (i = 0; i < clint->hart_count; i++)
+ clint_ipi_hartid2data[clint->first_hartid + i] = clint;
return 0;
}
-static u32 clint_time_hart_count;
-static volatile void *clint_time_base;
-static volatile u64 *clint_time_val;
-static volatile u64 *clint_time_cmp;
+static struct clint_data *clint_timer_hartid2data[SBI_HARTMASK_MAX_BITS];
#if __riscv_xlen != 32
static u64 clint_time_rd64(volatile u64 *addr)
@@ -94,66 +107,97 @@ static void clint_time_wr32(u64 value, volatile u64 *addr)
writel_relaxed(value >> 32, (void *)(addr) + 0x04);
}
-static u64 (*clint_time_rd)(volatile u64 *addr) = clint_time_rd32;
-static void (*clint_time_wr)(u64 value, volatile u64 *addr) = clint_time_wr32;
-
u64 clint_timer_value(void)
{
+ struct clint_data *clint = clint_timer_hartid2data[current_hartid()];
+
/* Read CLINT Time Value */
- return clint_time_rd(clint_time_val);
+ return clint->time_rd(clint->time_val) + clint->time_delta;
}
void clint_timer_event_stop(void)
{
u32 target_hart = current_hartid();
-
- if (clint_time_hart_count <= target_hart)
- return;
+ struct clint_data *clint = clint_timer_hartid2data[target_hart];
/* Clear CLINT Time Compare */
- clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
+ clint->time_wr(-1ULL,
+ &clint->time_cmp[target_hart - clint->first_hartid]);
}
void clint_timer_event_start(u64 next_event)
{
u32 target_hart = current_hartid();
-
- if (clint_time_hart_count <= target_hart)
- return;
+ struct clint_data *clint = clint_timer_hartid2data[target_hart];
/* Program CLINT Time Compare */
- clint_time_wr(next_event, &clint_time_cmp[target_hart]);
+ clint->time_wr(next_event - clint->time_delta,
+ &clint->time_cmp[target_hart - clint->first_hartid]);
}
int clint_warm_timer_init(void)
{
+ u64 v1, v2, mv;
u32 target_hart = current_hartid();
-
- if (clint_time_hart_count <= target_hart || !clint_time_base)
- return -1;
+ struct clint_data *reference;
+ struct clint_data *clint = clint_timer_hartid2data[target_hart];
+
+ if (!clint)
+ return SBI_ENODEV;
+
+ /*
+ * Compute delta if reference available
+ *
+ * We deliberately compute time_delta in warm init so that time_delta
+ * is computed on a HART which is going to use given CLINT. We use
+ * atomic flag timer_delta_computed to ensure that only one HART does
+ * time_delta computation.
+ */
+ if (clint->time_delta_reference) {
+ reference = clint->time_delta_reference;
+ if (!atomic_raw_xchg_ulong(&clint->time_delta_computed, 1)) {
+ v1 = clint->time_rd(clint->time_val);
+ mv = reference->time_rd(reference->time_val);
+ v2 = clint->time_rd(clint->time_val);
+ clint->time_delta = mv - ((v1 / 2) + (v2 / 2));
+ }
+ }
/* Clear CLINT Time Compare */
- clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
+ clint->time_wr(-1ULL,
+ &clint->time_cmp[target_hart - clint->first_hartid]);
return 0;
}
-int clint_cold_timer_init(unsigned long base, u32 hart_count,
- bool has_64bit_mmio)
+int clint_cold_timer_init(struct clint_data *clint,
+ struct clint_data *reference)
{
- /* Figure-out CLINT Time register address */
- clint_time_hart_count = hart_count;
- clint_time_base = (void *)base;
- clint_time_val = (u64 *)(clint_time_base + 0xbff8);
- clint_time_cmp = (u64 *)(clint_time_base + 0x4000);
+ u32 i;
+
+ if (!clint)
+ return SBI_EINVAL;
+
+ /* Initialize private data */
+ clint->time_delta_reference = reference;
+ clint->time_delta_computed = 0;
+ clint->time_delta = 0;
+ clint->time_val = (u64 *)((void *)clint->addr + CLINT_TIME_VAL_OFF);
+ clint->time_cmp = (u64 *)((void *)clint->addr + CLINT_TIME_CMP_OFF);
+ clint->time_rd = clint_time_rd32;
+ clint->time_wr = clint_time_wr32;
/* Override read/write accessors for 64bit MMIO */
#if __riscv_xlen != 32
- if (has_64bit_mmio) {
- clint_time_rd = clint_time_rd64;
- clint_time_wr = clint_time_wr64;
+ if (clint->has_64bit_mmio) {
+ clint->time_rd = clint_time_rd64;
+ clint->time_wr = clint_time_wr64;
}
#endif
+ /* Update timer hartid table */
+ for (i = 0; i < clint->hart_count; i++)
+ clint_timer_hartid2data[clint->first_hartid + i] = clint;
+
return 0;
}
diff --git a/lib/utils/timer/fdt_timer_clint.c b/lib/utils/timer/fdt_timer_clint.c
index 6aa6929..2f5f283 100644
--- a/lib/utils/timer/fdt_timer_clint.c
+++ b/lib/utils/timer/fdt_timer_clint.c
@@ -11,6 +11,8 @@
#include <sbi_utils/timer/fdt_timer.h>
#include <sbi_utils/sys/clint.h>
+static struct clint_data clint_timer;
+
static int timer_clint_cold_init(void *fdt, int nodeoff,
const struct fdt_match *match)
{
@@ -27,7 +29,12 @@ static int timer_clint_cold_init(void *fdt, int nodeoff,
return rc;
/* TODO: We should figure-out CLINT has_64bit_mmio from DT node */
- return clint_cold_timer_init(addr, max_hartid + 1, TRUE);
+ clint_timer.addr = addr;
+ clint_timer.first_hartid = 0;
+ clint_timer.hart_count = max_hartid + 1;
+ clint_timer.has_64bit_mmio = TRUE;
+
+ return clint_cold_timer_init(&clint_timer, NULL);
}
static const struct fdt_match timer_clint_match[] = {