1 /*
2  * Copyright (c) 2019 Arm Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /**
18  * \file systimer_armv8-m_drv.h
19  *
20  * \brief Driver for Armv8-M System Timer
21  *
22  * This System Timer is based on the 64-bit Armv8-M System Counter,
23  * generating the physical count for System Timer.
24  *
25  * Main features:
26  *   - Disabling the timer doesn't stop counting, but it disables timer output
27  *     signal, what might be a power saving option.
28  *   - 1 interrupt signal, can be triggered by the 2 modes below
29  *      Modes:
30  *          1. Normal mode
31  *          For clearing the interrupt generated by normal mode, the Timer
32  *          should be disabled.
33  *              Views
34  *                  1.1. 64-bit up-counting Compare view
35  *                       As soon as the physical up-counter reaches the set
36  *                       compare value, the interrupt status will be asserted.
37  *                       \ref systimer_armv8_m_set_compare_value
38  *                       \ref systimer_armv8_m_get_compare_value
39 
40  *                  1.2. 32-bit down-counting Timer view
41  *                       As soon as the down-counter timer reaches zero,
42  *                       the interrupt status will be asserted.
43  *                       Setting the down-counter timer value, sets the compare
44  *                       register by
45  *                         compare register = current counter + timer value
46  *                       \ref systimer_armv8_m_set_timer_value
47  *                       \ref systimer_armv8_m_get_timer_value
48  *
49  *          2. Auto-Increment mode
50  *              - The auto-increment feature allows generation of Timer
51  *                interrupt at regular intervals without the need for
52  *                reprogramming the Timer after each interrupt and re-enabling
53  *                the timer logic.
54  *              - Auto-increment is working as a 64-bit up-counter, which is set
55  *                by the 32-bit reload register.
56  *              - If auto-increment mode is enabled, none of the normal modes'
57  *                views can assert interrupt. *
58  *              \ref systimer_armv8_m_get_autoinc_value
59  *              \ref systimer_armv8_m_set_autoinc_reload
60  *              \ref systimer_armv8_m_enable_autoinc
61  *              \ref systimer_armv8_m_disable_autoinc
62  *              \ref systimer_armv8_m_is_autoinc_enabled
63  *              \ref systimer_armv8_m_clear_autoinc_interrupt
64  *              \ref systimer_armv8_m_is_autoinc_implemented
65  *
66  */
67 
68 #ifndef __SYSTIMER_ARMV8_M_DRV_H__
69 #define __SYSTIMER_ARMV8_M_DRV_H__
70 
71 #include <stdbool.h>
72 #include <stdint.h>
73 
74 #ifdef __cplusplus
75 extern "C" {
76 #endif
77 
78 #define SYSTIMER_ARMV8_M_REGISTER_BIT_WIDTH          32u
79     /*!< Armv8-M System Timer registers bit width */
80 
81 /**
82  *  \brief Armv8-M System Timer device configuration structure
83  */
84 struct systimer_armv8_m_dev_cfg_t {
85     const uint32_t base;
86         /*!< Armv8-M System Timer device base address */
87     uint32_t default_freq_hz;
88         /*!< Default reported frequency in Hz */
89 };
90 
91 /**
92  * \brief Armv8-M System Timer device data structure
93  */
94 struct systimer_armv8_m_dev_data_t {
95     bool is_initialized;
96 };
97 
98 /**
99  * \brief Armv8-M System Timer device structure
100  */
101 struct systimer_armv8_m_dev_t {
102     const struct systimer_armv8_m_dev_cfg_t* const cfg;
103         /*!< Armv8-M System Timer configuration structure */
104     struct systimer_armv8_m_dev_data_t* const data;
105         /*!< Armv8-M System Timer data structure */
106 };
107 
108 /**
109  * \brief Initializes timer to a known default state, which is:
110  *          - timer is enabled
111  *          - interrupt is disabled
112  *          - auto-increment is disabled
113  *          - reported timer frequency is set to default
114  *        Init should be called prior to any other process and
115  *        it's the caller's responsibility to follow proper call order.
116  *        More than one call results fall through.
117  *
118  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
119  *
120  * \note This function doesn't check if dev is NULL.
121  */
122 void systimer_armv8_m_init(struct systimer_armv8_m_dev_t* dev);
123 
124 /**
125  * \brief Uninitializes timer to a known default state, which is:
126  *          - timer is disabled
127  *          - interrupt is disabled
128  *          - auto-increment is disabled
129  *        Init should be called prior to any other process and
130  *        it's the caller's responsibility to follow proper call order.
131  *        More than one call results fall through.
132  *
133  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
134  *
135  * \note This function doesn't check if dev is NULL.
136  */
137 void systimer_armv8_m_uninit(struct systimer_armv8_m_dev_t* dev);
138 
139 /**
140  * \brief Reads 64-bit physical counter value
141  *
142  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
143  *
144  * \return 64-bit counter value
145  *
146  * \note This function doesn't check if dev is NULL.
147  */
148 uint64_t systimer_armv8_m_get_counter_value(
149            struct systimer_armv8_m_dev_t* dev);
150 
151 /**
152  * \brief Sets 64-bit compare value
153  *        As soon as the physical up-counter reaches this value, the interrupt
154  *        condition will be asserted \ref systimer_armv8_m_is_interrupt_asserted
155  *
156  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
157  * \param[in] value 64-bit compare value
158  *
159  * \note This function doesn't check if dev is NULL.
160  */
161 void systimer_armv8_m_set_compare_value(
162         struct systimer_armv8_m_dev_t* dev,
163         uint64_t value);
164 
165 /**
166  * \brief Reads 64-bit compare value
167  *
168  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
169  *
170  * \return 64-bit compare value
171  *
172  * \note This function doesn't check if dev is NULL.
173  */
174 uint64_t systimer_armv8_m_get_compare_value(
175         struct systimer_armv8_m_dev_t* dev);
176 
177 /**
178  * \brief Sets frequency register in Hz
179  *        Hardware does not interpret the value of the register, so it's only
180  *        for software can discover the frequency of the system counter.
181  *
182  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
183  * \param[in] value frequency in Hz
184  *
185  * \note This function doesn't check if dev is NULL.
186  */
187 void systimer_armv8_m_set_counter_freq(
188         struct systimer_armv8_m_dev_t* dev,
189         uint32_t value);
190 
191 /**
192  * \brief Reads frequency register in Hz
193  *
194  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
195  *
196  * \return frequency in Hz
197  *
198  * \note This function doesn't check if dev is NULL.
199  */
200 uint32_t systimer_armv8_m_get_counter_freq(
201         struct systimer_armv8_m_dev_t* dev);
202 
203 /**
204  * \brief Sets 32-bit down-counter timer value
205  *        'Down-counter timer set' automatically sets the compare register by
206  *        compare register = current counter + this timer value
207  *
208  *        As soon as the timer value reaches zero, the interrupt condition will
209  *        be asserted \ref systimer_armv8_m_is_interrupt_asserted.
210  *        Reaching zero doesn't stop the timer.
211  *
212  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
213  * \param[in] value 32-bit timer value
214  *
215  * \note This function doesn't check if dev is NULL.
216  */
217 void systimer_armv8_m_set_timer_value(struct systimer_armv8_m_dev_t* dev,
218                                       uint32_t value);
219 
220 /**
221  * \brief Reads down-counter timer value
222  *
223  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
224  *
225  * \return 32-bit timer value
226  *
227  * \note This function doesn't check if dev is NULL.
228  */
229 uint32_t systimer_armv8_m_get_timer_value(
230         struct systimer_armv8_m_dev_t* dev);
231 
232 /**
233  * \brief Enables timer
234  *        Enables timer output signal and interrupt status assertion
235  *        \ref systimer_armv8_m_is_interrupt_asserted
236  *
237  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
238  *
239  * \note This function doesn't check if dev is NULL.
240  */
241 void systimer_armv8_m_enable_timer(struct systimer_armv8_m_dev_t* dev);
242 
243 /**
244  * \brief Disables timer
245  *        Disables timer output signal. Interrupt status will be unknown
246  *        \ref systimer_armv8_m_is_interrupt_asserted
247  *
248  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
249  *
250  * \note This function doesn't check if dev is NULL.
251  */
252 void systimer_armv8_m_disable_timer(struct systimer_armv8_m_dev_t* dev);
253 
254 /**
255  * \brief Polls timer enable status
256  *
257  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
258  *
259  * \return true if enabled, false otherwise
260  *
261  * \note This function doesn't check if dev is NULL.
262  */
263 bool systimer_armv8_m_is_timer_enabled(
264         struct systimer_armv8_m_dev_t* dev);
265 
266 /**
267  * \brief Enables timer interrupt
268  *
269  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
270  *
271  * \note This function doesn't check if dev is NULL.
272  */
273 void systimer_armv8_m_enable_interrupt(
274         struct systimer_armv8_m_dev_t* dev);
275 
276 /**
277  * \brief Disables timer interrupt
278  *
279  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
280  *
281  * \note This function doesn't check if dev is NULL.
282  */
283 void systimer_armv8_m_disable_interrupt(
284         struct systimer_armv8_m_dev_t* dev);
285 
286 /**
287  * \brief Polls timer interrupt enable status
288  *
289  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
290  *
291  * \return true if enabled, false otherwise
292  *
293  * \note This function doesn't check if dev is NULL.
294  */
295 bool systimer_armv8_m_is_interrupt_enabled(
296         struct systimer_armv8_m_dev_t* dev);
297 
298 /**
299  * \brief Polls timer interrupt status
300  *        It's asserted if
301  *          1. Auto-Inc is disabled and counter reaches compare value
302  *          OR
303  *          2. Auto-Inc is enabled and counter reaches auto-inc value
304  *
305  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
306  *
307  * \return true if asserted, false otherwise
308  *
309  * \note This function doesn't check if dev is NULL.
310  */
311 bool systimer_armv8_m_is_interrupt_asserted(
312         struct systimer_armv8_m_dev_t* dev);
313 
314 /**
315  * \brief Reads auto-increment value
316  *        This value is automatically calculated by
317  *        auto-inc = current counter + auto-inc reload
318  *
319  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
320  *
321  * \return 64-bit auto-increment value
322  *
323  * \note This function doesn't check if dev is NULL.
324  */
325 uint64_t systimer_armv8_m_get_autoinc_value(
326         struct systimer_armv8_m_dev_t* dev);
327 
328 /**
329  * \brief Sets 32-bit auto-increment reload value
330  *        Auto-Inc value is automatically calculated by adding this reload value
331  *        to the current counter.
332  *        If the counter reaches auto-inc value, interrupt status is asserted
333  *        and auto-inc value is automatically set by current reload.
334  *
335  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
336  * \param[in] value 32-bit reload value
337  *
338  * \note This function doesn't check if dev is NULL.
339  */
340 void systimer_armv8_m_set_autoinc_reload(
341         struct systimer_armv8_m_dev_t* dev,
342         uint32_t value);
343 
344 /**
345  * \brief Reads auto-increment reload value
346  *
347  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
348  *
349  * \return 32-bit auto-increment reload value
350  *
351  * \note This function doesn't check if dev is NULL.
352  */
353 uint32_t systimer_armv8_m_get_autoinc_reload(
354            struct systimer_armv8_m_dev_t* dev);
355 
356 /**
357  * \brief Enables auto-increment mode
358  *
359  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
360  *
361  * \note This function doesn't check if dev is NULL.
362  */
363 void systimer_armv8_m_enable_autoinc(struct systimer_armv8_m_dev_t* dev);
364 
365 /**
366  * \brief Disables auto-increment mode
367  *
368  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
369  *
370  * \note This function doesn't check if dev is NULL.
371  */
372 void systimer_armv8_m_disable_autoinc(struct systimer_armv8_m_dev_t* dev);
373 
374 /**
375  * \brief Polls auto-increment enable status
376  *
377  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
378  *
379  * \return true if enabled, false otherwise
380  *
381  * \note This function doesn't check if dev is NULL.
382  */
383 bool systimer_armv8_m_is_autoinc_enabled(
384         struct systimer_armv8_m_dev_t* dev);
385 
386 /**
387  * \brief Clears auto-increment mode interrupt flag
388  *
389  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
390  *
391  * \note This function doesn't check if dev is NULL.
392  */
393 void systimer_armv8_m_clear_autoinc_interrupt(
394         struct systimer_armv8_m_dev_t* dev);
395 
396 /**
397  * \brief Polls auto-increment implementation status
398  *
399  * \param[in] dev Timer device struct \ref systimer_armv8_m_dev_t
400  *
401  * \return true if implemented, false otherwise
402  *
403  * \note This function doesn't check if dev is NULL.
404  */
405 bool systimer_armv8_m_is_autoinc_implemented(
406         struct systimer_armv8_m_dev_t* dev);
407 
408 #ifdef __cplusplus
409 }
410 #endif
411 #endif /* __SYSTIMER_ARMV8_M_DRV_H__ */
412