1 /*
2  * Copyright (c) 2019-2023 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 syscounter_armv8-m_cntrl_drv.h
19  *
20  * \brief Driver for Armv8-M System Counter Control, covering CNTControlBase
21  *        Frame
22  *
23  * This System Counter is a 64-bit up-counter, generating the physical
24  * count for System Timer.
25  *
26  * Main features:
27  *   - Enable/disable and Set/Get the 64-bit upcounter
28  *   - 2 scaling registers for the 2 clock sources
29  *       - These registers are used to pre-program the scaling values so
30  *          that when hardware based clock switching is implemented there is no
31  *          need to program the scaling increment value each time when clock is
32  *          switched.
33  *        - When counter scaling is enabled, ScaleVal is the value added to the
34  *          Counter Count Value for every period of the counter as determined
35  *          by 1/Frequency from the current operating frequency of the system
36  *          counter (the "counter tick").
37  *        - ScaleVal is expressed as an unsigned fixed-point number with
38  *          a 8 bit integer value and a 24-bit fractional value
39  *   - Interrupt for error detection
40  *       There are 2 possible reasons for error notification generation from
41  *       the Counter:
42  *         1. Security attribute mismatch between register access and security
43  *            attribute of the CONTROL frame
44  *         2. Address decode error within a given frame
45  *
46  */
47 
48 #ifndef __SYSCOUNTER_ARMV8_M_CNTRL_DRV_H__
49 #define __SYSCOUNTER_ARMV8_M_CNTRL_DRV_H__
50 
51 #include <stdbool.h>
52 #include <stdint.h>
53 
54 #ifdef __cplusplus
55 extern "C" {
56 #endif
57 
58 #define SYSCOUNTER_ARMV8_M_CNTRL_REGISTER_BIT_WIDTH     32u
59     /*!< Armv8-M System Counter Control registers bit width */
60 
61 #define SYSCOUNTER_ARMV8_M_DEFAULT_INIT_CNT_VAL         0u
62     /*!< Armv8-M System Counter Control default counter init value */
63 
64 /**
65  * \brief Armv8-M System Counter Control scaling value
66  */
67 struct syscounter_armv8_m_cntrl_scale_val_t {
68     uint32_t integer;              /* 8 bit */
69     uint32_t fixed_point_fraction; /* 24 bit */
70 };
71 
72 /**
73  * \brief Armv8-M System Counter Control scaling value macros *
74  *        8 bit integer and 24 bit fixed point fractional value
75  */
76 #define SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_MAX      UINT8_MAX
77 #define SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_OFF      24u
78 #define SYSCOUNTER_ARMV8_M_SCALE_VAL_FRACT_MAX    \
79             ((1u << SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_OFF) - 1u)
80 
81 /**
82  *  \brief Armv8-M System Counter Control device configuration structure
83  */
84 struct syscounter_armv8_m_cntrl_dev_cfg_t {
85     const uint32_t base;
86         /*!< Armv8-M System Counter Control device base address */
87     struct syscounter_armv8_m_cntrl_scale_val_t scale0;
88         /*!< Default clock scaling value for Clock source 0 */
89     struct syscounter_armv8_m_cntrl_scale_val_t scale1;
90         /*!< Default clock scaling value for Clock source 1 */
91 };
92 
93 /**
94  * \brief Armv8-M System Counter Control device data structure
95  */
96 struct syscounter_armv8_m_cntrl_dev_data_t {
97     bool is_initialized;
98 };
99 
100 /**
101  * \brief Armv8-M System Counter Control device structure
102  */
103 struct syscounter_armv8_m_cntrl_dev_t {
104     const struct syscounter_armv8_m_cntrl_dev_cfg_t* const cfg;
105         /*!< Armv8-M System Counter Control configuration structure */
106     struct syscounter_armv8_m_cntrl_dev_data_t* const data;
107         /*!< Armv8-M System Counter Control data structure */
108 };
109 
110 /**
111  * \brief Armv8-M System Counter Control error enumeration types
112  */
113 enum syscounter_armv8_m_cntrl_error_t {
114     SYSCOUNTER_ARMV8_M_ERR_NONE         = 0u,
115     SYSCOUNTER_ARMV8_M_ERR_INVALID      = 1u,
116     SYSCOUNTER_ARMV8_M_ERR_INVALID_ARG  = 2u
117 };
118 
119 /**
120  * \brief Armv8-M System Counter Control scaling number for each clock sources
121  */
122 enum syscounter_armv8_m_cntrl_scale_nr_t {
123     SYSCOUNTER_ARMV8_M_SCALE_NR_0         = 0u,
124       /*!< Scaling for \ref SYSCOUNTER_ARMV8_M_SELCLK_CLK0 */
125     SYSCOUNTER_ARMV8_M_SCALE_NR_1         = 1u
126       /*!< Scaling for \ref SYSCOUNTER_ARMV8_M_SELCLK_CLK1 */
127 };
128 
129 /**
130  * \brief Clock select values
131  */
132 enum syscounter_armv8_m_cntrl_selclk_t {
133     SYSCOUNTER_ARMV8_M_SELCLK_CLK_INVALID0  = 0u,
134         /*!< Clock select invalid value */
135     SYSCOUNTER_ARMV8_M_SELCLK_CLK0          = 1u,
136         /*!< Clock select clock source 0 */
137     SYSCOUNTER_ARMV8_M_SELCLK_CLK1          = 2u,
138         /*!< Clock select clock source 1 */
139     SYSCOUNTER_ARMV8_M_SELCLK_CLK_INVALID1  = 3u
140         /*!< Clock select invalid value */
141 };
142 
143 /**
144  * \brief Override counter enable condition for writing to CNTSCR registers
145  *
146  */
147 enum syscounter_armv8_m_cntrl_cntscr_ovr_t {
148     SYSCOUNTER_ARMV8_M_CNTSCR_IF_DISABLED   = 0u,
149     /*!< Scaling registers can be written only when counter is disabled */
150     SYSCOUNTER_ARMV8_M_CNTSCR_ALWAYS        = 1u
151     /*!< CNTSCR can be written regardless of counter enabled or disabled */
152 };
153 
154 /**
155  * \brief Initializes counter to a known default state, which is:
156  *          - counter is enabled, so starts counting
157  *          - interrupt is disabled
158  *          - counter reset to default reset value
159  *              \ref SYSCOUNTER_ARMV8_M_DEFAULT_INIT_CNT_VAL
160  *          - scaling is disabled
161  *          - scaling registers are set to the set values:
162  *              \ref struct syscounter_armv8_m_cntrl_dev_cfg_t
163  *        Init should be called prior to any other process and
164  *        it's the caller's responsibility to follow proper call order.
165  *        More than one call results fall through.
166  *
167  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
168  *
169  * \return Error status \ref enum syscounter_armv8_m_cntrl_error_t
170  *
171  * \note This function doesn't check if dev is NULL.
172  */
173 enum syscounter_armv8_m_cntrl_error_t syscounter_armv8_m_cntrl_init(
174         struct syscounter_armv8_m_cntrl_dev_t* dev);
175 
176 /**
177  * \brief Uninitializes counter to a known default state, which is:
178  *          - counter is disabled, so stops counting
179  *          - interrupt is disabled
180  *          - counter reset to default reset value
181  *              \ref SYSCOUNTER_ARMV8_M_DEFAULT_INIT_CNT_VAL
182  *          - scaling is disabled
183  *        Init should be called prior to any other process and
184  *        it's the caller's responsibility to follow proper call order.
185  *
186  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
187  *
188  * \note This function doesn't check if dev is NULL.
189  */
190 void syscounter_armv8_m_cntrl_uninit(
191         struct syscounter_armv8_m_cntrl_dev_t* dev);
192 
193 /**
194  * \brief Enables the counter, so counter starts counting
195  *
196  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
197  *
198  * \note This function doesn't check if dev is NULL.
199  */
200 void syscounter_armv8_m_cntrl_enable_counter(
201         struct syscounter_armv8_m_cntrl_dev_t* dev);
202 
203 /**
204  * \brief Disables the counter, so counter stops counting
205  *
206  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
207  *
208  * \note This function doesn't check if dev is NULL.
209  */
210 void syscounter_armv8_m_cntrl_disable_counter(
211         struct syscounter_armv8_m_cntrl_dev_t* dev);
212 
213 /**
214  * \brief Polls counter enable status
215  *
216  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
217  *
218  * \return true if enabled, false otherwise
219  *
220  * \note This function doesn't check if dev is NULL.
221  */
222 bool syscounter_armv8_m_cntrl_is_counter_enabled(
223         struct syscounter_armv8_m_cntrl_dev_t* dev);
224 
225 /**
226  * \brief Enables Halt-On-Debug feature
227  *
228  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
229  *
230  * \note This function doesn't check if dev is NULL.
231  */
232 void syscounter_armv8_m_cntrl_enable_halt_on_debug(
233         struct syscounter_armv8_m_cntrl_dev_t* dev);
234 
235 /**
236  * \brief Disables Halt-On-Debug feature
237  *
238  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
239  *
240  * \note This function doesn't check if dev is NULL.
241  */
242 void syscounter_armv8_m_cntrl_disable_halt_on_debug(
243         struct syscounter_armv8_m_cntrl_dev_t* dev);
244 
245 /**
246  * \brief Polls Halt-On-Debug enablement status
247  *
248  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
249 
250  * \return true if enabled, false otherwise
251  *
252  * \note This function doesn't check if dev is NULL.
253  */
254 bool syscounter_armv8_m_cntrl_is_halt_on_debug_enabled(
255         struct syscounter_armv8_m_cntrl_dev_t* dev);
256 
257 /**
258  * \brief Enables scaling
259  *        The used scaling register is depending on the used HW clock source.
260  *
261  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
262  *
263  * \note This function doesn't check if dev is NULL.
264  */
265 void syscounter_armv8_m_cntrl_enable_scale(
266         struct syscounter_armv8_m_cntrl_dev_t* dev);
267 
268 /**
269  * \brief Disables scaling
270  *        Counter count will be incremented by default 1 for each ticks.
271  *
272  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
273  *
274  * \note This function doesn't check if dev is NULL.
275  */
276 void syscounter_armv8_m_cntrl_disable_scale(
277         struct syscounter_armv8_m_cntrl_dev_t* dev);
278 
279 /**
280  * \brief Polls scaling enablement status
281  *
282  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
283  *
284  * \return true if enabled, false otherwise
285  *
286  * \note This function doesn't check if dev is NULL.
287  */
288 bool syscounter_armv8_m_cntrl_is_scale_enabled(
289         struct syscounter_armv8_m_cntrl_dev_t* dev);
290 
291 /**
292  * \brief Enables interrupt
293  *
294  *  There are 2 possible reasons for error notification generation from
295  *  the Counter:
296  *   1. Security attribute mismatch between register access and security
297  *       attribute of the CONTROL frame
298  *   2. Address decode error within a given frame
299  *
300  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
301  *
302  * \note This function doesn't check if dev is NULL.
303  */
304 void syscounter_armv8_m_cntrl_enable_interrupt(
305         struct syscounter_armv8_m_cntrl_dev_t* dev);
306 
307 /**
308  * \brief Disables interrupt
309  *
310  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
311  *
312  * \note This function doesn't check if dev is NULL.
313  */
314 void syscounter_armv8_m_cntrl_disable_interrupt(
315         struct syscounter_armv8_m_cntrl_dev_t* dev);
316 
317 /**
318  * \brief Polls interrupt enablement status
319  *
320  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
321  *
322  * \return true if enabled, false otherwise
323  *
324  * \note This function doesn't check if dev is NULL.
325  */
326 bool syscounter_armv8_m_cntrl_is_interrupt_enabled(
327         struct syscounter_armv8_m_cntrl_dev_t* dev);
328 
329 /**
330  * \brief Enables PSLVERR output
331  *
332  *        PSLVERR output signal on APB bus dynamically generated for the
333  *        following error:
334  *          For security attribute mismatch between register access and security
335  *          attribute of the CONTROL frame
336  *
337  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
338  *
339  * \note This function doesn't check if dev is NULL.
340  */
341 void syscounter_armv8_m_cntrl_enable_pslverr(
342         struct syscounter_armv8_m_cntrl_dev_t* dev);
343 
344 /**
345  * \brief Disables PSLVERR output
346  *
347  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
348  *
349  * \note This function doesn't check if dev is NULL.
350  */
351 void syscounter_armv8_m_cntrl_disable_pslverr(
352         struct syscounter_armv8_m_cntrl_dev_t* dev);
353 
354 /**
355  * \brief Polls PSLVERR output enablement status
356  *
357  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
358  *
359  * \return true if enabled, false otherwise
360  *
361  * \note This function doesn't check if dev is NULL.
362  */
363 bool syscounter_armv8_m_cntrl_is_pslverr_enabled(
364         struct syscounter_armv8_m_cntrl_dev_t* dev);
365 
366 /**
367  * \brief Clears interrupt pending flag
368  *
369  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
370  *
371  * \note This function doesn't check if dev is NULL.
372  */
373 void syscounter_armv8_m_cntrl_clear_interrupt(
374         struct syscounter_armv8_m_cntrl_dev_t* dev);
375 
376 /**
377  * \brief Polls Halt-On-Debug status
378  *
379  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
380  *
381  * \return true if counter is halted, false otherwise
382  *
383  * \note This function doesn't check if dev is NULL.
384  */
385 bool syscounter_armv8_m_cntrl_is_counter_halted_on_debug(
386         struct syscounter_armv8_m_cntrl_dev_t* dev);
387 
388 /**
389  * \brief Read counter value
390  *
391  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
392  *
393  * \return 64 bit counter value
394  *
395  * \note This function doesn't check if dev is NULL.
396  */
397 uint64_t syscounter_armv8_m_cntrl_get_counter_value(
398         struct syscounter_armv8_m_cntrl_dev_t* dev);
399 
400 /**
401  * \brief Writes counter value
402  *
403  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
404  * \param[in] value 64 bit counter value
405  *
406  * \note This function doesn't check if dev is NULL.
407  */
408 void syscounter_armv8_m_cntrl_set_counter_value(
409         struct syscounter_armv8_m_cntrl_dev_t* dev,
410         uint64_t value);
411 
412 /**
413  * \brief Polls whether scaling is implemented
414  *
415  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
416  *
417  * \return true if implemented, false otherwise
418  *
419  * \note This function doesn't check if dev is NULL.
420  */
421 bool syscounter_armv8_m_cntrl_is_counter_scaling_implemented(
422         struct syscounter_armv8_m_cntrl_dev_t* dev);
423 
424 /**
425  * \brief Polls whether HW based clock switching is implemented
426  *
427  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
428  *
429  * \return true if implemented, false otherwise
430  *
431  * \note This function doesn't check if dev is NULL.
432  */
433 bool syscounter_armv8_m_cntrl_is_clock_switching_implemented(
434         struct syscounter_armv8_m_cntrl_dev_t* dev);
435 
436 /**
437  * \brief Reads which clock source is being used
438  *
439  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
440  *
441  * \return Clock source \ref enum syscounter_armv8_m_cntrl_selclk_t
442  *
443  * \note This function doesn't check if dev is NULL.
444  */
445 enum syscounter_armv8_m_cntrl_selclk_t
446         syscounter_armv8_m_cntrl_get_clock_source(
447         struct syscounter_armv8_m_cntrl_dev_t* dev);
448 
449 /**
450  * \brief Reads scaling register can be overriden anytime
451  *
452  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
453  *
454  * \return Override condition \ref enum syscounter_armv8_m_cntrl_cntscr_ovr_t
455  *
456  * \note This function doesn't check if dev is NULL.
457  */
458 enum syscounter_armv8_m_cntrl_cntscr_ovr_t
459         syscounter_armv8_m_cntrl_get_override_cntscr(
460         struct syscounter_armv8_m_cntrl_dev_t* dev);
461 
462 /**
463  * \brief Reads scaling register
464  *
465  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
466  * \param[in] nr Index of scaling register to read
467  *              \ref enum syscounter_armv8_m_cntrl_scale_nr_t
468  * \param[out] nr Pointer to structure to read the scale value
469  *                \ref struct syscounter_armv8_m_cntrl_scale_val_t
470  *
471  * \return Override condition \ref enum syscounter_armv8_m_cntrl_cntscr_ovr_t
472  *
473  * \note This function doesn't check if dev is NULL.
474  */
475 enum syscounter_armv8_m_cntrl_error_t
476 syscounter_armv8_m_cntrl_get_counter_scale_value(
477         struct syscounter_armv8_m_cntrl_dev_t* dev,
478         enum syscounter_armv8_m_cntrl_scale_nr_t nr,
479         struct syscounter_armv8_m_cntrl_scale_val_t *val);
480 
481 /**
482  * \brief Writes scaling register
483  *
484  * \param[in] dev Counter device struct \ref syscounter_armv8_m_cntrl_dev_t
485  * \param[in] nr Index of scaling register to write
486  *              \ref enum syscounter_armv8_m_cntrl_scale_nr_t
487  * \param[in] Scale value structure
488  *              \ref struct syscounter_armv8_m_cntrl_scale_val_t
489  *
490  * \return Error status \ref enum syscounter_armv8_m_cntrl_error_t
491  *
492  * \note This function doesn't check if dev is NULL.
493  */
494 enum syscounter_armv8_m_cntrl_error_t
495 syscounter_armv8_m_cntrl_set_counter_scale_value(
496         struct syscounter_armv8_m_cntrl_dev_t* dev,
497         enum syscounter_armv8_m_cntrl_scale_nr_t nr,
498         struct syscounter_armv8_m_cntrl_scale_val_t val);
499 
500 #ifdef __cplusplus
501 }
502 #endif
503 #endif /* __SYSCOUNTER_ARMV8_M_CNTRL_DRV_H__ */
504