193bcbb09SJames Raphael Tiovalen // SPDX-License-Identifier: GPL-2.0-only 293bcbb09SJames Raphael Tiovalen /* 393bcbb09SJames Raphael Tiovalen * Copyright (C) 2024, James Raphael Tiovalen <jamestiotio@gmail.com> 493bcbb09SJames Raphael Tiovalen */ 593bcbb09SJames Raphael Tiovalen #include <libcflat.h> 693bcbb09SJames Raphael Tiovalen #include <devicetree.h> 7*ff2fceb1SAndrew Jones #include <limits.h> 8*ff2fceb1SAndrew Jones #include <asm/csr.h> 9*ff2fceb1SAndrew Jones #include <asm/delay.h> 10*ff2fceb1SAndrew Jones #include <asm/isa.h> 11*ff2fceb1SAndrew Jones #include <asm/sbi.h> 1293bcbb09SJames Raphael Tiovalen #include <asm/setup.h> 13*ff2fceb1SAndrew Jones #include <asm/smp.h> 1493bcbb09SJames Raphael Tiovalen #include <asm/timer.h> 1593bcbb09SJames Raphael Tiovalen 1693bcbb09SJames Raphael Tiovalen void timer_get_frequency(void) 1793bcbb09SJames Raphael Tiovalen { 1893bcbb09SJames Raphael Tiovalen const struct fdt_property *prop; 1993bcbb09SJames Raphael Tiovalen u32 *data; 2093bcbb09SJames Raphael Tiovalen int cpus, len; 2193bcbb09SJames Raphael Tiovalen 2293bcbb09SJames Raphael Tiovalen assert_msg(dt_available(), "ACPI not yet supported"); 2393bcbb09SJames Raphael Tiovalen 2493bcbb09SJames Raphael Tiovalen const void *fdt = dt_fdt(); 2593bcbb09SJames Raphael Tiovalen 2693bcbb09SJames Raphael Tiovalen cpus = fdt_path_offset(fdt, "/cpus"); 2793bcbb09SJames Raphael Tiovalen assert(cpus >= 0); 2893bcbb09SJames Raphael Tiovalen 2993bcbb09SJames Raphael Tiovalen prop = fdt_get_property(fdt, cpus, "timebase-frequency", &len); 3093bcbb09SJames Raphael Tiovalen assert(prop != NULL && len == 4); 3193bcbb09SJames Raphael Tiovalen 3293bcbb09SJames Raphael Tiovalen data = (u32 *)prop->data; 3393bcbb09SJames Raphael Tiovalen timebase_frequency = fdt32_to_cpu(*data); 3493bcbb09SJames Raphael Tiovalen } 35*ff2fceb1SAndrew Jones 36*ff2fceb1SAndrew Jones void timer_start(unsigned long duration_us) 37*ff2fceb1SAndrew Jones { 38*ff2fceb1SAndrew Jones uint64_t next = timer_get_cycles() + usec_to_cycles((uint64_t)duration_us); 39*ff2fceb1SAndrew Jones 40*ff2fceb1SAndrew Jones if (cpu_has_extension(smp_processor_id(), ISA_SSTC)) { 41*ff2fceb1SAndrew Jones csr_write(CSR_STIMECMP, (unsigned long)next); 42*ff2fceb1SAndrew Jones if (__riscv_xlen == 32) 43*ff2fceb1SAndrew Jones csr_write(CSR_STIMECMPH, (unsigned long)(next >> 32)); 44*ff2fceb1SAndrew Jones } else if (sbi_probe(SBI_EXT_TIME)) { 45*ff2fceb1SAndrew Jones struct sbiret ret = sbi_set_timer(next); 46*ff2fceb1SAndrew Jones assert(ret.error == SBI_SUCCESS); 47*ff2fceb1SAndrew Jones assert(!(next >> 32)); 48*ff2fceb1SAndrew Jones } else { 49*ff2fceb1SAndrew Jones assert_msg(false, "No timer to start!"); 50*ff2fceb1SAndrew Jones } 51*ff2fceb1SAndrew Jones } 52*ff2fceb1SAndrew Jones 53*ff2fceb1SAndrew Jones void timer_stop(void) 54*ff2fceb1SAndrew Jones { 55*ff2fceb1SAndrew Jones if (cpu_has_extension(smp_processor_id(), ISA_SSTC)) { 56*ff2fceb1SAndrew Jones csr_write(CSR_STIMECMP, ULONG_MAX); 57*ff2fceb1SAndrew Jones if (__riscv_xlen == 32) 58*ff2fceb1SAndrew Jones csr_write(CSR_STIMECMPH, ULONG_MAX); 59*ff2fceb1SAndrew Jones } else if (sbi_probe(SBI_EXT_TIME)) { 60*ff2fceb1SAndrew Jones struct sbiret ret = sbi_set_timer(ULONG_MAX); 61*ff2fceb1SAndrew Jones assert(ret.error == SBI_SUCCESS); 62*ff2fceb1SAndrew Jones } else { 63*ff2fceb1SAndrew Jones assert_msg(false, "No timer to stop!"); 64*ff2fceb1SAndrew Jones } 65*ff2fceb1SAndrew Jones } 66