#include <sbi/sbi_types.h>
+struct clint_data {
+ /* Public details */
+ unsigned long addr;
+ u32 first_hartid;
+ u32 hart_count;
+ bool has_64bit_mmio;
+ /* Private details (initialized and used by CLINT library)*/
+ u32 *ipi;
+ struct clint_data *time_delta_reference;
+ unsigned long time_delta_computed;
+ u64 time_delta;
+ u64 *time_val;
+ u64 *time_cmp;
+ u64 (*time_rd)(volatile u64 *addr);
+ void (*time_wr)(u64 value, volatile u64 *addr);
+};
+
void clint_ipi_send(u32 target_hart);
void clint_ipi_clear(u32 target_hart);
int clint_warm_ipi_init(void);
-int clint_cold_ipi_init(unsigned long base, u32 hart_count);
+int clint_cold_ipi_init(struct clint_data *clint);
u64 clint_timer_value(void);
int clint_warm_timer_init(void);
-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);
#endif
#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)
{
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[] = {
#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)
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;
}
#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)
{
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[] = {
#define ARIANE_PLIC_ADDR 0xc000000
#define ARIANE_PLIC_NUM_SOURCES 3
#define ARIANE_HART_COUNT 1
-#define ARIANE_CLINT_ADDR 0x2000000
+#define ARIANE_CLINT_ADDR 0x2000000
static struct plic_data plic = {
.addr = ARIANE_PLIC_ADDR,
.num_src = ARIANE_PLIC_NUM_SOURCES,
};
+static struct clint_data clint = {
+ .addr = ARIANE_CLINT_ADDR,
+ .first_hartid = 0,
+ .hart_count = ARIANE_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
+
/*
* Ariane platform early initialization.
*/
int ret;
if (cold_boot) {
- ret = clint_cold_ipi_init(ARIANE_CLINT_ADDR,
- ARIANE_HART_COUNT);
+ ret = clint_cold_ipi_init(&clint);
if (ret)
return ret;
}
int ret;
if (cold_boot) {
- ret = clint_cold_timer_init(ARIANE_CLINT_ADDR,
- ARIANE_HART_COUNT, TRUE);
+ ret = clint_cold_timer_init(&clint, NULL);
if (ret)
return ret;
}
.addr = OPENPITON_DEFAULT_PLIC_ADDR,
.num_src = OPENPITON_DEFAULT_PLIC_NUM_SOURCES,
};
-static unsigned long clint_addr = OPENPITON_DEFAULT_CLINT_ADDR;
+
+static struct clint_data clint = {
+ .addr = OPENPITON_DEFAULT_CLINT_ADDR,
+ .first_hartid = 0,
+ .hart_count = OPENPITON_DEFAULT_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
/*
* OpenPiton platform early initialization.
void *fdt;
struct platform_uart_data uart_data;
struct plic_data plic_data;
- unsigned long clint_data;
+ unsigned long clint_addr;
int rc;
if (!cold_boot)
if (!rc)
plic = plic_data;
- rc = fdt_parse_compat_addr(fdt, &clint_data, "riscv,clint0");
+ rc = fdt_parse_compat_addr(fdt, &clint_addr, "riscv,clint0");
if (!rc)
- clint_addr = clint_data;
+ clint.addr = clint_addr;
return 0;
}
int ret;
if (cold_boot) {
- ret = clint_cold_ipi_init(clint_addr,
- OPENPITON_DEFAULT_HART_COUNT);
+ ret = clint_cold_ipi_init(&clint);
if (ret)
return ret;
}
int ret;
if (cold_boot) {
- ret = clint_cold_timer_init(clint_addr,
- OPENPITON_DEFAULT_HART_COUNT, TRUE);
+ ret = clint_cold_timer_init(&clint, NULL);
if (ret)
return ret;
}
.num_src = K210_PLIC_NUM_SOURCES,
};
+static struct clint_data clint = {
+ .addr = K210_CLINT_BASE_ADDR,
+ .first_hartid = 0,
+ .hart_count = K210_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
+
static u32 k210_get_clk_freq(void)
{
u32 clksel0, pll0;
int rc;
if (cold_boot) {
- rc = clint_cold_ipi_init(K210_CLINT_BASE_ADDR,
- K210_HART_COUNT);
+ rc = clint_cold_ipi_init(&clint);
if (rc)
return rc;
}
int rc;
if (cold_boot) {
- rc = clint_cold_timer_init(K210_CLINT_BASE_ADDR,
- K210_HART_COUNT, TRUE);
+ rc = clint_cold_timer_init(&clint, NULL);
if (rc)
return rc;
}
.num_src = UX600_PLIC_NUM_SOURCES,
};
+static struct clint_data clint = {
+ .addr = UX600_CLINT_TIMER_ADDR,
+ .first_hartid = 0,
+ .hart_count = UX600_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
+
static void ux600_modify_dt(void *fdt)
{
fdt_fixups(fdt);
int rc;
if (cold_boot) {
- rc = clint_cold_ipi_init(UX600_CLINT_TIMER_ADDR, UX600_HART_COUNT);
+ rc = clint_cold_ipi_init(&clint);
if (rc)
return rc;
}
int rc;
if (cold_boot) {
- rc = clint_cold_timer_init(UX600_CLINT_TIMER_ADDR,
- UX600_HART_COUNT, TRUE);
+ rc = clint_cold_timer_init(&clint, NULL);
if (rc)
return rc;
}
.num_src = FU540_PLIC_NUM_SOURCES,
};
+static struct clint_data clint = {
+ .addr = FU540_CLINT_ADDR,
+ .first_hartid = 0,
+ .hart_count = FU540_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
+
static void fu540_modify_dt(void *fdt)
{
fdt_cpu_fixup(fdt);
int rc;
if (cold_boot) {
- rc = clint_cold_ipi_init(FU540_CLINT_ADDR, FU540_HART_COUNT);
+ rc = clint_cold_ipi_init(&clint);
if (rc)
return rc;
}
int rc;
if (cold_boot) {
- rc = clint_cold_timer_init(FU540_CLINT_ADDR,
- FU540_HART_COUNT, TRUE);
+ rc = clint_cold_timer_init(&clint, NULL);
if (rc)
return rc;
}
#include <sbi_utils/serial/uart8250.h>
#include <sbi_utils/sys/clint.h>
-#define PLATFORM_PLIC_ADDR 0xc000000
-#define PLATFORM_PLIC_NUM_SOURCES 128
-#define PLATFORM_HART_COUNT 4
-#define PLATFORM_CLINT_ADDR 0x2000000
+#define PLATFORM_PLIC_ADDR 0xc000000
+#define PLATFORM_PLIC_NUM_SOURCES 128
+#define PLATFORM_HART_COUNT 4
+#define PLATFORM_CLINT_ADDR 0x2000000
#define PLATFORM_UART_ADDR 0x09000000
#define PLATFORM_UART_INPUT_FREQ 10000000
#define PLATFORM_UART_BAUDRATE 115200
.num_src = PLATFORM_PLIC_NUM_SOURCES,
};
+static struct clint_data clint = {
+ .addr = PLATFORM_CLINT_ADDR,
+ .first_hartid = 0,
+ .hart_count = PLATFORM_HART_COUNT,
+ .has_64bit_mmio = TRUE,
+};
+
/*
* Platform early initialization.
*/
/* Example if the generic CLINT driver is used */
if (cold_boot) {
- ret = clint_cold_ipi_init(PLATFORM_CLINT_ADDR,
- PLATFORM_HART_COUNT);
+ ret = clint_cold_ipi_init(&clint, NULL);
if (ret)
return ret;
}
/* Example if the generic CLINT driver is used */
if (cold_boot) {
- ret = clint_cold_timer_init(PLATFORM_CLINT_ADDR,
- PLATFORM_HART_COUNT, TRUE);
+ ret = clint_cold_timer_init(&clint);
if (ret)
return ret;
}
static struct c910_regs_struct c910_regs;
+static struct clint_data clint = {
+ .addr = 0, /* Updated at cold boot time */
+ .first_hartid = 0,
+ .hart_count = C910_HART_COUNT,
+ .has_64bit_mmio = FALSE,
+};
+
static int c910_early_init(bool cold_boot)
{
if (cold_boot) {
int rc;
if (cold_boot) {
- rc = clint_cold_ipi_init(c910_regs.clint_base_addr, C910_HART_COUNT);
+ clint.addr = c910_regs.clint_base_addr;
+ rc = clint_cold_ipi_init(&clint);
if (rc)
return rc;
}
int ret;
if (cold_boot) {
- ret = clint_cold_timer_init(c910_regs.clint_base_addr,
- C910_HART_COUNT, FALSE);
+ clint.addr = c910_regs.clint_base_addr;
+ ret = clint_cold_timer_init(&clint, NULL);
if (ret)
return ret;
}