diff --git a/arch/riscv/include/asm/timex.h b/arch/riscv/include/asm/timex.h index a06697846e6952..d78075351bf4f9 100644 --- a/arch/riscv/include/asm/timex.h +++ b/arch/riscv/include/asm/timex.h @@ -17,17 +17,26 @@ typedef unsigned long cycles_t; #ifdef CONFIG_64BIT static inline cycles_t get_cycles(void) { + if (riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR)) + return csr_read(CSR_TIME); + return readq_relaxed(clint_time_val); } #else /* !CONFIG_64BIT */ static inline u32 get_cycles(void) { + if (riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR)) + return csr_read(CSR_TIME); + return readl_relaxed(((u32 *)clint_time_val)); } #define get_cycles get_cycles static inline u32 get_cycles_hi(void) { + if (riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR)) + return csr_read(CSR_TIMEH); + return readl_relaxed(((u32 *)clint_time_val) + 1); } #define get_cycles_hi get_cycles_hi @@ -40,7 +49,8 @@ static inline u32 get_cycles_hi(void) */ static inline unsigned long random_get_entropy(void) { - if (unlikely(clint_time_val == NULL)) + if (!riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR) && + (unlikely(clint_time_val == NULL))) return random_get_entropy_fallback(); return get_cycles(); } diff --git a/drivers/clocksource/timer-clint.c b/drivers/clocksource/timer-clint.c index 0bdd9d7ec54583..62fe28df73fbab 100644 --- a/drivers/clocksource/timer-clint.c +++ b/drivers/clocksource/timer-clint.c @@ -39,6 +39,7 @@ static u64 __iomem *clint_timer_cmp; static u64 __iomem *clint_timer_val; static unsigned long clint_timer_freq; static unsigned int clint_timer_irq; +static bool is_c900_clint; #ifdef CONFIG_RISCV_M_MODE u64 __iomem *clint_time_val; @@ -81,6 +82,12 @@ static u64 notrace clint_get_cycles64(void) { return clint_get_cycles(); } + +static u64 notrace csr_get_cycles64(void) +{ + return csr_read(CSR_TIME); +} + #else /* CONFIG_64BIT */ static u64 notrace clint_get_cycles64(void) { @@ -93,8 +100,26 @@ static u64 notrace clint_get_cycles64(void) return ((u64)hi << 32) | lo; } + +static u64 notrace csr_get_cycles64(void) +{ + u32 hi, lo; + + do { + hi = csr_read(CSR_TIMEH); + lo = csr_read(CSR_TIME); + } while (hi != csr_read(CSR_TIMEH)); + + return ((u64)hi << 32) | lo; +} + #endif /* CONFIG_64BIT */ +static u64 csr_rdtime(struct clocksource *cs) +{ + return csr_get_cycles64(); +} + static u64 clint_rdtime(struct clocksource *cs) { return clint_get_cycles64(); @@ -105,9 +130,20 @@ static struct clocksource clint_clocksource = { .rating = 300, .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .read = clint_rdtime, + .read = csr_rdtime, }; +static int csr_clock_next_event(unsigned long delta, + struct clock_event_device *ce) +{ + void __iomem *r = clint_timer_cmp + + cpuid_to_hartid_map(smp_processor_id()); + + csr_set(CSR_IE, IE_TIE); + writeq_relaxed(csr_get_cycles64() + delta, r); + return 0; +} + static int clint_clock_next_event(unsigned long delta, struct clock_event_device *ce) { @@ -119,17 +155,36 @@ static int clint_clock_next_event(unsigned long delta, return 0; } +static int c900_clint_clock_next_event(unsigned long delta, + struct clock_event_device *ce) +{ + void __iomem *r = clint_timer_cmp + + cpuid_to_hartid_map(smp_processor_id()); + u64 val = csr_get_cycles64() + delta; + + csr_set(CSR_IE, IE_TIE); + writel_relaxed(val, r); + writel_relaxed(val >> 32, r + 4); + return 0; +} + static DEFINE_PER_CPU(struct clock_event_device, clint_clock_event) = { .name = "clint_clockevent", .features = CLOCK_EVT_FEAT_ONESHOT, .rating = 100, - .set_next_event = clint_clock_next_event, + .set_next_event = csr_clock_next_event, }; static int clint_timer_starting_cpu(unsigned int cpu) { struct clock_event_device *ce = per_cpu_ptr(&clint_clock_event, cpu); + if (!riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR)) + ce->set_next_event = clint_clock_next_event; + + if (is_c900_clint) + ce->set_next_event = c900_clint_clock_next_event; + ce->cpumask = cpumask_of(cpu); clockevents_config_and_register(ce, clint_timer_freq, 100, ULONG_MAX); @@ -161,7 +216,7 @@ static irqreturn_t clint_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __init clint_timer_init_dt(struct device_node *np) +static int __init clint_timer_init(struct device_node *np) { int rc; u32 i, nr_irqs; @@ -227,13 +282,19 @@ static int __init clint_timer_init_dt(struct device_node *np) pr_info("%pOFP: timer running at %ld Hz\n", np, clint_timer_freq); + if (!riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR)) + clint_clocksource.read = clint_rdtime; + rc = clocksource_register_hz(&clint_clocksource, clint_timer_freq); if (rc) { pr_err("%pOFP: clocksource register failed [%d]\n", np, rc); goto fail_iounmap; } - sched_clock_register(clint_get_cycles64, 64, clint_timer_freq); + if (riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR)) + sched_clock_register(csr_get_cycles64, 64, clint_timer_freq); + else + sched_clock_register(clint_get_cycles64, 64, clint_timer_freq); rc = request_percpu_irq(clint_timer_irq, clint_timer_interrupt, "clint-timer", &clint_clock_event); @@ -273,5 +334,18 @@ static int __init clint_timer_init_dt(struct device_node *np) return rc; } +static int __init clint_timer_init_dt(struct device_node *np) +{ + is_c900_clint = false; + return clint_timer_init(np); +} + +static int __init c900_clint_timer_init_dt(struct device_node *np) +{ + is_c900_clint = true; + return clint_timer_init(np); +} + TIMER_OF_DECLARE(clint_timer, "riscv,clint0", clint_timer_init_dt); TIMER_OF_DECLARE(clint_timer1, "sifive,clint0", clint_timer_init_dt); +TIMER_OF_DECLARE(clint_timer2, "thead,c900-clint", c900_clint_timer_init_dt);