blob: 29a8b94a4fa9a5d7c8d8f6dd706f0ef33ea09fcd [file] [log] [blame]
/*
* 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__ */