1 /*
2  * Copyright (c) 2019-2021 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.c
19  *
20  * \brief Driver for Armv8-M System Timer
21  */
22 
23 #include "systimer_armv8-m_drv.h"
24 #include "systimer_armv8-m_reg_map.h"
25 
26 /** Setter bit manipulation macro */
27 #define SET_BIT(WORD, BIT_INDEX) ((WORD) |= (1u << (BIT_INDEX)))
28 /** Clearing bit manipulation macro */
29 #define CLR_BIT(WORD, BIT_INDEX) ((WORD) &= ~(1u << (BIT_INDEX)))
30 /** Getter bit manipulation macro */
31 #define GET_BIT(WORD, BIT_INDEX) (bool)(((WORD) & (1u << (BIT_INDEX))))
32 /** Getter bit-field manipulation macro */
33 #define GET_BIT_FIELD(WORD, BIT_MASK, BIT_OFFSET) \
34             ((WORD & BIT_MASK) >> BIT_OFFSET)
35 /** Bit mask for given width bit-field manipulation macro */
36 #define BITMASK(width) ((1u<<(width))-1)
37 
38 /**
39  * \brief Timer Control Register bit fields
40  */
41 #define SYSCTIMER_ARMV8M_CNTP_CTL_EN_OFF           0u
42     /*!< Timer Control Register Enable Counter bit field offset */
43 #define SYSCTIMER_ARMV8M_CNTP_CTL_IMASK_OFF        1u
44 /*!< Timer Control Register Interrupt Mask bit field offset */
45 #define SYSCTIMER_ARMV8M_CNTP_CTL_ISTATUS_OFF      2u
46 /*!< Timer Control Register Interrupt Status bit field offset */
47 
48 /**
49  * \brief Timer AutoInc Control Register bit fields
50  */
51 #define SYSCTIMER_ARMV8M_CNTP_AIVAL_CTL_EN_OFF           0u
52     /*!< Timer Control Register Enable Counter bit field offset */
53 #define SYSCTIMER_ARMV8M_CNTP_AIVAL_CTL_IRQ_CLR_OFF      1u
54 /*!< Timer Control Register Interrupt clear bit field offset */
55 
56 /**
57  * \brief Timer AutoInc Config Register bit fields
58  */
59 #define SYSCTIMER_ARMV8M_CNTP_CFG_CTL_AUTOINC_OFF        0u
60     /*!< Timer Control Register AutoInc is implemented bit field offset */
61 
62 
systimer_armv8_m_init(struct systimer_armv8_m_dev_t * dev)63 void systimer_armv8_m_init(struct systimer_armv8_m_dev_t* dev)
64 {
65     if (dev->data->is_initialized == false) {
66         systimer_armv8_m_disable_interrupt(dev);
67         systimer_armv8_m_disable_autoinc(dev);
68         systimer_armv8_m_set_counter_freq(dev, dev->cfg->default_freq_hz);
69         systimer_armv8_m_enable_timer(dev);
70         dev->data->is_initialized = true;
71     }
72 }
73 
systimer_armv8_m_uninit(struct systimer_armv8_m_dev_t * dev)74 void systimer_armv8_m_uninit(struct systimer_armv8_m_dev_t* dev)
75 {
76     if (dev->data->is_initialized == true) {
77         systimer_armv8_m_disable_interrupt(dev);
78         systimer_armv8_m_disable_autoinc(dev);
79         systimer_armv8_m_disable_timer(dev);
80         dev->data->is_initialized = false;
81     }
82 }
83 
systimer_armv8_m_get_counter_value(struct systimer_armv8_m_dev_t * dev)84 uint64_t systimer_armv8_m_get_counter_value(
85            struct systimer_armv8_m_dev_t* dev)
86 {
87     struct cnt_base_reg_map_t* p_cnt =
88             (struct cnt_base_reg_map_t*)dev->cfg->base;
89     uint32_t high = 0;
90     uint32_t low = 0;
91     uint32_t high_prev = 0;
92     uint64_t value = 0;
93 
94     /* Make sure the 64-bit read will be atomic to avoid overflow between
95      * the low and high registers read
96      */
97     high = p_cnt->cntpct_high;
98     do {
99         high_prev = high;
100         low = p_cnt->cntpct_low;
101         high = p_cnt->cntpct_high;
102     }while(high != high_prev);
103 
104     value = low | (((uint64_t)high) << SYSTIMER_ARMV8_M_REGISTER_BIT_WIDTH);
105     return value;
106 }
107 
systimer_armv8_m_set_compare_value(struct systimer_armv8_m_dev_t * dev,uint64_t value)108 void systimer_armv8_m_set_compare_value(
109         struct systimer_armv8_m_dev_t* dev,
110         uint64_t value)
111 {
112     struct cnt_base_reg_map_t* p_cnt =
113             (struct cnt_base_reg_map_t*)dev->cfg->base;
114     p_cnt->cntp_cval_low = value & UINT32_MAX;
115     p_cnt->cntp_cval_high = value >> SYSTIMER_ARMV8_M_REGISTER_BIT_WIDTH;
116 }
117 
systimer_armv8_m_get_compare_value(struct systimer_armv8_m_dev_t * dev)118 uint64_t systimer_armv8_m_get_compare_value(
119         struct systimer_armv8_m_dev_t* dev)
120 {
121     uint64_t value = 0;
122     struct cnt_base_reg_map_t* p_cnt =
123             (struct cnt_base_reg_map_t*)dev->cfg->base;
124     value = p_cnt->cntp_cval_low |
125             (((uint64_t)p_cnt->cntp_cval_high) <<
126                     SYSTIMER_ARMV8_M_REGISTER_BIT_WIDTH);
127     return value;
128 }
129 
systimer_armv8_m_set_counter_freq(struct systimer_armv8_m_dev_t * dev,uint32_t value)130 void systimer_armv8_m_set_counter_freq(struct systimer_armv8_m_dev_t* dev,
131                                        uint32_t value)
132 {
133     struct cnt_base_reg_map_t* p_cnt =
134             (struct cnt_base_reg_map_t*)dev->cfg->base;
135     p_cnt->cntfrq = value;
136 }
137 
systimer_armv8_m_get_counter_freq(struct systimer_armv8_m_dev_t * dev)138 uint32_t systimer_armv8_m_get_counter_freq(
139         struct systimer_armv8_m_dev_t* dev)
140 {
141     struct cnt_base_reg_map_t* p_cnt =
142             (struct cnt_base_reg_map_t*)dev->cfg->base;
143     return p_cnt->cntfrq;
144 }
145 
systimer_armv8_m_set_timer_value(struct systimer_armv8_m_dev_t * dev,uint32_t value)146 void systimer_armv8_m_set_timer_value(struct systimer_armv8_m_dev_t* dev,
147                                       uint32_t value)
148 {
149     struct cnt_base_reg_map_t* p_cnt =
150             (struct cnt_base_reg_map_t*)dev->cfg->base;
151     p_cnt->cntp_tval = value;
152 }
153 
systimer_armv8_m_get_timer_value(struct systimer_armv8_m_dev_t * dev)154 uint32_t systimer_armv8_m_get_timer_value(
155         struct systimer_armv8_m_dev_t* dev)
156 {
157     struct cnt_base_reg_map_t* p_cnt =
158             (struct cnt_base_reg_map_t*)dev->cfg->base;
159     return p_cnt->cntp_tval;
160 }
161 
systimer_armv8_m_enable_timer(struct systimer_armv8_m_dev_t * dev)162 void systimer_armv8_m_enable_timer(struct systimer_armv8_m_dev_t* dev)
163 {
164     struct cnt_base_reg_map_t* p_cnt =
165             (struct cnt_base_reg_map_t*)dev->cfg->base;
166     SET_BIT(p_cnt->cntp_ctl, SYSCTIMER_ARMV8M_CNTP_CTL_EN_OFF);
167 }
168 
systimer_armv8_m_disable_timer(struct systimer_armv8_m_dev_t * dev)169 void systimer_armv8_m_disable_timer(struct systimer_armv8_m_dev_t* dev)
170 {
171     struct cnt_base_reg_map_t* p_cnt =
172             (struct cnt_base_reg_map_t*)dev->cfg->base;
173     CLR_BIT(p_cnt->cntp_ctl, SYSCTIMER_ARMV8M_CNTP_CTL_EN_OFF);
174 }
175 
systimer_armv8_m_is_timer_enabled(struct systimer_armv8_m_dev_t * dev)176 bool systimer_armv8_m_is_timer_enabled(
177         struct systimer_armv8_m_dev_t* dev)
178 {
179     struct cnt_base_reg_map_t* p_cnt =
180             (struct cnt_base_reg_map_t*)dev->cfg->base;
181     return GET_BIT(p_cnt->cntp_ctl, SYSCTIMER_ARMV8M_CNTP_CTL_EN_OFF);
182 }
183 
systimer_armv8_m_enable_interrupt(struct systimer_armv8_m_dev_t * dev)184 void systimer_armv8_m_enable_interrupt(
185         struct systimer_armv8_m_dev_t* dev)
186 {
187     struct cnt_base_reg_map_t* p_cnt =
188             (struct cnt_base_reg_map_t*)dev->cfg->base;
189     /* The bit is masking interrupt, so it should be inverted. */
190     CLR_BIT(p_cnt->cntp_ctl, SYSCTIMER_ARMV8M_CNTP_CTL_IMASK_OFF);
191 }
192 
systimer_armv8_m_disable_interrupt(struct systimer_armv8_m_dev_t * dev)193 void systimer_armv8_m_disable_interrupt(
194         struct systimer_armv8_m_dev_t* dev)
195 {
196     struct cnt_base_reg_map_t* p_cnt =
197             (struct cnt_base_reg_map_t*)dev->cfg->base;
198     /* The bit is masking interrupt, so it should be inverted. */
199     SET_BIT(p_cnt->cntp_ctl, SYSCTIMER_ARMV8M_CNTP_CTL_IMASK_OFF);
200 }
201 
systimer_armv8_m_is_interrupt_enabled(struct systimer_armv8_m_dev_t * dev)202 bool systimer_armv8_m_is_interrupt_enabled(
203         struct systimer_armv8_m_dev_t* dev)
204 {
205     struct cnt_base_reg_map_t* p_cnt =
206             (struct cnt_base_reg_map_t*)dev->cfg->base;
207     /* The bit is masking interrupt, so it should be inverted. */
208     return !GET_BIT(p_cnt->cntp_ctl, SYSCTIMER_ARMV8M_CNTP_CTL_IMASK_OFF);
209 }
210 
systimer_armv8_m_is_interrupt_asserted(struct systimer_armv8_m_dev_t * dev)211 bool systimer_armv8_m_is_interrupt_asserted(
212         struct systimer_armv8_m_dev_t* dev)
213 {
214     struct cnt_base_reg_map_t* p_cnt =
215             (struct cnt_base_reg_map_t*)dev->cfg->base;
216     return GET_BIT(p_cnt->cntp_ctl, SYSCTIMER_ARMV8M_CNTP_CTL_ISTATUS_OFF);
217 }
218 
systimer_armv8_m_get_autoinc_value(struct systimer_armv8_m_dev_t * dev)219 uint64_t systimer_armv8_m_get_autoinc_value(
220         struct systimer_armv8_m_dev_t* dev)
221 {
222     uint64_t value = 0;
223     struct cnt_base_reg_map_t* p_cnt =
224             (struct cnt_base_reg_map_t*)dev->cfg->base;
225     value = p_cnt->cntp_aival_low |
226             (((uint64_t)p_cnt->cntp_aival_high) <<
227              SYSTIMER_ARMV8_M_REGISTER_BIT_WIDTH);
228     return value;
229 }
230 
systimer_armv8_m_set_autoinc_reload(struct systimer_armv8_m_dev_t * dev,uint32_t value)231 void systimer_armv8_m_set_autoinc_reload(
232         struct systimer_armv8_m_dev_t* dev,
233         uint32_t value)
234 {
235     struct cnt_base_reg_map_t* p_cnt =
236             (struct cnt_base_reg_map_t*)dev->cfg->base;
237     p_cnt->cntp_aival_reload = value;
238 }
239 
systimer_armv8_m_get_autoinc_reload(struct systimer_armv8_m_dev_t * dev)240 uint32_t systimer_armv8_m_get_autoinc_reload(
241         struct systimer_armv8_m_dev_t* dev)
242 {
243     struct cnt_base_reg_map_t* p_cnt =
244             (struct cnt_base_reg_map_t*)dev->cfg->base;
245     return p_cnt->cntp_aival_reload;
246 }
247 
systimer_armv8_m_enable_autoinc(struct systimer_armv8_m_dev_t * dev)248 void systimer_armv8_m_enable_autoinc(struct systimer_armv8_m_dev_t* dev)
249 {
250     struct cnt_base_reg_map_t* p_cnt =
251             (struct cnt_base_reg_map_t*)dev->cfg->base;
252     SET_BIT(p_cnt->cntp_aival_ctl, SYSCTIMER_ARMV8M_CNTP_AIVAL_CTL_EN_OFF);
253 }
254 
systimer_armv8_m_disable_autoinc(struct systimer_armv8_m_dev_t * dev)255 void systimer_armv8_m_disable_autoinc(struct systimer_armv8_m_dev_t* dev)
256 {
257     struct cnt_base_reg_map_t* p_cnt =
258             (struct cnt_base_reg_map_t*)dev->cfg->base;
259     CLR_BIT(p_cnt->cntp_aival_ctl, SYSCTIMER_ARMV8M_CNTP_AIVAL_CTL_EN_OFF);
260 }
261 
systimer_armv8_m_is_autoinc_enabled(struct systimer_armv8_m_dev_t * dev)262 bool systimer_armv8_m_is_autoinc_enabled(
263         struct systimer_armv8_m_dev_t* dev)
264 {
265     struct cnt_base_reg_map_t* p_cnt =
266             (struct cnt_base_reg_map_t*)dev->cfg->base;
267     return GET_BIT(p_cnt->cntp_aival_ctl,
268                    SYSCTIMER_ARMV8M_CNTP_AIVAL_CTL_EN_OFF);
269 }
270 
systimer_armv8_m_clear_autoinc_interrupt(struct systimer_armv8_m_dev_t * dev)271 void systimer_armv8_m_clear_autoinc_interrupt(
272         struct systimer_armv8_m_dev_t* dev)
273 {
274     struct cnt_base_reg_map_t* p_cnt =
275             (struct cnt_base_reg_map_t*)dev->cfg->base;
276     CLR_BIT(p_cnt->cntp_aival_ctl, SYSCTIMER_ARMV8M_CNTP_AIVAL_CTL_IRQ_CLR_OFF);
277 }
278 
systimer_armv8_m_is_autoinc_implemented(struct systimer_armv8_m_dev_t * dev)279 bool systimer_armv8_m_is_autoinc_implemented(
280         struct systimer_armv8_m_dev_t* dev)
281 {
282     struct cnt_base_reg_map_t* p_cnt =
283             (struct cnt_base_reg_map_t*)dev->cfg->base;
284     return GET_BIT(p_cnt->cntp_cfg,
285                    SYSCTIMER_ARMV8M_CNTP_CFG_CTL_AUTOINC_OFF);
286 }
287