/* * 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 #include #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__ */