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 syscounter_armv8-m_cntrl_drv.c
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 * - Enabled/disable and Set/Get the 64-bit upcounter
28 * - 2 scaling register 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 amount 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 #include "syscounter_armv8-m_cntrl_drv.h"
49 #include "syscounter_armv8-m_cntrl_reg_map.h"
50
51 /** Setter bit manipulation macro */
52 #define SET_BIT(WORD, BIT_INDEX) ((WORD) |= (1U << (BIT_INDEX)))
53 /** Clearing bit manipulation macro */
54 #define CLR_BIT(WORD, BIT_INDEX) ((WORD) &= ~(1U << (BIT_INDEX)))
55 /** Getter bit manipulation macro */
56 #define GET_BIT(WORD, BIT_INDEX) (bool)(((WORD) & (1U << (BIT_INDEX))))
57 /** Clear-and-Set bit manipulation macro */
58 #define ASSIGN_BIT(WORD, BIT_INDEX, VALUE) \
59 (WORD = ((WORD & ~(1U << (BIT_INDEX))) | (VALUE << (BIT_INDEX))))
60 /** Getter bit-field manipulation macro */
61 #define GET_BIT_FIELD(WORD, BIT_MASK, BIT_OFFSET) \
62 ((WORD & BIT_MASK) >> BIT_OFFSET)
63 /** Bit mask for given width bit-field manipulation macro */
64 #define BITMASK(width) ((1u<<(width))-1)
65
66 /**
67 * \brief Counter Control Register bit fields
68 */
69 #define SYSCOUNTER_ARMV8M_CNTCR_EN_OFF 0u
70 /*!< Counter Control Register Enable Counter bit field offset */
71 #define SYSCOUNTER_ARMV8M_CNTCR_HDBG_OFF 1u
72 /*!< Counter Control Register Halt On Debug bit field offset */
73 #define SYSCOUNTER_ARMV8M_CNTCR_SCEN_OFF 2u
74 /*!< Counter Control Register Scale enable bit field offset */
75 #define SYSCOUNTER_ARMV8M_CNTCR_INTRMASK_OFF 3u
76 /*!< Counter Control Register Interrupt mask bit field offset */
77 #define SYSCOUNTER_ARMV8M_CNTCR_PSLVERRDIS_OFF 4u
78 /*!< Counter Control Register PSLVERR disable bit field offset */
79 #define SYSCOUNTER_ARMV8M_CNTCR_INTRCLR_OFF 5u
80 /*!< Counter Control Register Interrupt Clear bit field offset */
81
82 /**
83 * \brief Counter Status Register bit fields
84 */
85 #define SYSCOUNTER_ARMV8M_CNTSR_DBGH_OFF 1u
86 /*!< Counter Status Register Halt-on-Debug bit field offset */
87
88 /**
89 * \brief Counter ID Register bit fields
90 */
91 #define SYSCOUNTER_ARMV8M_CNTID_CNTSC_OFF 0u
92 /*!< Counter ID Register Counter Scaling is implemented bit field offset */
93 #define SYSCOUNTER_ARMV8M_CNTID_CNTCS_OFF 16u
94 /*!< Counter ID Register Clock switching is implemented bit field offset */
95
96 /*! Counter ID Register Clock source */
97 #define SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_OFF 17u
98 #define SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_WIDTH 2u
99 #define SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_MASK \
100 (BITMASK(SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_WIDTH) \
101 << SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_OFF)
102
103 #define SYSCOUNTER_ARMV8M_CNTID_CNTSCR_OVR_OFF 19u
104 /*!< Counter ID Register Override counter enable condition for
105 * writing to CNTSCR registers bit offset
106 */
107
syscounter_armv8_m_cntrl_init(struct syscounter_armv8_m_cntrl_dev_t * dev)108 enum syscounter_armv8_m_cntrl_error_t syscounter_armv8_m_cntrl_init(
109 struct syscounter_armv8_m_cntrl_dev_t* dev)
110 {
111 enum syscounter_armv8_m_cntrl_error_t result = SYSCOUNTER_ARMV8_M_ERR_NONE;
112
113 if (dev->data->is_initialized == false) {
114 syscounter_armv8_m_cntrl_disable_counter(dev);
115 if (syscounter_armv8_m_cntrl_is_counter_scaling_implemented(dev)) {
116 result = syscounter_armv8_m_cntrl_set_counter_scale_value(
117 dev, SYSCOUNTER_ARMV8_M_SCALE_NR_0, dev->cfg->scale0);
118 if (result != SYSCOUNTER_ARMV8_M_ERR_NONE) {
119 return result;
120 }
121 result = syscounter_armv8_m_cntrl_set_counter_scale_value(
122 dev, SYSCOUNTER_ARMV8_M_SCALE_NR_1, dev->cfg->scale1);
123 if (result != SYSCOUNTER_ARMV8_M_ERR_NONE) {
124 return result;
125 }
126 }
127 syscounter_armv8_m_cntrl_set_counter_value(dev,
128 SYSCOUNTER_ARMV8_M_DEFAULT_INIT_CNT_VAL);
129 syscounter_armv8_m_cntrl_disable_interrupt(dev);
130 syscounter_armv8_m_cntrl_disable_scale(dev);
131
132 syscounter_armv8_m_cntrl_enable_counter(dev);
133 dev->data->is_initialized = true;
134 }
135 return SYSCOUNTER_ARMV8_M_ERR_NONE;
136 }
137
syscounter_armv8_m_cntrl_uninit(struct syscounter_armv8_m_cntrl_dev_t * dev)138 void syscounter_armv8_m_cntrl_uninit(
139 struct syscounter_armv8_m_cntrl_dev_t* dev)
140 {
141 if (dev->data->is_initialized == true) {
142 syscounter_armv8_m_cntrl_disable_counter(dev);
143 syscounter_armv8_m_cntrl_disable_interrupt(dev);
144 syscounter_armv8_m_cntrl_set_counter_value(dev,
145 SYSCOUNTER_ARMV8_M_DEFAULT_INIT_CNT_VAL);
146 dev->data->is_initialized = false;
147 }
148 }
149
syscounter_armv8_m_cntrl_enable_counter(struct syscounter_armv8_m_cntrl_dev_t * dev)150 void syscounter_armv8_m_cntrl_enable_counter(
151 struct syscounter_armv8_m_cntrl_dev_t* dev)
152 {
153 struct cnt_control_base_reg_map_t* p_cnt =
154 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
155 SET_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_EN_OFF);
156 }
157
syscounter_armv8_m_cntrl_disable_counter(struct syscounter_armv8_m_cntrl_dev_t * dev)158 void syscounter_armv8_m_cntrl_disable_counter(
159 struct syscounter_armv8_m_cntrl_dev_t* dev)
160 {
161 struct cnt_control_base_reg_map_t* p_cnt =
162 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
163 CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_EN_OFF);
164 }
165
syscounter_armv8_m_cntrl_is_counter_enabled(struct syscounter_armv8_m_cntrl_dev_t * dev)166 bool syscounter_armv8_m_cntrl_is_counter_enabled(
167 struct syscounter_armv8_m_cntrl_dev_t* dev)
168 {
169 struct cnt_control_base_reg_map_t* p_cnt =
170 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
171 return GET_BIT(p_cnt->cntcr,
172 SYSCOUNTER_ARMV8M_CNTCR_EN_OFF);
173 }
174
syscounter_armv8_m_cntrl_enable_halt_on_debug(struct syscounter_armv8_m_cntrl_dev_t * dev)175 void syscounter_armv8_m_cntrl_enable_halt_on_debug(
176 struct syscounter_armv8_m_cntrl_dev_t* dev)
177 {
178 struct cnt_control_base_reg_map_t* p_cnt =
179 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
180 SET_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_HDBG_OFF);
181 }
182
syscounter_armv8_m_cntrl_disable_halt_on_debug(struct syscounter_armv8_m_cntrl_dev_t * dev)183 void syscounter_armv8_m_cntrl_disable_halt_on_debug(
184 struct syscounter_armv8_m_cntrl_dev_t* dev)
185 {
186 struct cnt_control_base_reg_map_t* p_cnt =
187 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
188 CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_HDBG_OFF);
189 }
190
syscounter_armv8_m_cntrl_is_halt_on_debug_enabled(struct syscounter_armv8_m_cntrl_dev_t * dev)191 bool syscounter_armv8_m_cntrl_is_halt_on_debug_enabled(
192 struct syscounter_armv8_m_cntrl_dev_t* dev)
193 {
194 struct cnt_control_base_reg_map_t* p_cnt =
195 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
196 return GET_BIT(p_cnt->cntcr,
197 SYSCOUNTER_ARMV8M_CNTCR_HDBG_OFF);
198 }
199
syscounter_armv8_m_cntrl_enable_scale(struct syscounter_armv8_m_cntrl_dev_t * dev)200 void syscounter_armv8_m_cntrl_enable_scale(
201 struct syscounter_armv8_m_cntrl_dev_t* dev)
202 {
203 struct cnt_control_base_reg_map_t* p_cnt =
204 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
205 SET_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_SCEN_OFF);
206 }
207
syscounter_armv8_m_cntrl_disable_scale(struct syscounter_armv8_m_cntrl_dev_t * dev)208 void syscounter_armv8_m_cntrl_disable_scale(
209 struct syscounter_armv8_m_cntrl_dev_t* dev)
210 {
211 struct cnt_control_base_reg_map_t* p_cnt =
212 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
213 CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_SCEN_OFF);
214 }
215
syscounter_armv8_m_cntrl_is_scale_enabled(struct syscounter_armv8_m_cntrl_dev_t * dev)216 bool syscounter_armv8_m_cntrl_is_scale_enabled(
217 struct syscounter_armv8_m_cntrl_dev_t* dev)
218 {
219 struct cnt_control_base_reg_map_t* p_cnt =
220 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
221 return GET_BIT(p_cnt->cntcr,
222 SYSCOUNTER_ARMV8M_CNTCR_SCEN_OFF);
223 }
224
syscounter_armv8_m_cntrl_enable_interrupt(struct syscounter_armv8_m_cntrl_dev_t * dev)225 void syscounter_armv8_m_cntrl_enable_interrupt(
226 struct syscounter_armv8_m_cntrl_dev_t* dev)
227 {
228 struct cnt_control_base_reg_map_t* p_cnt =
229 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
230 SET_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_INTRMASK_OFF);
231 }
232
syscounter_armv8_m_cntrl_disable_interrupt(struct syscounter_armv8_m_cntrl_dev_t * dev)233 void syscounter_armv8_m_cntrl_disable_interrupt(
234 struct syscounter_armv8_m_cntrl_dev_t* dev)
235 {
236 struct cnt_control_base_reg_map_t* p_cnt =
237 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
238 CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_INTRMASK_OFF);
239 }
240
syscounter_armv8_m_cntrl_is_interrupt_enabled(struct syscounter_armv8_m_cntrl_dev_t * dev)241 bool syscounter_armv8_m_cntrl_is_interrupt_enabled(
242 struct syscounter_armv8_m_cntrl_dev_t* dev)
243 {
244 struct cnt_control_base_reg_map_t* p_cnt =
245 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
246 return GET_BIT(p_cnt->cntcr,
247 SYSCOUNTER_ARMV8M_CNTCR_INTRMASK_OFF);
248 }
249
syscounter_armv8_m_cntrl_enable_pslverr(struct syscounter_armv8_m_cntrl_dev_t * dev)250 void syscounter_armv8_m_cntrl_enable_pslverr(
251 struct syscounter_armv8_m_cntrl_dev_t* dev)
252 {
253 struct cnt_control_base_reg_map_t* p_cnt =
254 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
255 SET_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_PSLVERRDIS_OFF);
256 }
257
syscounter_armv8_m_cntrl_disable_pslverr(struct syscounter_armv8_m_cntrl_dev_t * dev)258 void syscounter_armv8_m_cntrl_disable_pslverr(
259 struct syscounter_armv8_m_cntrl_dev_t* dev)
260 {
261 struct cnt_control_base_reg_map_t* p_cnt =
262 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
263 CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_PSLVERRDIS_OFF);
264 }
265
syscounter_armv8_m_cntrl_is_pslverr_enabled(struct syscounter_armv8_m_cntrl_dev_t * dev)266 bool syscounter_armv8_m_cntrl_is_pslverr_enabled(
267 struct syscounter_armv8_m_cntrl_dev_t* dev)
268 {
269 struct cnt_control_base_reg_map_t* p_cnt =
270 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
271 return GET_BIT(p_cnt->cntcr,
272 SYSCOUNTER_ARMV8M_CNTCR_PSLVERRDIS_OFF);
273 }
274
syscounter_armv8_m_cntrl_clear_interrupt(struct syscounter_armv8_m_cntrl_dev_t * dev)275 void syscounter_armv8_m_cntrl_clear_interrupt(
276 struct syscounter_armv8_m_cntrl_dev_t* dev)
277 {
278 struct cnt_control_base_reg_map_t* p_cnt =
279 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
280 CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_INTRCLR_OFF);
281 }
282
syscounter_armv8_m_cntrl_is_counter_halted_on_debug(struct syscounter_armv8_m_cntrl_dev_t * dev)283 bool syscounter_armv8_m_cntrl_is_counter_halted_on_debug(
284 struct syscounter_armv8_m_cntrl_dev_t* dev)
285 {
286 struct cnt_control_base_reg_map_t* p_cnt =
287 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
288 return GET_BIT(p_cnt->cntsr,
289 SYSCOUNTER_ARMV8M_CNTSR_DBGH_OFF);
290 }
291
syscounter_armv8_m_cntrl_get_counter_value(struct syscounter_armv8_m_cntrl_dev_t * dev)292 uint64_t syscounter_armv8_m_cntrl_get_counter_value(
293 struct syscounter_armv8_m_cntrl_dev_t* dev)
294 {
295 struct cnt_control_base_reg_map_t* p_cnt =
296 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
297 uint32_t high = 0;
298 uint32_t low = 0;
299 uint32_t high_prev = 0;
300 uint64_t value = 0;
301
302 /* Make sure the 64-bit read will be atomic to avoid overflow between
303 * the low and high registers read
304 */
305 high = p_cnt->cntcv_high;
306 do {
307 high_prev = high;
308 low = p_cnt->cntcv_low;
309 high = p_cnt->cntcv_high;
310 }while(high != high_prev);
311
312 value = low |
313 (((uint64_t)high) << SYSCOUNTER_ARMV8_M_CNTRL_REGISTER_BIT_WIDTH);
314 return value;
315 }
316
syscounter_armv8_m_cntrl_set_counter_value(struct syscounter_armv8_m_cntrl_dev_t * dev,uint64_t value)317 void syscounter_armv8_m_cntrl_set_counter_value(
318 struct syscounter_armv8_m_cntrl_dev_t* dev,
319 uint64_t value)
320 {
321 struct cnt_control_base_reg_map_t* p_cnt =
322 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
323 p_cnt->cntcv_low = value & UINT32_MAX;
324 p_cnt->cntcv_high = value >> SYSCOUNTER_ARMV8_M_CNTRL_REGISTER_BIT_WIDTH;
325 }
326
syscounter_armv8_m_cntrl_is_counter_scaling_implemented(struct syscounter_armv8_m_cntrl_dev_t * dev)327 bool syscounter_armv8_m_cntrl_is_counter_scaling_implemented(
328 struct syscounter_armv8_m_cntrl_dev_t* dev)
329 {
330 struct cnt_control_base_reg_map_t* p_cnt =
331 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
332 return GET_BIT(p_cnt->cntid,
333 SYSCOUNTER_ARMV8M_CNTID_CNTSC_OFF);
334 }
335
syscounter_armv8_m_cntrl_is_clock_switching_implemented(struct syscounter_armv8_m_cntrl_dev_t * dev)336 bool syscounter_armv8_m_cntrl_is_clock_switching_implemented(
337 struct syscounter_armv8_m_cntrl_dev_t* dev)
338 {
339 struct cnt_control_base_reg_map_t* p_cnt =
340 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
341 return GET_BIT(p_cnt->cntid,
342 SYSCOUNTER_ARMV8M_CNTID_CNTCS_OFF);
343 }
344
345 enum syscounter_armv8_m_cntrl_selclk_t
syscounter_armv8_m_cntrl_get_clock_source(struct syscounter_armv8_m_cntrl_dev_t * dev)346 syscounter_armv8_m_cntrl_get_clock_source(
347 struct syscounter_armv8_m_cntrl_dev_t* dev)
348 {
349 struct cnt_control_base_reg_map_t* p_cnt =
350 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
351 return (enum syscounter_armv8_m_cntrl_selclk_t)
352 GET_BIT_FIELD(p_cnt->cntid,
353 SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_MASK,
354 SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_OFF);
355 }
356
357 enum syscounter_armv8_m_cntrl_cntscr_ovr_t
syscounter_armv8_m_cntrl_get_override_cntscr(struct syscounter_armv8_m_cntrl_dev_t * dev)358 syscounter_armv8_m_cntrl_get_override_cntscr(
359 struct syscounter_armv8_m_cntrl_dev_t* dev)
360 {
361 struct cnt_control_base_reg_map_t* p_cnt =
362 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
363 return (enum syscounter_armv8_m_cntrl_cntscr_ovr_t)
364 GET_BIT(p_cnt->cntid,
365 SYSCOUNTER_ARMV8M_CNTID_CNTSCR_OVR_OFF);
366 }
367
368 enum syscounter_armv8_m_cntrl_error_t
syscounter_armv8_m_cntrl_get_counter_scale_value(struct syscounter_armv8_m_cntrl_dev_t * dev,enum syscounter_armv8_m_cntrl_scale_nr_t nr,struct syscounter_armv8_m_cntrl_scale_val_t * val)369 syscounter_armv8_m_cntrl_get_counter_scale_value(
370 struct syscounter_armv8_m_cntrl_dev_t* dev,
371 enum syscounter_armv8_m_cntrl_scale_nr_t nr,
372 struct syscounter_armv8_m_cntrl_scale_val_t *val)
373 {
374 struct cnt_control_base_reg_map_t* p_cnt =
375 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
376
377 switch (nr) {
378 case SYSCOUNTER_ARMV8_M_SCALE_NR_0:
379 val->integer = p_cnt->cntscr0 >> SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_OFF;
380 val->fixed_point_fraction = p_cnt->cntscr0 &
381 SYSCOUNTER_ARMV8_M_SCALE_VAL_FRACT_MAX;
382 break;
383 case SYSCOUNTER_ARMV8_M_SCALE_NR_1:
384 val->integer = p_cnt->cntscr1 >> SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_OFF;
385 val->fixed_point_fraction = p_cnt->cntscr1 &
386 SYSCOUNTER_ARMV8_M_SCALE_VAL_FRACT_MAX;
387 break;
388 default:
389 val->integer = 0;
390 val->fixed_point_fraction = 0;
391 return SYSCOUNTER_ARMV8_M_ERR_INVALID_ARG;
392 }
393
394 return SYSCOUNTER_ARMV8_M_ERR_NONE;
395 }
396
397 enum syscounter_armv8_m_cntrl_error_t
syscounter_armv8_m_cntrl_set_counter_scale_value(struct syscounter_armv8_m_cntrl_dev_t * dev,enum syscounter_armv8_m_cntrl_scale_nr_t nr,struct syscounter_armv8_m_cntrl_scale_val_t val)398 syscounter_armv8_m_cntrl_set_counter_scale_value(
399 struct syscounter_armv8_m_cntrl_dev_t* dev,
400 enum syscounter_armv8_m_cntrl_scale_nr_t nr,
401 struct syscounter_armv8_m_cntrl_scale_val_t val)
402 {
403 struct cnt_control_base_reg_map_t* p_cnt =
404 (struct cnt_control_base_reg_map_t*)dev->cfg->base;
405 uint32_t reg_val = 0;
406
407 if ((syscounter_armv8_m_cntrl_get_override_cntscr(dev) ==
408 SYSCOUNTER_ARMV8_M_CNTSCR_IF_DISABLED) &&
409 syscounter_armv8_m_cntrl_is_counter_enabled(dev)) {
410 return SYSCOUNTER_ARMV8_M_ERR_INVALID;
411 }
412 if (val.integer > SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_MAX ||
413 val.fixed_point_fraction > SYSCOUNTER_ARMV8_M_SCALE_VAL_FRACT_MAX) {
414 return SYSCOUNTER_ARMV8_M_ERR_INVALID_ARG;
415 }
416
417 reg_val = val.integer << SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_OFF;
418 reg_val |= (val.fixed_point_fraction &
419 SYSCOUNTER_ARMV8_M_SCALE_VAL_FRACT_MAX);
420
421 switch (nr) {
422 case SYSCOUNTER_ARMV8_M_SCALE_NR_0:
423 p_cnt->cntscr0 = reg_val;
424 break;
425 case SYSCOUNTER_ARMV8_M_SCALE_NR_1:
426 p_cnt->cntscr1 = reg_val;
427 break;
428 default:
429 return SYSCOUNTER_ARMV8_M_ERR_INVALID_ARG;
430 }
431
432 return SYSCOUNTER_ARMV8_M_ERR_NONE;
433 }
434