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