/** Possible feature flags of a platform */
enum sbi_platform_features {
- /** Platform has timer value */
- SBI_PLATFORM_HAS_TIMER_VALUE = (1 << 0),
/** Platform has HART hotplug support */
- SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 1),
+ SBI_PLATFORM_HAS_HART_HOTPLUG = (1 << 0),
/** Platform has fault delegation support */
- SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 2),
+ SBI_PLATFORM_HAS_MFAULTS_DELEGATION = (1 << 1),
/** Platform has custom secondary hart booting support */
- SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 3),
+ SBI_PLATFORM_HAS_HART_SECONDARY_BOOT = (1 << 2),
/** Last index of Platform features*/
SBI_PLATFORM_HAS_LAST_FEATURE = SBI_PLATFORM_HAS_HART_SECONDARY_BOOT,
/** Default feature set for a platform */
#define SBI_PLATFORM_DEFAULT_FEATURES \
- (SBI_PLATFORM_HAS_TIMER_VALUE | SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
+ (SBI_PLATFORM_HAS_MFAULTS_DELEGATION)
/** Platform functions */
struct sbi_platform_operations {
/** Get tlb flush limit value **/
u64 (*get_tlbr_flush_limit)(void);
- /** Get platform timer value */
- u64 (*timer_value)(void);
- /** Start platform timer event for current HART */
- void (*timer_event_start)(u64 next_event);
- /** Stop platform timer event for current HART */
- void (*timer_event_stop)(void);
/** Initialize platform timer for current HART */
int (*timer_init)(bool cold_boot);
/** Exit platform timer for current HART */
#define sbi_platform_ops(__p) \
((const struct sbi_platform_operations *)(__p)->platform_ops_addr)
-/** Check whether the platform supports timer value */
-#define sbi_platform_has_timer_value(__p) \
- ((__p)->features & SBI_PLATFORM_HAS_TIMER_VALUE)
/** Check whether the platform supports HART hotplug */
#define sbi_platform_has_hart_hotplug(__p) \
((__p)->features & SBI_PLATFORM_HAS_HART_HOTPLUG)
}
/**
- * Get platform timer value
- *
- * @param plat pointer to struct sbi_platform
- *
- * @return 64-bit timer value
- */
-static inline u64 sbi_platform_timer_value(const struct sbi_platform *plat)
-{
- if (plat && sbi_platform_ops(plat)->timer_value)
- return sbi_platform_ops(plat)->timer_value();
- return 0;
-}
-
-/**
- * Start platform timer event for current HART
- *
- * @param plat pointer to struct struct sbi_platform
- * @param next_event timer value when timer event will happen
- */
-static inline void
-sbi_platform_timer_event_start(const struct sbi_platform *plat, u64 next_event)
-{
- if (plat && sbi_platform_ops(plat)->timer_event_start)
- sbi_platform_ops(plat)->timer_event_start(next_event);
-}
-
-/**
- * Stop platform timer event for current HART
- *
- * @param plat pointer to struct sbi_platform
- */
-static inline void
-sbi_platform_timer_event_stop(const struct sbi_platform *plat)
-{
- if (plat && sbi_platform_ops(plat)->timer_event_stop)
- sbi_platform_ops(plat)->timer_event_stop();
-}
-
-/**
* Initialize the platform timer for current HART
*
* @param plat pointer to struct sbi_platform
#include <sbi/sbi_types.h>
+/** Timer hardware device */
+struct sbi_timer_device {
+ /** Name of the timer operations */
+ char name[32];
+
+ /** Get free-running timer value */
+ u64 (*timer_value)(void);
+
+ /** Start timer event for current HART */
+ void (*timer_event_start)(u64 next_event);
+
+ /** Stop timer event for current HART */
+ void (*timer_event_stop)(void);
+};
+
struct sbi_scratch;
/** Get timer value for current HART */
/** Process timer event for current HART */
void sbi_timer_process(void);
+/** Get current timer device */
+const struct sbi_timer_device *sbi_timer_get_device(void);
+
+/** Register timer device */
+void sbi_timer_set_device(const struct sbi_timer_device *dev);
+
/* Initialize timer */
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot);
int clint_cold_ipi_init(struct clint_data *clint);
-u64 clint_timer_value(void);
-
-void clint_timer_event_stop(void);
-
-void clint_timer_event_start(u64 next_event);
-
int clint_warm_timer_init(void);
int clint_cold_timer_init(struct clint_data *clint,
int (*cold_init)(void *fdt, int nodeoff, const struct fdt_match *match);
int (*warm_init)(void);
void (*exit)(void);
- u64 (*value)(void);
- void (*event_stop)(void);
- void (*event_start)(u64 next_event);
};
-u64 fdt_timer_value(void);
-
-void fdt_timer_event_stop(void);
-
-void fdt_timer_event_start(u64 next_event);
-
void fdt_timer_exit(void);
int fdt_timer_init(bool cold_boot);
return NULL;
switch (feature) {
- case SBI_PLATFORM_HAS_TIMER_VALUE:
- fstr = "timer";
- break;
case SBI_PLATFORM_HAS_HART_HOTPLUG:
fstr = "hotplug";
break;
#include <sbi/sbi_timer.h>
static unsigned long time_delta_off;
-static u64 (*get_time_val)(const struct sbi_platform *plat);
+static u64 (*get_time_val)(void);
+static const struct sbi_timer_device *timer_dev = NULL;
#if __riscv_xlen == 32
-static u64 get_ticks(const struct sbi_platform *plat)
+static u64 get_ticks(void)
{
u32 lo, hi, tmp;
__asm__ __volatile__("1:\n"
return ((u64)hi << 32) | lo;
}
#else
-static u64 get_ticks(const struct sbi_platform *plat)
+static u64 get_ticks(void)
{
unsigned long n;
}
#endif
+static u64 get_platform_ticks(void)
+{
+ return timer_dev->timer_value();
+}
+
u64 sbi_timer_value(void)
{
- return get_time_val(sbi_platform_thishart_ptr());
+ if (get_time_val)
+ return get_time_val();
+ return 0;
}
u64 sbi_timer_virt_value(void)
void sbi_timer_event_start(u64 next_event)
{
- sbi_platform_timer_event_start(sbi_platform_thishart_ptr(), next_event);
+ if (timer_dev && timer_dev->timer_event_start)
+ timer_dev->timer_event_start(next_event);
csr_clear(CSR_MIP, MIP_STIP);
csr_set(CSR_MIE, MIP_MTIP);
}
csr_set(CSR_MIP, MIP_STIP);
}
+const struct sbi_timer_device *sbi_timer_get_device(void)
+{
+ return timer_dev;
+}
+
+void sbi_timer_set_device(const struct sbi_timer_device *dev)
+{
+ if (!dev || timer_dev)
+ return;
+
+ timer_dev = dev;
+ if (!get_time_val && timer_dev->timer_value)
+ get_time_val = get_platform_ticks;
+}
+
int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot)
{
u64 *time_delta;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
- int ret;
if (cold_boot) {
time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta),
"TIME_DELTA");
if (!time_delta_off)
return SBI_ENOMEM;
+
+ if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
+ get_time_val = get_ticks;
} else {
if (!time_delta_off)
return SBI_ENOMEM;
time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off);
*time_delta = 0;
- ret = sbi_platform_timer_init(plat, cold_boot);
- if (ret)
- return ret;
-
- if (sbi_hart_has_feature(scratch, SBI_HART_HAS_TIME))
- get_time_val = get_ticks;
- else if (sbi_platform_has_timer_value(plat))
- get_time_val = sbi_platform_timer_value;
- else
- /* There is no method to provide timer value */
- return SBI_ENODEV;
-
- return 0;
+ return sbi_platform_timer_init(plat, cold_boot);
}
void sbi_timer_exit(struct sbi_scratch *scratch)
{
- sbi_platform_timer_event_stop(sbi_platform_ptr(scratch));
+ if (timer_dev && timer_dev->timer_event_stop)
+ timer_dev->timer_event_stop();
csr_clear(CSR_MIP, MIP_STIP);
csr_clear(CSR_MIE, MIP_MTIP);
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_hartmask.h>
+#include <sbi/sbi_timer.h>
#include <sbi_utils/sys/clint.h>
#define CLINT_IPI_OFF 0
writel_relaxed(value >> 32, (void *)(addr) + 0x04);
}
-u64 clint_timer_value(void)
+static u64 clint_timer_value(void)
{
struct clint_data *clint = clint_timer_hartid2data[current_hartid()];
return clint->time_rd(clint->time_val) + clint->time_delta;
}
-void clint_timer_event_stop(void)
+static void clint_timer_event_stop(void)
{
u32 target_hart = current_hartid();
struct clint_data *clint = clint_timer_hartid2data[target_hart];
&clint->time_cmp[target_hart - clint->first_hartid]);
}
-void clint_timer_event_start(u64 next_event)
+static void clint_timer_event_start(u64 next_event)
{
u32 target_hart = current_hartid();
struct clint_data *clint = clint_timer_hartid2data[target_hart];
&clint->time_cmp[target_hart - clint->first_hartid]);
}
+static struct sbi_timer_device clint_timer = {
+ .name = "clint",
+ .timer_value = clint_timer_value,
+ .timer_event_start = clint_timer_event_start,
+ .timer_event_stop = clint_timer_event_stop
+};
+
int clint_warm_timer_init(void)
{
u64 v1, v2, mv;
sbi_domain_memregion_init(clint->addr + CLINT_TIME_CMP_OFF,
CLINT_TIME_CMP_SIZE,
SBI_DOMAIN_MEMREGION_MMIO, ®);
- return sbi_domain_root_add_memregion(®);
+ rc = sbi_domain_root_add_memregion(®);
+ if (rc)
+ return rc;
+
+ sbi_timer_set_device(&clint_timer);
+
+ return 0;
}
&fdt_timer_clint
};
-static u64 dummy_value(void)
-{
- return 0;
-}
-
-static void dummy_event_stop(void)
-{
-}
-
-static void dummy_event_start(u64 next_event)
-{
-}
-
static struct fdt_timer dummy = {
.match_table = NULL,
.cold_init = NULL,
.warm_init = NULL,
.exit = NULL,
- .value = dummy_value,
- .event_stop = dummy_event_stop,
- .event_start = dummy_event_start
};
static struct fdt_timer *current_driver = &dummy;
-u64 fdt_timer_value(void)
-{
- return current_driver->value();
-}
-
-void fdt_timer_event_stop(void)
-{
- current_driver->event_stop();
-}
-
-void fdt_timer_event_start(u64 next_event)
-{
- current_driver->event_start(next_event);
-}
-
void fdt_timer_exit(void)
{
if (current_driver->exit)
.cold_init = timer_clint_cold_init,
.warm_init = clint_warm_timer_init,
.exit = NULL,
- .value = clint_timer_value,
- .event_stop = clint_timer_event_stop,
- .event_start = clint_timer_event_start,
};
.ipi_clear = plicsw_ipi_clear,
.timer_init = ae350_timer_init,
- .timer_value = plmt_timer_value,
- .timer_event_start = plmt_timer_event_start,
- .timer_event_stop = plmt_timer_event_stop,
.vendor_ext_provider = ae350_vendor_ext_provider
};
#include <sbi/riscv_asm.h>
#include <sbi/riscv_io.h>
+#include <sbi/sbi_timer.h>
static u32 plmt_time_hart_count;
static volatile void *plmt_time_base;
static volatile u64 *plmt_time_val;
static volatile u64 *plmt_time_cmp;
-u64 plmt_timer_value(void)
+static u64 plmt_timer_value(void)
{
#if __riscv_xlen == 64
return readq_relaxed(plmt_time_val);
#endif
}
-void plmt_timer_event_stop(void)
+static void plmt_timer_event_stop(void)
{
u32 target_hart = current_hartid();
#endif
}
-void plmt_timer_event_start(u64 next_event)
+static void plmt_timer_event_start(u64 next_event)
{
u32 target_hart = current_hartid();
}
+static struct sbi_timer_device plmt_timer = {
+ .name = "ae350_plmt",
+ .timer_value = plmt_timer_value,
+ .timer_event_start = plmt_timer_event_start,
+ .timer_event_stop = plmt_timer_event_stop
+};
+
int plmt_warm_timer_init(void)
{
u32 target_hart = current_hartid();
plmt_time_val = (u64 *)(plmt_time_base);
plmt_time_cmp = (u64 *)(plmt_time_base + 0x8);
+ sbi_timer_set_device(&plmt_timer);
+
return 0;
}
#ifndef _AE350_PLMT_H_
#define _AE350_PLMT_H_
-u64 plmt_timer_value(void);
-
-void plmt_timer_event_stop(void);
-
-void plmt_timer_event_start(u64 next_event);
-
int plmt_warm_timer_init(void);
int plmt_cold_timer_init(unsigned long base, u32 hart_count);
.ipi_send = clint_ipi_send,
.ipi_clear = clint_ipi_clear,
.timer_init = ariane_timer_init,
- .timer_value = clint_timer_value,
- .timer_event_start = clint_timer_event_start,
- .timer_event_stop = clint_timer_event_stop,
};
const struct sbi_platform platform = {
.ipi_send = clint_ipi_send,
.ipi_clear = clint_ipi_clear,
.timer_init = openpiton_timer_init,
- .timer_value = clint_timer_value,
- .timer_event_start = clint_timer_event_start,
- .timer_event_stop = clint_timer_event_stop,
};
const struct sbi_platform platform = {
.ipi_init = fdt_ipi_init,
.ipi_exit = fdt_ipi_exit,
.get_tlbr_flush_limit = generic_tlbr_flush_limit,
- .timer_value = fdt_timer_value,
- .timer_event_stop = fdt_timer_event_stop,
- .timer_event_start = fdt_timer_event_start,
.timer_init = fdt_timer_init,
.timer_exit = fdt_timer_exit,
.system_reset_check = generic_system_reset_check,
.system_reset = k210_system_reset,
.timer_init = k210_timer_init,
- .timer_value = clint_timer_value,
- .timer_event_stop = clint_timer_event_stop,
- .timer_event_start = clint_timer_event_start,
};
const struct sbi_platform platform = {
.opensbi_version = OPENSBI_VERSION,
.platform_version = SBI_PLATFORM_VERSION(0x0, 0x01),
.name = "Kendryte K210",
- .features = SBI_PLATFORM_HAS_TIMER_VALUE,
+ .features = 0,
.hart_count = K210_HART_COUNT,
.hart_stack_size = SBI_PLATFORM_DEFAULT_HART_STACK_SIZE,
.platform_ops_addr = (unsigned long)&platform_ops
.ipi_send = clint_ipi_send,
.ipi_clear = clint_ipi_clear,
.ipi_init = ux600_ipi_init,
- .timer_value = clint_timer_value,
- .timer_event_stop = clint_timer_event_stop,
- .timer_event_start = clint_timer_event_start,
.timer_init = ux600_timer_init,
.system_reset_check = ux600_system_reset_check,
.system_reset = ux600_system_reset
.ipi_clear = clint_ipi_clear,
.ipi_init = fu540_ipi_init,
.get_tlbr_flush_limit = fu540_get_tlbr_flush_limit,
- .timer_value = clint_timer_value,
- .timer_event_stop = clint_timer_event_stop,
- .timer_event_start = clint_timer_event_start,
.timer_init = fu540_timer_init,
};
}
/*
- * Get platform timer value.
- */
-static u64 platform_timer_value(void)
-{
- /* Example if the generic CLINT driver is used */
- return clint_timer_value();
-}
-
-/*
- * Start platform timer event for current HART.
- */
-static void platform_timer_event_start(u64 next_event)
-{
- /* Example if the generic CLINT driver is used */
- clint_timer_event_start(next_event);
-}
-
-/*
- * Stop platform timer event for current HART.
- */
-static void platform_timer_event_stop(void)
-{
- /* Example if the generic CLINT driver is used */
- clint_timer_event_stop();
-}
-
-/*
* Check reset type and reason supported by the platform.
*/
static int platform_system_reset_check(u32 type, u32 reason)
.ipi_send = platform_ipi_send,
.ipi_clear = platform_ipi_clear,
.ipi_init = platform_ipi_init,
- .timer_value = platform_timer_value,
- .timer_event_stop = platform_timer_event_stop,
- .timer_event_start = platform_timer_event_start,
.timer_init = platform_timer_init,
.system_reset_check = platform_system_reset_check,
.system_reset = platform_system_reset