summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bsps/arm/xilinx-zynqmp-rpu/include/bsp.h3
-rw-r--r--bsps/arm/xilinx-zynqmp-rpu/include/bsp/irq.h1
-rw-r--r--bsps/shared/dev/clock/xil-ttc.c255
-rw-r--r--spec/build/bsps/arm/xilinx-zynqmp-rpu/grp.yml6
-rw-r--r--spec/build/bsps/optxilclockttcbaseaddr.yml18
-rw-r--r--spec/build/bsps/optxilclockttcirq.yml18
-rw-r--r--spec/build/bsps/optxilclockttcrefclk.yml18
-rw-r--r--spec/build/testsuites/validation/bsps/objclockxilttc.yml14
-rw-r--r--spec/build/testsuites/validation/bsps/validation-bsp-0.yml6
-rw-r--r--testsuites/validation/tc-dev-clock-xil-ttc.c136
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();
+}
+
+/** @} */