Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:00

0001 /*
0002  * SPDX-License-Identifier: BSD-2-Clause
0003  *
0004  * Copyright (C) 2024 Kevin Kirspel
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #include <stdlib.h>
0029 #include <bsp/fatal.h>
0030 #include <bsp/irq.h>
0031 #include <bsp/niosv.h>
0032 
0033 #include <rtems/sysinit.h>
0034 #include <rtems/counter.h>
0035 #include <rtems/timecounter.h>
0036 #include <rtems/btimer.h>
0037 #include <rtems/score/riscv-utility.h>
0038 
0039 #define BENCHMARK_TIMER_INTERVAL_FREQ 1000000
0040 
0041 /* This is defined in dev/clock/clockimpl.h */
0042 void Clock_isr(void *arg);
0043 
0044 static volatile uint64_t interval_period;
0045 static volatile uint64_t last_mtimecmp;
0046 static volatile uint64_t benchmark_timer_base;
0047 
0048 static struct timecounter niosv_clock_tc;
0049 
0050 static uint64_t niosv_mtime_get(void)
0051 {
0052   uint32_t lowbits;
0053   uint32_t highbits;
0054 
0055   /* Guard against rollover while acquiring each word */
0056   do {
0057     highbits = CLOCK_REGS->mtime_hi;
0058     lowbits = CLOCK_REGS->mtime_lo;
0059   } while (CLOCK_REGS->mtime_hi != highbits);
0060 
0061   return (((uint64_t)highbits) << 32) | lowbits;
0062 }
0063 
0064 static void niosv_mtimecmp_set(uint64_t next_time)
0065 {
0066   /*
0067    * Make sure to set the high word to a max value first to prevent triggering
0068    * inadvertently
0069    */
0070   CLOCK_REGS->mtimecmp_hi = 0xFFFFFFFF;
0071   CLOCK_REGS->mtimecmp_lo = (uint32_t)next_time;
0072   CLOCK_REGS->mtimecmp_hi = (uint32_t)(next_time >> 32);
0073   last_mtimecmp = next_time;
0074 }
0075 
0076 static void niosv_clock_exit(void)
0077 {
0078   clear_csr(mie, MIP_MTIP);
0079 }
0080 
0081 static uint32_t niosv_timer_read( void )
0082 {
0083   /* Write to request snapshot of timer value */
0084   TIMER_REGS->snap = 0;
0085 
0086   return (0xFFFFFFFF - TIMER_REGS->snap);
0087 }
0088 
0089 static uint32_t niosv_tc_get_timecount(struct timecounter *tc)
0090 {
0091   return niosv_timer_read();
0092 }
0093 
0094 static void niosv_clock_initialize(void)
0095 {
0096   uint64_t current_time;
0097 
0098   /* Register the driver exit procedure so we can shutdown */
0099   atexit(niosv_clock_exit);
0100 
0101   interval_period = (((uint64_t)CLOCK_FREQ) / 1000000) *
0102     (uint64_t)rtems_configuration_get_microseconds_per_tick();
0103   niosv_mtimecmp_set(MTIMECMP_MAX_VALUE);
0104 
0105   set_csr(mie, MIP_MTIP);
0106 
0107   current_time = niosv_mtime_get();
0108   niosv_mtimecmp_set(current_time + interval_period);
0109 
0110   /* Install timecounter */
0111   niosv_clock_tc.tc_get_timecount = niosv_tc_get_timecount;
0112   niosv_clock_tc.tc_counter_mask = 0xffffffff;
0113   niosv_clock_tc.tc_frequency = BENCHMARK_TIMER_INTERVAL_FREQ;
0114   niosv_clock_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
0115   rtems_timecounter_install(&niosv_clock_tc);
0116 }
0117 
0118 static void niosv_clock_at_tick(void)
0119 {
0120   niosv_mtimecmp_set(last_mtimecmp + interval_period);
0121 }
0122 
0123 static void niosv_clock_handler_install(void)
0124 {
0125   rtems_status_code sc;
0126 
0127   sc = rtems_interrupt_handler_install(
0128     NIOSV_INTERRUPT_VECTOR_TIMER,
0129     "Clock",
0130     RTEMS_INTERRUPT_UNIQUE,
0131     (rtems_interrupt_handler) Clock_isr,
0132     NULL
0133   );
0134   if (sc != RTEMS_SUCCESSFUL) {
0135     bsp_fatal(RISCV_FATAL_CLOCK_IRQ_INSTALL);
0136   }
0137 }
0138 
0139 static void niosv_counter_initialize( void )
0140 {
0141   /* Disable timer interrupt, stop timer */
0142   TIMER_REGS->control = ALTERA_AVALON_TIMER_CONTROL_STOP_MSK;
0143 
0144   /* set period to max value, running timer */
0145   TIMER_REGS->period = 0xFFFFFFFF;
0146 
0147   /* set prescalar for 1us timer */
0148   TIMER_REGS->prescalar = (
0149     BENCHMARK_TIMER_FREQ / BENCHMARK_TIMER_INTERVAL_FREQ
0150   ) - 1;
0151 
0152   /* For timers that can be stopped, writing to periodl/h
0153      also stopped the timer and we have to manually start it. */
0154 
0155   TIMER_REGS->control = ALTERA_AVALON_TIMER_CONTROL_CONT_MSK |
0156                         ALTERA_AVALON_TIMER_CONTROL_START_MSK;
0157 }
0158 
0159 void benchmark_timer_initialize(void)
0160 {
0161   benchmark_timer_base = niosv_timer_read();
0162 }
0163 
0164 benchmark_timer_t benchmark_timer_read(void)
0165 {
0166   uint32_t timer_snap = niosv_timer_read();
0167 
0168   /* Check for wrap around */
0169   if(benchmark_timer_base < timer_snap) {
0170     return (timer_snap - benchmark_timer_base);
0171   }
0172   return ((0xFFFFFFFF - benchmark_timer_base) + timer_snap + 1);
0173 }
0174 
0175 void benchmark_timer_disable_subtracting_average_overhead(
0176   bool find_average_overhead
0177 )
0178 {
0179   ( void ) find_average_overhead;
0180 }
0181 
0182 uint32_t _CPU_Counter_frequency( void )
0183 {
0184   return BENCHMARK_TIMER_INTERVAL_FREQ;
0185 }
0186 
0187 CPU_Counter_ticks _CPU_Counter_read( void )
0188 {
0189   return (CPU_Counter_ticks)niosv_timer_read();
0190 }
0191 
0192 RTEMS_SYSINIT_ITEM(
0193   niosv_counter_initialize,
0194   RTEMS_SYSINIT_CPU_COUNTER,
0195   RTEMS_SYSINIT_ORDER_FIRST
0196 );
0197 
0198 #define Clock_driver_support_at_tick(arg) niosv_clock_at_tick()
0199 
0200 #define Clock_driver_support_initialize_hardware() niosv_clock_initialize()
0201 
0202 #define Clock_driver_support_install_isr(isr) niosv_clock_handler_install()
0203 
0204 #include "../../../shared/dev/clock/clockimpl.h"
0205