Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsSPARCLEON3
0007  *
0008  * @brief This source file contains the Clock Driver implementation.
0009  */
0010 
0011 /*
0012  *  COPYRIGHT (c) 1989-2006.
0013  *  On-Line Applications Research Corporation (OAR).
0014  *
0015  *  Modified for LEON3 BSP.
0016  *  COPYRIGHT (c) 2004.
0017  *  Gaisler Research.
0018  *
0019  *  Copyright (C) 2014, 2023 embedded brains GmbH & Co. KG
0020  *
0021  * Redistribution and use in source and binary forms, with or without
0022  * modification, are permitted provided that the following conditions
0023  * are met:
0024  * 1. Redistributions of source code must retain the above copyright
0025  *    notice, this list of conditions and the following disclaimer.
0026  * 2. Redistributions in binary form must reproduce the above copyright
0027  *    notice, this list of conditions and the following disclaimer in the
0028  *    documentation and/or other materials provided with the distribution.
0029  *
0030  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0031  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0032  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0033  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0034  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0035  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0036  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0037  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0038  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0039  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0040  * POSSIBILITY OF SUCH DAMAGE.
0041  */
0042 
0043 #include <bsp.h>
0044 #include <bsp/fatal.h>
0045 #include <bsp/irq-generic.h>
0046 #include <bsp/leon3.h>
0047 #include <grlib/irqamp.h>
0048 #include <rtems/score/profiling.h>
0049 #include <rtems/timecounter.h>
0050 
0051 /* The LEON3 BSP Timer driver can rely on the Driver Manager if the
0052  * DrvMgr is initialized during startup. Otherwise the classic driver
0053  * must be used.
0054  *
0055  * The DrvMgr Clock driver is located in the shared/timer directory
0056  */
0057 #ifndef RTEMS_DRVMGR_STARTUP
0058 
0059 /* LEON3 Timer system interrupt number */
0060 static int clkirq;
0061 
0062 #if defined(RTEMS_PROFILING) && \
0063   (defined(LEON3_HAS_ASR_22_23_UP_COUNTER) || \
0064      defined(LEON3_PROBE_ASR_22_23_UP_COUNTER) || \
0065      defined(LEON3_IRQAMP_PROBE_TIMESTAMP))
0066 
0067 #define LEON3_CLOCK_PROBE_IRQAMP_TIMESTAMP
0068 
0069 #define IRQMP_TIMESTAMP_S1_S2 ((1U << 25) | (1U << 26))
0070 
0071 static void leon3_tc_tick_default(void)
0072 {
0073   rtems_timecounter_tick();
0074 }
0075 
0076 static void (*leon3_tc_tick)(void) = leon3_tc_tick_default;
0077 
0078 static void leon3_tc_do_tick(void)
0079 {
0080   (*leon3_tc_tick)();
0081 }
0082 
0083 static void leon3_tc_tick_irqmp_timestamp(void)
0084 {
0085   irqamp_timestamp *irqmp_ts =
0086     irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs);
0087   uint32_t first = grlib_load_32(&irqmp_ts->itstmpas);
0088   uint32_t second = grlib_load_32(&irqmp_ts->itcnt);
0089   uint32_t control = grlib_load_32(&irqmp_ts->itstmpc);
0090 
0091   control |= IRQMP_TIMESTAMP_S1_S2;
0092   grlib_store_32(&irqmp_ts->itstmpc, control);
0093 
0094   _Profiling_Update_max_interrupt_delay(_Per_CPU_Get(), second - first);
0095 
0096   rtems_timecounter_tick();
0097 }
0098 
0099 static void leon3_tc_tick_irqmp_timestamp_init(void)
0100 {
0101   /*
0102    * Ignore the first clock interrupt, since it contains the sequential system
0103    * initialization time.  Do the timestamp initialization on the fly.
0104    */
0105 
0106 #ifdef RTEMS_SMP
0107   static Atomic_Uint counter = ATOMIC_INITIALIZER_UINT(0);
0108 
0109   bool done =
0110     _Atomic_Fetch_add_uint(&counter, 1, ATOMIC_ORDER_RELAXED)
0111       == rtems_scheduler_get_processor_maximum() - 1;
0112 #else
0113   bool done = true;
0114 #endif
0115 
0116   irqamp_timestamp *irqmp_ts =
0117     irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs);
0118   uint32_t ks = 1U << 5;
0119   uint32_t control = grlib_load_32(&irqmp_ts->itstmpc);
0120 
0121   control = ks | IRQMP_TIMESTAMP_S1_S2 | (unsigned int) clkirq;
0122   grlib_store_32(&irqmp_ts->itstmpc, control);
0123 
0124   if (done) {
0125     leon3_tc_tick = leon3_tc_tick_irqmp_timestamp;
0126   }
0127 
0128   rtems_timecounter_tick();
0129 }
0130 #else
0131 static void leon3_tc_do_tick(void)
0132 {
0133   rtems_timecounter_tick();
0134 }
0135 #endif
0136 
0137 #define Adjust_clkirq_for_node() do { clkirq += LEON3_CLOCK_INDEX; } while(0)
0138 
0139 #define Clock_driver_support_find_timer() \
0140   do { \
0141     /* Assume timer found during BSP initialization */ \
0142     if (LEON3_Timer_Regs) { \
0143       clkirq = (grlib_load_32(&LEON3_Timer_Regs->config) & 0xf8) >> 3; \
0144       \
0145       Adjust_clkirq_for_node(); \
0146     } \
0147   } while (0)
0148 
0149 #define Clock_driver_support_install_isr(isr) \
0150   bsp_clock_handler_install(isr)
0151 
0152 static rtems_interrupt_entry leon3_clock_interrupt_entry;
0153 
0154 static void bsp_clock_handler_install(rtems_interrupt_handler isr)
0155 {
0156   rtems_status_code sc;
0157 
0158   rtems_interrupt_entry_initialize(
0159     &leon3_clock_interrupt_entry,
0160     isr,
0161     NULL,
0162     "Clock"
0163   );
0164   sc = rtems_interrupt_entry_install(
0165     clkirq,
0166     RTEMS_INTERRUPT_UNIQUE,
0167     &leon3_clock_interrupt_entry
0168   );
0169   if (sc != RTEMS_SUCCESSFUL) {
0170     rtems_fatal(RTEMS_FATAL_SOURCE_BSP, LEON3_FATAL_CLOCK_INITIALIZATION);
0171   }
0172 }
0173 
0174 #define Clock_driver_support_set_interrupt_affinity(online_processors) \
0175   bsp_interrupt_set_affinity(clkirq, online_processors)
0176 
0177 static void leon3_clock_initialize(void)
0178 {
0179   gptimer_timer *timer;
0180 
0181   timer = &LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX];
0182 
0183   grlib_store_32(
0184     &timer->trldval,
0185     rtems_configuration_get_microseconds_per_tick() - 1
0186   );
0187   grlib_store_32(
0188     &timer->tctrl,
0189     GPTIMER_TCTRL_EN | GPTIMER_TCTRL_RS | GPTIMER_TCTRL_LD | GPTIMER_TCTRL_IE
0190   );
0191 
0192 #if defined(LEON3_CLOCK_PROBE_IRQAMP_TIMESTAMP)
0193   if (irqamp_get_timestamp_registers(LEON3_IrqCtrl_Regs) != NULL) {
0194     leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
0195   }
0196 #endif
0197 
0198   rtems_timecounter_install(&leon3_timecounter_instance.base);
0199 }
0200 
0201 #define Clock_driver_support_initialize_hardware() \
0202   leon3_clock_initialize()
0203 
0204 #define Clock_driver_timecounter_tick(arg) leon3_tc_do_tick()
0205 
0206 #define BSP_FEATURE_IRQ_EXTENSION
0207 
0208 #include "../../../shared/dev/clock/clockimpl.h"
0209 
0210 #endif /* RTEMS_DRVMGR_STARTUP */