Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSDriverClockArmGenericTimer
0007  *
0008  * @brief This source file contains a Clock Driver implementation using
0009  *   Armv7-AR/AArch64 Generic Timer.
0010  */
0011 
0012 /*
0013  * Copyright (c) 2017 embedded brains GmbH & Co. KG
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #include <bsp.h>
0038 #include <bsp/fatal.h>
0039 #include <bsp/irq.h>
0040 #include <bsp/irq-generic.h>
0041 #include <dev/clock/arm-generic-timer.h>
0042 
0043 #include <rtems/counter.h>
0044 #include <rtems/sysinit.h>
0045 #include <rtems/timecounter.h>
0046 #include <rtems/score/smpimpl.h>
0047 
0048 /**
0049  * @defgroup RTEMSDriverClockArmGenericTimer \
0050  *   Armv7-AR/AArch64 Generic Timer Clock Driver
0051  *
0052  * @ingroup RTEMSDriverClockImpl
0053  *
0054  * @brief This group contains the Armv7-AR/AArch64 Generic Timer Clock Driver
0055  *   implementation.
0056  *
0057  * The BSP must provide the following function:
0058  *
0059  * void arm_generic_timer_get_config(uint32_t *frequency, uint32_t *irq);
0060  *
0061  * The BSP may optionally define ARM_GENERIC_TIMER_USE_VIRTUAL in <bsp.h> to
0062  * use the virtual timer instead of the physical timer.
0063  *
0064  * @{
0065  */
0066 
0067 typedef struct {
0068   struct timecounter tc;
0069   uint32_t interval;
0070   rtems_vector_number irq;
0071 } arm_gt_clock_context;
0072 
0073 static arm_gt_clock_context arm_gt_clock_instance;
0074 
0075 static void arm_gt_clock_at_tick(arm_gt_clock_context *ctx)
0076 {
0077   uint64_t cval;
0078   uint32_t interval;
0079 
0080   interval = ctx->interval;
0081   cval = arm_gt_clock_get_compare_value();
0082   cval += interval;
0083   arm_gt_clock_set_compare_value(cval);
0084 #ifdef ARM_GENERIC_TIMER_UNMASK_AT_TICK
0085   arm_gt_clock_set_control(0x1);
0086 #endif /* ARM_GENERIC_TIMER_UNMASK_AT_TICK */
0087 }
0088 
0089 static rtems_interrupt_entry arm_gt_interrupt_entry;
0090 
0091 static void arm_gt_clock_handler_install(rtems_interrupt_handler handler)
0092 {
0093   rtems_status_code sc;
0094 
0095   rtems_interrupt_entry_initialize(
0096     &arm_gt_interrupt_entry,
0097     handler,
0098     &arm_gt_clock_instance,
0099     "Clock"
0100   );
0101   sc = rtems_interrupt_entry_install(
0102     arm_gt_clock_instance.irq,
0103     RTEMS_INTERRUPT_UNIQUE,
0104     &arm_gt_interrupt_entry
0105   );
0106   if (sc != RTEMS_SUCCESSFUL) {
0107     bsp_fatal(BSP_ARM_FATAL_GENERIC_TIMER_CLOCK_IRQ_INSTALL);
0108   }
0109 }
0110 
0111 static uint32_t arm_gt_clock_get_timecount(struct timecounter *tc)
0112 {
0113   return (uint32_t) arm_gt_clock_get_count();
0114 }
0115 
0116 static void arm_gt_clock_gt_init(uint64_t cval)
0117 {
0118   arm_gt_clock_set_compare_value(cval);
0119   arm_gt_clock_set_control(0x1);
0120 }
0121 
0122 #if defined(RTEMS_SMP) && !defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR)
0123 static void arm_gt_clock_secondary_action(void *arg)
0124 {
0125   uint64_t *cval;
0126 
0127   cval = arg;
0128   arm_gt_clock_gt_init(*cval);
0129   bsp_interrupt_vector_enable(arm_gt_clock_instance.irq);
0130 }
0131 #endif
0132 
0133 static void arm_gt_clock_secondary_initialization(uint64_t cval)
0134 {
0135 #if defined(RTEMS_SMP) && !defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR)
0136   _SMP_Broadcast_action(arm_gt_clock_secondary_action, &cval);
0137 #endif
0138 }
0139 
0140 static void arm_gt_clock_initialize(void)
0141 {
0142   uint64_t frequency;
0143   uint64_t us_per_tick;
0144   uint32_t interval;
0145   uint64_t cval;
0146   struct timecounter *tc;
0147 
0148   tc = &arm_gt_clock_instance.tc;
0149   frequency = tc->tc_frequency;
0150   us_per_tick = rtems_configuration_get_microseconds_per_tick();
0151   interval = (uint32_t) ((frequency * us_per_tick) / 1000000);
0152   cval = arm_gt_clock_get_count();
0153   cval += interval;
0154   arm_gt_clock_instance.interval = interval;
0155 
0156   arm_gt_clock_gt_init(cval);
0157   arm_gt_clock_secondary_initialization(cval);
0158 
0159   tc->tc_get_timecount = arm_gt_clock_get_timecount;
0160   tc->tc_counter_mask = 0xffffffff;
0161   tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
0162   rtems_timecounter_install(tc);
0163 }
0164 
0165 uint32_t _CPU_Counter_frequency(void)
0166 {
0167   return (uint32_t) arm_gt_clock_instance.tc.tc_frequency;
0168 }
0169 
0170 CPU_Counter_ticks _CPU_Counter_read(void)
0171 {
0172   return (uint32_t) arm_gt_clock_get_count();
0173 }
0174 
0175 static void arm_gt_system_init(void)
0176 {
0177 #ifdef ARM_GENERIC_TIMER_SYSTEM_BASE
0178   volatile uint32_t *cntcr;
0179 
0180   cntcr = (volatile uint32_t *) ARM_GENERIC_TIMER_SYSTEM_BASE;
0181   *cntcr = ARM_GENERIC_TIMER_SYSTEM_CNTCR;
0182 #endif
0183 }
0184 
0185 static void arm_gt_clock_early_init(void)
0186 {
0187   uint32_t frequency;
0188 
0189   arm_gt_system_init();
0190   arm_gt_clock_set_control(0x3);
0191   arm_generic_timer_get_config(
0192     &frequency,
0193     &arm_gt_clock_instance.irq
0194   );
0195 
0196   /*
0197    * Used by _CPU_Counter_frequency() before arm_gt_clock_initialize() is
0198    * called.
0199    */
0200   arm_gt_clock_instance.tc.tc_frequency = frequency;
0201 }
0202 
0203 RTEMS_SYSINIT_ITEM(
0204   arm_gt_clock_early_init,
0205   RTEMS_SYSINIT_CPU_COUNTER,
0206   RTEMS_SYSINIT_ORDER_FIRST
0207 );
0208 
0209 #define Clock_driver_support_at_tick(arg) \
0210   arm_gt_clock_at_tick(arg)
0211 
0212 #define Clock_driver_support_initialize_hardware() \
0213   arm_gt_clock_initialize()
0214 
0215 #define Clock_driver_support_install_isr(isr) \
0216   arm_gt_clock_handler_install(isr)
0217 
0218 /** @} */
0219 
0220 /* Include shared source clock driver code */
0221 #include "../../shared/dev/clock/clockimpl.h"