diff options
-rw-r--r-- | bsps/arm/xilinx-zynqmp-rpu/include/bsp.h | 3 | ||||
-rw-r--r-- | bsps/arm/xilinx-zynqmp-rpu/include/bsp/irq.h | 1 | ||||
-rw-r--r-- | bsps/shared/dev/clock/xil-ttc.c | 255 | ||||
-rw-r--r-- | spec/build/bsps/arm/xilinx-zynqmp-rpu/grp.yml | 6 | ||||
-rw-r--r-- | spec/build/bsps/optxilclockttcbaseaddr.yml | 18 | ||||
-rw-r--r-- | spec/build/bsps/optxilclockttcirq.yml | 18 | ||||
-rw-r--r-- | spec/build/bsps/optxilclockttcrefclk.yml | 18 | ||||
-rw-r--r-- | spec/build/testsuites/validation/bsps/objclockxilttc.yml | 14 | ||||
-rw-r--r-- | spec/build/testsuites/validation/bsps/validation-bsp-0.yml | 6 | ||||
-rw-r--r-- | testsuites/validation/tc-dev-clock-xil-ttc.c | 136 |
10 files changed, 337 insertions, 138 deletions
diff --git a/bsps/arm/xilinx-zynqmp-rpu/include/bsp.h b/bsps/arm/xilinx-zynqmp-rpu/include/bsp.h index d80cedbd0d..70ad4f3c57 100644 --- a/bsps/arm/xilinx-zynqmp-rpu/include/bsp.h +++ b/bsps/arm/xilinx-zynqmp-rpu/include/bsp.h @@ -59,7 +59,6 @@ #include <bsp/default-initial-extension.h> #include <bsp/start.h> -#include <peripheral_maps/xilinx_zynqmp.h> #include <dev/serial/zynq-uart-zynqmp.h> @@ -76,8 +75,6 @@ extern "C" { #define BSP_ARM_A9MPCORE_GT_BASE 0 -#define BSP_SELECTED_TTC_ADDR ZYNQMP_TTC0 - /** * @brief Zynq UltraScale+ MPSoC specific set up of the MMU. * diff --git a/bsps/arm/xilinx-zynqmp-rpu/include/bsp/irq.h b/bsps/arm/xilinx-zynqmp-rpu/include/bsp/irq.h index a65e5404f0..51aa613cdd 100644 --- a/bsps/arm/xilinx-zynqmp-rpu/include/bsp/irq.h +++ b/bsps/arm/xilinx-zynqmp-rpu/include/bsp/irq.h @@ -51,7 +51,6 @@ extern "C" { #endif /* __cplusplus */ -#define BSP_SELECTED_TTC_IRQ ZYNQMP_IRQ_TTC_0_0 #define BSP_INTERRUPT_VECTOR_COUNT 188 /** @} */ diff --git a/bsps/shared/dev/clock/xil-ttc.c b/bsps/shared/dev/clock/xil-ttc.c index 35f176b825..624845d71c 100644 --- a/bsps/shared/dev/clock/xil-ttc.c +++ b/bsps/shared/dev/clock/xil-ttc.c @@ -1,14 +1,16 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** * @file * - * @ingroup RTEMSBSPsARMZynqMP + * @ingroup RTEMSDriverClockXilTTC * - * @brief Triple Timer Counter clock functions definitions. + * @brief This source file contains a Clock Driver implementation using the + * Xilinx Triple Timer Counter (TTC). */ /* - * SPDX-License-Identifier: BSD-2-Clause - * + * Copyright (C) 2024 embedded brains GmbH & Co. KG * Copyright (C) 2023 Reflex Aerospace GmbH * * Written by Philip Kirkpatrick <p.kirkpatrick@reflexaerospace.com> @@ -38,175 +40,160 @@ #include <bsp.h> #include <bsp/irq.h> #include <bsp/fatal.h> -#include <peripheral_maps/xilinx_zynqmp.h> #include <dev/clock/xttcps_hw.h> +#include <rtems/sysinit.h> #include <rtems/timecounter.h> -typedef struct { - struct timecounter ttc_tc; - uint32_t irq_match_interval; - uint32_t tick_miss; -} ttc_clock_context; - -static ttc_clock_context ttc_clock_instance = {0, }; +#if XTTCPS_COUNT_VALUE_MASK != UINT32_MAX +#error "unexpected XTTCPS_COUNT_VALUE_MASK value" +#endif -#define TTC_REFERENCE_CLOCK 100000000 +/** + * @defgroup RTEMSDriverClockXilTTC \ + * Xilinx Triple Timer Counter (TTC) Clock Driver + * + * @ingroup RTEMSDriverClockImpl + * + * @brief This group contains the Xilinx Triple Timer Counter (TTC) Clock + * Driver implementation. + * + * @{ + */ uint32_t _CPU_Counter_frequency( void ) { - return ttc_clock_instance.ttc_tc.tc_frequency; + return XIL_CLOCK_TTC_REFERENCE_CLOCK; } -static uint32_t zynqmp_ttc_get_timecount(struct timecounter *tc) +CPU_Counter_ticks _CPU_Counter_read(void) { - uint32_t time; - time = XTtcPs_ReadReg(BSP_SELECTED_TTC_ADDR, XTTCPS_COUNT_VALUE_OFFSET); - return time; + return XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_COUNT_VALUE_OFFSET); } -CPU_Counter_ticks _CPU_Counter_read(void) +static void xil_ttc_initialize(void) { - return zynqmp_ttc_get_timecount(&ttc_clock_instance.ttc_tc); + /* Do not use a prescaler to get a high resolution time source */ + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_CLK_CNTRL_OFFSET, 0); + + /* Disable interupts */ + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_IER_OFFSET, 0); + + /* + * Enable the timer, do not enable waveform output, increment up, use + * overflow mode, enable match mode. + */ + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_CNT_CNTRL_OFFSET, + XTTCPS_CNT_CNTRL_EN_WAVE_MASK | XTTCPS_CNT_CNTRL_MATCH_MASK); } -/** - * @brief Initialize the HW peripheral for clock driver - * - * Clock driver is implemented by RTI module - * - * @retval Void - */ -static void zynqmp_ttc_clock_driver_support_initialize_hardware(void) -{ +RTEMS_SYSINIT_ITEM( + xil_ttc_initialize, + RTEMS_SYSINIT_CPU_COUNTER, + RTEMS_SYSINIT_ORDER_MIDDLE +); + +typedef struct { + struct timecounter base; + uint32_t irq_match_interval; +} xil_ttc_timecounter; - uint32_t microsec_per_tick; - uint16_t clock_ratio; - uint8_t index; - uint32_t frequency; - uint32_t prescaler; - uint32_t tmp_reg_val; +static xil_ttc_timecounter xil_ttc_clock_instance; - microsec_per_tick = rtems_configuration_get_microseconds_per_tick(); +static uint32_t xil_ttc_get_timecount(struct timecounter *tc) +{ + (void) tc; + return XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_COUNT_VALUE_OFFSET); +} - /* Check the TTC is OFF before reconfiguring */ - XTtcPs_WriteReg(BSP_SELECTED_TTC_ADDR, XTTCPS_CNT_CNTRL_OFFSET, - /* Don't enable waveform output */ - XTTCPS_CNT_CNTRL_DIS_MASK | XTTCPS_CNT_CNTRL_EN_WAVE_MASK); +static void xil_ttc_clock_driver_support_initialize_hardware(void) +{ + xil_ttc_timecounter *tc; + uint64_t frequency; + uint32_t irq_match_interval; + uint32_t count; - /* Prescaler value is 2^(N + 1) - * Divide down the clock as much as possible while still retaining a - * frequency that is an integer multiple of 1MHz. This maximizes time to - * overflow while minimizing rounding errors in 1us periods - */ - clock_ratio = TTC_REFERENCE_CLOCK / 1000000; - /* Search for the highest set bit. This is effectively min(log2(ratio)) */ - for(index = sizeof(clock_ratio) * 8 - 1; index > 0; index--) { - if((clock_ratio >> (index)) & 0x01) { - break; - } - } - if(index == 0 && (clock_ratio & 0x01) == 0) { - /* No prescaler */ - frequency = TTC_REFERENCE_CLOCK; - XTtcPs_WriteReg(BSP_SELECTED_TTC_ADDR, XTTCPS_CLK_CNTRL_OFFSET, 0); - } else { - prescaler = index - 1; - frequency = TTC_REFERENCE_CLOCK / (1 << (prescaler + 1)); - XTtcPs_WriteReg(BSP_SELECTED_TTC_ADDR, XTTCPS_CLK_CNTRL_OFFSET, - prescaler << XTTCPS_CLK_CNTRL_PS_VAL_SHIFT | - XTTCPS_CLK_CNTRL_PS_EN_MASK); - } + tc = &xil_ttc_clock_instance; + frequency = XIL_CLOCK_TTC_REFERENCE_CLOCK; + irq_match_interval = (uint32_t) + ((frequency * rtems_configuration_get_microseconds_per_tick()) / 1000000); - /* Max out the counter interval */ - tmp_reg_val = XTTCPS_INTERVAL_VAL_MASK; - XTtcPs_WriteReg(BSP_SELECTED_TTC_ADDR, XTTCPS_INTERVAL_VAL_OFFSET, - tmp_reg_val); + /* Setup match register to generate clock interrupts */ + count = XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_COUNT_VALUE_OFFSET); + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_MATCH_0_OFFSET, + count + irq_match_interval); - /* Setup match register to generate tick IRQ */ - ttc_clock_instance.irq_match_interval = - (uint32_t) (((uint64_t)frequency * microsec_per_tick) / 1000000); - XTtcPs_WriteReg(BSP_SELECTED_TTC_ADDR, XTTCPS_MATCH_0_OFFSET, - ttc_clock_instance.irq_match_interval); /* Clear interupts (clear on read) */ - XTtcPs_ReadReg(BSP_SELECTED_TTC_ADDR, XTTCPS_ISR_OFFSET); + (void) XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_ISR_OFFSET); + /* Enable interupt for match register */ - XTtcPs_WriteReg(BSP_SELECTED_TTC_ADDR, XTTCPS_IER_OFFSET, + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_IER_OFFSET, XTTCPS_IXR_MATCH_0_MASK); - /* Configure, reset, and enable counter */ - XTtcPs_WriteReg(BSP_SELECTED_TTC_ADDR, XTTCPS_CNT_CNTRL_OFFSET, - XTTCPS_CNT_CNTRL_EN_WAVE_MASK | /* Don't enable waveform output */ - XTTCPS_CNT_CNTRL_RST_MASK | /* Reset count and start counter */ - XTTCPS_CNT_CNTRL_MATCH_MASK /* Enable match mode */ - /* Increment mode */ - /* Overflow mode */ - /* Not disabled */ - ); - - /* set timecounter */ - ttc_clock_instance.ttc_tc.tc_get_timecount = zynqmp_ttc_get_timecount; - ttc_clock_instance.ttc_tc.tc_counter_mask = XTTCPS_COUNT_VALUE_MASK; - ttc_clock_instance.ttc_tc.tc_frequency = frequency; - ttc_clock_instance.ttc_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; - rtems_timecounter_install(&ttc_clock_instance.ttc_tc); + + /* Install timecounter */ + tc->irq_match_interval = irq_match_interval; + tc->base.tc_counter_mask = UINT32_MAX; + tc->base.tc_frequency = XIL_CLOCK_TTC_REFERENCE_CLOCK; + tc->base.tc_get_timecount = xil_ttc_get_timecount; + tc->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install(&tc->base); } -/** - * @brief Clears interrupt source - * - * @retval Void - */ -static void zynqmp_ttc_clock_driver_support_at_tick(ttc_clock_context *tc) +static void xil_ttc_clock_driver_support_at_tick(xil_ttc_timecounter *tc) { - uint32_t irq_flags; - uint32_t cval; - uint32_t now; - uint32_t delta; - - /* Get and clear interupts (clear on read) */ - irq_flags = XTtcPs_ReadReg(BSP_SELECTED_TTC_ADDR, XTTCPS_ISR_OFFSET); - - if(irq_flags & XTTCPS_IXR_MATCH_0_MASK) { - /* Update match */ - cval = XTtcPs_ReadReg(BSP_SELECTED_TTC_ADDR, XTTCPS_MATCH_0_OFFSET); - /* Check that the match for the next tick is in the future - * If no, then set the match for one irq interval from now - * This will have the effect that your timebase will slip but - * won't hang waiting for the counter to wrap around. - * If this happens during normal operation, there is a problem - * causing this interrupt to not be serviced quickly enough - * If this happens during debugging, that is normal and expected - * because the TTC does NOT pause when the CPU is halted on a breakpoint + uint32_t irq_match_interval; + uint32_t count; + uint32_t match; + + irq_match_interval = tc->irq_match_interval; + + /* Update match register */ + match = XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_MATCH_0_OFFSET); + match += irq_match_interval; + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_MATCH_0_OFFSET, match); + + /* Clear interupts (clear on read) */ + (void) XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_ISR_OFFSET); + + /* Check that the new match value is in the future */ + count = XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_COUNT_VALUE_OFFSET); + + while (RTEMS_PREDICT_FALSE(match - count > irq_match_interval)) { + /* + * Tick misses may happen if interrupts are disabled for an extremly long + * period or while debugging. */ - now = XTtcPs_ReadReg(BSP_SELECTED_TTC_ADDR, XTTCPS_COUNT_VALUE_OFFSET); - delta = now - cval; - if(delta > tc->irq_match_interval) { - cval = now; - tc->tick_miss++; - } - cval += tc->irq_match_interval; - XTtcPs_WriteReg(BSP_SELECTED_TTC_ADDR, XTTCPS_MATCH_0_OFFSET, cval); + rtems_timecounter_tick(); + + /* Update match register */ + match += irq_match_interval; + XTtcPs_WriteReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_MATCH_0_OFFSET, match); + + /* Clear interupts (clear on read) */ + (void) XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_ISR_OFFSET); + + /* Maybe the new match value is now in the future */ + count = XTtcPs_ReadReg(XIL_CLOCK_TTC_BASE_ADDR, XTTCPS_COUNT_VALUE_OFFSET); } - /* Else, something is set up wrong, only match should be enabled */ } -static rtems_interrupt_entry zynqmp_ttc_interrupt_entry; +static rtems_interrupt_entry xil_ttc_interrupt_entry; -static void zynqmp_ttc_clock_driver_support_install_isr( +static void xil_ttc_clock_driver_support_install_isr( rtems_interrupt_handler handler ) { rtems_status_code sc; rtems_interrupt_entry_initialize( - &zynqmp_ttc_interrupt_entry, + &xil_ttc_interrupt_entry, handler, - &ttc_clock_instance, + &xil_ttc_clock_instance, "Clock" ); sc = rtems_interrupt_entry_install( - BSP_SELECTED_TTC_IRQ, + XIL_CLOCK_TTC_IRQ, RTEMS_INTERRUPT_UNIQUE, - &zynqmp_ttc_interrupt_entry + &xil_ttc_interrupt_entry ); if ( sc != RTEMS_SUCCESSFUL ) { bsp_fatal(XIL_FATAL_TTC_IRQ_INSTALL); @@ -214,12 +201,14 @@ static void zynqmp_ttc_clock_driver_support_install_isr( } #define Clock_driver_support_at_tick(arg) \ - zynqmp_ttc_clock_driver_support_at_tick(arg) + xil_ttc_clock_driver_support_at_tick(arg) #define Clock_driver_support_initialize_hardware \ - zynqmp_ttc_clock_driver_support_initialize_hardware + xil_ttc_clock_driver_support_initialize_hardware #define Clock_driver_support_install_isr(isr) \ - zynqmp_ttc_clock_driver_support_install_isr(isr) + xil_ttc_clock_driver_support_install_isr(isr) + +/** @} */ #include "../../../shared/dev/clock/clockimpl.h" diff --git a/spec/build/bsps/arm/xilinx-zynqmp-rpu/grp.yml b/spec/build/bsps/arm/xilinx-zynqmp-rpu/grp.yml index df576368d5..a088c69052 100644 --- a/spec/build/bsps/arm/xilinx-zynqmp-rpu/grp.yml +++ b/spec/build/bsps/arm/xilinx-zynqmp-rpu/grp.yml @@ -25,6 +25,12 @@ links: - role: build-dependency uid: optconirq - role: build-dependency + uid: ../../optxilclockttcbaseaddr +- role: build-dependency + uid: ../../optxilclockttcirq +- role: build-dependency + uid: ../../optxilclockttcrefclk +- role: build-dependency uid: optint0len - role: build-dependency uid: optint0ori diff --git a/spec/build/bsps/optxilclockttcbaseaddr.yml b/spec/build/bsps/optxilclockttcbaseaddr.yml new file mode 100644 index 0000000000..c6f4769428 --- /dev/null +++ b/spec/build/bsps/optxilclockttcbaseaddr.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- get-integer: null +- format-and-define: null +build-type: option +copyrights: +- Copyright (C) 2024 embedded brains GmbH & Co. KG +default: +- enabled-by: true + value: 0xff110000 +description: | + This option defines the Xilinx Triple-Timer Counter (TTC) base address used by + the Clock Driver. +enabled-by: true +format: '{:#010x}' +links: [] +name: XIL_CLOCK_TTC_BASE_ADDR +type: build diff --git a/spec/build/bsps/optxilclockttcirq.yml b/spec/build/bsps/optxilclockttcirq.yml new file mode 100644 index 0000000000..248e4e313b --- /dev/null +++ b/spec/build/bsps/optxilclockttcirq.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- get-integer: null +- define: null +build-type: option +copyrights: +- Copyright (C) 2024 embedded brains GmbH & Co. KG +default: +- enabled-by: true + value: 68 +description: | + This option defines the Xilinx Triple-Timer Counter (TTC) interrupt vector + number used by the Clock Driver. +enabled-by: true +format: '{}' +links: [] +name: XIL_CLOCK_TTC_IRQ +type: build diff --git a/spec/build/bsps/optxilclockttcrefclk.yml b/spec/build/bsps/optxilclockttcrefclk.yml new file mode 100644 index 0000000000..0a9723828b --- /dev/null +++ b/spec/build/bsps/optxilclockttcrefclk.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- get-integer: null +- define: null +build-type: option +copyrights: +- Copyright (C) 2024 embedded brains GmbH & Co. KG +default: +- enabled-by: true + value: 100000000 +description: | + This option defines the Xilinx Triple-Timer Counter (TTC) reference clock in + Hz used by the Clock Driver. +enabled-by: true +format: '{}' +links: [] +name: XIL_CLOCK_TTC_REFERENCE_CLOCK +type: build diff --git a/spec/build/testsuites/validation/bsps/objclockxilttc.yml b/spec/build/testsuites/validation/bsps/objclockxilttc.yml new file mode 100644 index 0000000000..b080bcdbfb --- /dev/null +++ b/spec/build/testsuites/validation/bsps/objclockxilttc.yml @@ -0,0 +1,14 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: objects +cflags: [] +copyrights: +- Copyright (C) 2024 embedded brains GmbH & Co. KG +cppflags: [] +cxxflags: [] +enabled-by: bsps/arm/xilinx-zynqmp-rpu +includes: [] +install: [] +links: [] +source: +- testsuites/validation/tc-dev-clock-xil-ttc.c +type: build diff --git a/spec/build/testsuites/validation/bsps/validation-bsp-0.yml b/spec/build/testsuites/validation/bsps/validation-bsp-0.yml index af811b8502..790e05e0bc 100644 --- a/spec/build/testsuites/validation/bsps/validation-bsp-0.yml +++ b/spec/build/testsuites/validation/bsps/validation-bsp-0.yml @@ -5,13 +5,17 @@ copyrights: - Copyright (C) 2023 embedded brains GmbH & Co. KG cppflags: [] cxxflags: [] -enabled-by: bsps/sparc/leon3 +enabled-by: +- bsps/arm/xilinx-zynqmp-rpu +- bsps/sparc/leon3 features: c cprogram includes: [] ldflags: - -Wl,--wrap=_IO_Relax links: - role: build-dependency + uid: objclockxilttc +- role: build-dependency uid: objgrlib - role: build-dependency uid: objsparcgr712rc diff --git a/testsuites/validation/tc-dev-clock-xil-ttc.c b/testsuites/validation/tc-dev-clock-xil-ttc.c new file mode 100644 index 0000000000..70f49a4cc6 --- /dev/null +++ b/testsuites/validation/tc-dev-clock-xil-ttc.c @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup DevClockXilTtcValTickCatchUp + */ + +/* + * Copyright (C) 2024 embedded brains GmbH & Co. KG + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file is part of the RTEMS quality process and was automatically + * generated. If you find something that needs to be fixed or + * worded better please post a report or patch to an RTEMS mailing list + * or raise a bug report: + * + * https://www.rtems.org/bugs.html + * + * For information on updating and regenerating please refer to the How-To + * section in the Software Requirements Engineering chapter of the + * RTEMS Software Engineering manual. The manual is provided as a part of + * a release. For development sources please refer to the online + * documentation at: + * + * https://docs.rtems.org + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <sys/time.h> + +#include <rtems/test.h> + +/** + * @defgroup DevClockXilTtcValTickCatchUp \ + * spec:/dev/clock/xil-ttc/val/tick-catch-up + * + * @ingroup TestsuitesBspsValidationBsp0 + * + * @brief Tests some Xilinx TTC clock driver functions. + * + * This test case performs the following actions: + * + * - Synchronize with the clock tick. Disable interrupts. Busy wait three + * clock tick intervals. Enable interrupts. + * + * - Check that exactly three clock ticks happened once interrupts are + * enabled again. + * + * @{ + */ + +/** + * @brief Synchronize with the clock tick. Disable interrupts. Busy wait + * three clock tick intervals. Enable interrupts. + */ +static void DevClockXilTtcValTickCatchUp_Action_0( void ) +{ + uint32_t ns_per_tick; + uint64_t three_ticks_interval; + rtems_interrupt_level level; + rtems_interval t_0; + rtems_interval t_1; + rtems_interval t_2; + uint64_t m_0; + uint64_t m_1; + + ns_per_tick = rtems_configuration_get_nanoseconds_per_tick(); + three_ticks_interval = ( 7 * (uint64_t) nstosbt( ns_per_tick ) ) / 2; + t_0 = rtems_clock_get_ticks_since_boot(); + + /* Synchronize with clock tick */ + do { + t_1 = rtems_clock_get_ticks_since_boot(); + m_0 = (uint64_t) rtems_clock_get_monotonic_sbintime(); + } while ( t_0 == t_1 ); + + rtems_interrupt_local_disable( level ); + + do { + m_1 = (uint64_t) rtems_clock_get_monotonic_sbintime(); + } while ( m_1 - m_0 <= three_ticks_interval ); + + rtems_interrupt_local_enable( level ); + + /* + * Make sure the clock interrupt was serviced after the interrupt enable. + */ + do { + t_2 = rtems_clock_get_ticks_since_boot(); + } while ( t_1 == t_2 ); + + /* + * Check that exactly three clock ticks happened once interrupts are enabled + * again. + */ + T_step_eq_u32( 0, t_2 - t_1, 3 ); +} + +/** + * @fn void T_case_body_DevClockXilTtcValTickCatchUp( void ) + */ +T_TEST_CASE( DevClockXilTtcValTickCatchUp ) +{ + T_plan( 1 ); + + DevClockXilTtcValTickCatchUp_Action_0(); +} + +/** @} */ |