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