diff options
Diffstat (limited to 'bsps/riscv/griscv/clock/clockdrv.c')
-rw-r--r-- | bsps/riscv/griscv/clock/clockdrv.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/bsps/riscv/griscv/clock/clockdrv.c b/bsps/riscv/griscv/clock/clockdrv.c new file mode 100644 index 0000000000..47ed6b305d --- /dev/null +++ b/bsps/riscv/griscv/clock/clockdrv.c @@ -0,0 +1,202 @@ +/* + * Clock Tick Device Driver + * + * This routine initializes GRLIB gptimer 1 which used for the clock tick. + * + * The tick frequency is directly programmed to the configured number of + * microseconds per tick. + * + * COPYRIGHT (c) 1989-2006. + * On-Line Applications Research Corporation (OAR). + * + * Modified for GRLIB BSP. + * COPYRIGHT (c) 2004. + * Gaisler Research. + * + * Copyright (c) 2014, 2018 embedded brains GmbH + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <bsp.h> +#include <amba.h> +#include <bsp/irq.h> +#include <bspopts.h> +#include <bsp/fatal.h> +#include <rtems/rtems/intr.h> +#include <grlib/ambapp.h> +#include <rtems/score/profiling.h> +#include <rtems/timecounter.h> +#include <rtems/score/cpuimpl.h> +#include <rtems/score/riscv-utility.h> + +volatile uint32_t _RISCV_Counter_register; + +/* The GRLIB BSP Timer driver can rely on the Driver Manager if the + * DrvMgr is initialized during startup. Otherwise the classic driver + * must be used. + * + * The DrvMgr Clock driver is located in the shared/timer directory + */ +#ifndef RTEMS_DRVMGR_STARTUP + +/* GRLIB Timer system interrupt number */ +static int clkirq; + +static void (*grlib_tc_tick)(void); + +static struct timecounter grlib_tc; + +#ifdef RTEMS_PROFILING +#define IRQMP_TIMESTAMP_S1_S2 ((1U << 25) | (1U << 26)) + +static void grlib_tc_tick_irqmp_timestamp(void) +{ + volatile struct irqmp_timestamp_regs *irqmp_ts = + &GRLIB_IrqCtrl_Regs->timestamp[0]; + unsigned int first = irqmp_ts->assertion; + unsigned int second = irqmp_ts->counter; + + irqmp_ts->control |= IRQMP_TIMESTAMP_S1_S2; + + _Profiling_Update_max_interrupt_delay(_Per_CPU_Get(), second - first); + + rtems_timecounter_tick(); +} +#endif + +static void grlib_tc_tick_irqmp_timestamp_init(void) +{ +#ifdef RTEMS_PROFILING + /* + * Ignore the first clock interrupt, since it contains the sequential system + * initialization time. Do the timestamp initialization on the fly. + */ + +#ifdef RTEMS_SMP + static Atomic_Uint counter = ATOMIC_INITIALIZER_UINT(0); + + bool done = + _Atomic_Fetch_add_uint(&counter, 1, ATOMIC_ORDER_RELAXED) + == rtems_get_processor_count() - 1; +#else + bool done = true; +#endif + + volatile struct irqmp_timestamp_regs *irqmp_ts = + &GRLIB_IrqCtrl_Regs->timestamp[0]; + unsigned int ks = 1U << 5; + + irqmp_ts->control = ks | IRQMP_TIMESTAMP_S1_S2 | (unsigned int) clkirq; + + if (done) { + grlib_tc_tick = grlib_tc_tick_irqmp_timestamp; + } +#endif + + rtems_timecounter_tick(); +} + +static void grlib_tc_do_tick(void) +{ + (*grlib_tc_tick)(); +} + +#define Adjust_clkirq_for_node() do { clkirq += GRLIB_CLOCK_INDEX; } while(0) + +#define Clock_driver_support_find_timer() \ + do { \ + /* Assume timer found during BSP initialization */ \ + if (GRLIB_Timer_Regs) { \ + clkirq = (GRLIB_Timer_Regs->cfg & 0xf8) >> 3; \ + \ + Adjust_clkirq_for_node(); \ + } \ + } while (0) + +#define Clock_driver_support_install_isr( _new ) \ + bsp_clock_handler_install(_new) + +static void bsp_clock_handler_install(rtems_isr *new) +{ + rtems_status_code sc; + + sc = rtems_interrupt_handler_install( + clkirq, + "Clock", + RTEMS_INTERRUPT_UNIQUE, + new, + NULL + ); + if (sc != RTEMS_SUCCESSFUL) { + rtems_fatal(RTEMS_FATAL_SOURCE_BSP, LEON3_FATAL_CLOCK_INITIALIZATION); + } +} + +#define Clock_driver_support_set_interrupt_affinity(online_processors) \ + bsp_interrupt_set_affinity(clkirq, online_processors) + +uint32_t _CPU_Counter_frequency( void ) +{ + return grlib_up_counter_frequency(); +} + + +static uint32_t _RISCV_Get_timecount_csr(struct timecounter *tc) +{ + return read_csr(time); +} + +static void grlib_clock_initialize(void) +{ + volatile struct gptimer_regs *gpt; + struct timecounter *tc; + + gpt = GRLIB_Timer_Regs; + tc = &grlib_tc; + + gpt->timer[GRLIB_CLOCK_INDEX].reload = + rtems_configuration_get_microseconds_per_tick() - 1; + gpt->timer[GRLIB_CLOCK_INDEX].ctrl = + GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_RS | + GPTIMER_TIMER_CTRL_LD | GPTIMER_TIMER_CTRL_IE; + + /* Use the RISCV time register as up-counter */ + tc->tc_get_timecount = _RISCV_Get_timecount_csr; + tc->tc_frequency = grlib_up_counter_frequency(); + +#ifdef RTEMS_PROFILING + volatile struct irqmp_timestamp_regs *irqmp_ts = + &GRLIB_IrqCtrl_Regs->timestamp[0]; + + if (!grlib_irqmp_has_timestamp(irqmp_ts)) { + bsp_fatal(GRLIB_FATAL_CLOCK_NO_IRQMP_TIMESTAMP_SUPPORT); + } +#endif + + grlib_tc_tick = grlib_tc_tick_irqmp_timestamp_init; + + tc->tc_counter_mask = 0xffffffff; + tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(tc); +} + +CPU_Counter_ticks _CPU_Counter_read( void ) +{ + unsigned long timec; + + __asm__ volatile ( "csrr %0, time" : "=&r" ( timec ) ); + + return timec; +} + +#define Clock_driver_support_initialize_hardware() \ + grlib_clock_initialize() + +#define Clock_driver_timecounter_tick() grlib_tc_do_tick() + +#include "../../../shared/dev/clock/clockimpl.h" + +#endif |