| /* |
| * Copyright (c) 2019 Arm Limited |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * \file systimer_armv8-m_drv.h |
| * |
| * \brief Driver for Armv8-M System Timer |
| * |
| * This System Timer is based on the 64-bit Armv8-M System Counter, |
| * generating the physical count for System Timer. |
| * |
| * Main features: |
| * - Disabling the timer doesn't stop counting, but it disables timer output |
| * signal, what might be a power saving option. |
| * - 1 interrupt signal, can be triggered by the 2 modes below |
| * Modes: |
| * 1. Normal mode |
| * For clearing the interrupt generated by normal mode, the Timer |
| * should be disabled. |
| * Views |
| * 1.1. 64-bit up-counting Compare view |
| * As soon as the physical up-counter reaches the set |
| * compare value, the interrupt status will be asserted. |
| * \ref systimer_armv8_m_set_compare_value |
| * \ref systimer_armv8_m_get_compare_value |
| |
| * 1.2. 32-bit down-counting Timer view |
| * As soon as the down-counter timer reaches zero, |
| * the interrupt status will be asserted. |
| * Setting the down-counter timer value, sets the compare |
| * register by |
| * compare register = current counter + timer value |
| * \ref systimer_armv8_m_set_timer_value |
| * \ref systimer_armv8_m_get_timer_value |
| * |
| * 2. Auto-Increment mode |
| * - The auto-increment feature allows generation of Timer |
| * interrupt at regular intervals without the need for |
| * reprogramming the Timer after each interrupt and re-enabling |
| * the timer logic. |
| * - Auto-increment is working as a 64-bit up-counter, which is set |
| * by the 32-bit reload register. |
| * - If auto-increment mode is enabled, none of the normal modes' |
| * views can assert interrupt. * |
| * \ref systimer_armv8_m_get_autoinc_value |
| * \ref systimer_armv8_m_set_autoinc_reload |
| * \ref systimer_armv8_m_enable_autoinc |
| * \ref systimer_armv8_m_disable_autoinc |
| * \ref systimer_armv8_m_is_autoinc_enabled |
| * \ref systimer_armv8_m_clear_autoinc_interrupt |
| * \ref systimer_armv8_m_is_autoinc_implemented |
| * |
| */ |
| |
| #ifndef __SYSTIMER_ARMV8_M_DRV_H__ |
| #define __SYSTIMER_ARMV8_M_DRV_H__ |
| |
| #include <stdbool.h> |
| #include <stdint.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #define SYSTIMER_ARMV8_M_REGISTER_BIT_WIDTH 32u |
| /*!< Armv8-M System Timer registers bit width */ |
| |
| /** |
| * \brief Armv8-M System Timer device configuration structure |
| */ |
| struct systimer_armv8_m_dev_cfg_t |
| { |
| const uint32_t base; |
| /*!< Armv8-M System Timer device base address */ |
| uint32_t default_freq_hz; |
| /*!< Default reported frequency in Hz */ |
| }; |
| |
| /** |
| * \brief Armv8-M System Timer device data structure |
| */ |
| struct systimer_armv8_m_dev_data_t |
| { |
| bool is_initialized; |
| }; |
| |
| /** |
| * \brief Armv8-M System Timer device structure |
| */ |
| struct systimer_armv8_m_dev_t |
| { |
| const struct systimer_armv8_m_dev_cfg_t * const cfg; |
| /*!< Armv8-M System Timer configuration structure */ |
| struct systimer_armv8_m_dev_data_t * const data; |
| /*!< Armv8-M System Timer data structure */ |
| }; |
| |
| /** |
| * \brief Initializes timer to a known default state, which is: |
| * - timer is enabled |
| * - interrupt is disabled |
| * - auto-increment is disabled |
| * - reported timer frequency is set to default |
| * Init should be called prior to any other process and |
| * it's the caller's responsibility to follow proper call order. |
| * More than one call results fall through. |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_init(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Uninitializes timer to a known default state, which is: |
| * - timer is disabled |
| * - interrupt is disabled |
| * - auto-increment is disabled |
| * Init should be called prior to any other process and |
| * it's the caller's responsibility to follow proper call order. |
| * More than one call results fall through. |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_uninit(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Reads 64-bit physical counter value |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \return 64-bit counter value |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| uint64_t systimer_armv8_m_get_counter_value(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Sets 64-bit compare value |
| * As soon as the physical up-counter reaches this value, the interrupt |
| * condition will be asserted \ref systimer_armv8_m_is_interrupt_asserted |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * \param[in] value 64-bit compare value |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_set_compare_value(struct systimer_armv8_m_dev_t * dev, uint64_t value); |
| |
| /** |
| * \brief Reads 64-bit compare value |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \return 64-bit compare value |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| uint64_t systimer_armv8_m_get_compare_value(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Sets frequency register in Hz |
| * Hardware does not interpret the value of the register, so it's only |
| * for software can discover the frequency of the system counter. |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * \param[in] value frequency in Hz |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_set_counter_freq(struct systimer_armv8_m_dev_t * dev, uint32_t value); |
| |
| /** |
| * \brief Reads frequency register in Hz |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \return frequency in Hz |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| uint32_t systimer_armv8_m_get_counter_freq(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Sets 32-bit down-counter timer value |
| * 'Down-counter timer set' automatically sets the compare register by |
| * compare register = current counter + this timer value |
| * |
| * As soon as the timer value reaches zero, the interrupt condition will |
| * be asserted \ref systimer_armv8_m_is_interrupt_asserted. |
| * Reaching zero doesn't stop the timer. |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * \param[in] value 32-bit timer value |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_set_timer_value(struct systimer_armv8_m_dev_t * dev, uint32_t value); |
| |
| /** |
| * \brief Reads down-counter timer value |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \return 32-bit timer value |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| uint32_t systimer_armv8_m_get_timer_value(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Enables timer |
| * Enables timer output signal and interrupt status assertion |
| * \ref systimer_armv8_m_is_interrupt_asserted |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_enable_timer(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Disables timer |
| * Disables timer output signal. Interrupt status will be unknown |
| * \ref systimer_armv8_m_is_interrupt_asserted |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_disable_timer(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Polls timer enable status |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \return true if enabled, false otherwise |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| bool systimer_armv8_m_is_timer_enabled(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Enables timer interrupt |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_enable_interrupt(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Disables timer interrupt |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_disable_interrupt(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Polls timer interrupt enable status |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \return true if enabled, false otherwise |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| bool systimer_armv8_m_is_interrupt_enabled(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Polls timer interrupt status |
| * It's asserted if |
| * 1. Auto-Inc is disabled and counter reaches compare value |
| * OR |
| * 2. Auto-Inc is enabled and counter reaches auto-inc value |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \return true if asserted, false otherwise |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| bool systimer_armv8_m_is_interrupt_asserted(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Reads auto-increment value |
| * This value is automatically calculated by |
| * auto-inc = current counter + auto-inc reload |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \return 64-bit auto-increment value |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| uint64_t systimer_armv8_m_get_autoinc_value(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Sets 32-bit auto-increment reload value |
| * Auto-Inc value is automatically calculated by adding this reload value |
| * to the current counter. |
| * If the counter reaches auto-inc value, interrupt status is asserted |
| * and auto-inc value is automatically set by current reload. |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * \param[in] value 32-bit reload value |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_set_autoinc_reload(struct systimer_armv8_m_dev_t * dev, uint32_t value); |
| |
| /** |
| * \brief Reads auto-increment reload value |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \return 32-bit auto-increment reload value |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| uint32_t systimer_armv8_m_get_autoinc_reload(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Enables auto-increment mode |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_enable_autoinc(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Disables auto-increment mode |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_disable_autoinc(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Polls auto-increment enable status |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \return true if enabled, false otherwise |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| bool systimer_armv8_m_is_autoinc_enabled(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Clears auto-increment mode interrupt flag |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| void systimer_armv8_m_clear_autoinc_interrupt(struct systimer_armv8_m_dev_t * dev); |
| |
| /** |
| * \brief Polls auto-increment implementation status |
| * |
| * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t |
| * |
| * \return true if implemented, false otherwise |
| * |
| * \note This function doesn't check if dev is NULL. |
| */ |
| bool systimer_armv8_m_is_autoinc_implemented(struct systimer_armv8_m_dev_t * dev); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| #endif /* __SYSTIMER_ARMV8_M_DRV_H__ */ |