aboutsummaryrefslogtreecommitdiff
path: root/platform/ext/target/mps3/fvp_sse300/native_drivers/syscounter_armv8-m_cntrl_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/ext/target/mps3/fvp_sse300/native_drivers/syscounter_armv8-m_cntrl_drv.c')
-rw-r--r--platform/ext/target/mps3/fvp_sse300/native_drivers/syscounter_armv8-m_cntrl_drv.c485
1 files changed, 485 insertions, 0 deletions
diff --git a/platform/ext/target/mps3/fvp_sse300/native_drivers/syscounter_armv8-m_cntrl_drv.c b/platform/ext/target/mps3/fvp_sse300/native_drivers/syscounter_armv8-m_cntrl_drv.c
new file mode 100644
index 000000000..832bb0292
--- /dev/null
+++ b/platform/ext/target/mps3/fvp_sse300/native_drivers/syscounter_armv8-m_cntrl_drv.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright (c) 2019 Arm Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file syscounter_armv8-m_cntrl_drv.c
+ *
+ * \brief Driver for Armv8-M System Counter Control, covering CNTControlBase
+ * Frame
+ *
+ * This System Counter is a 64-bit up-counter, generating the physical
+ * count for System Timer.
+ *
+ * Main features:
+ * - Enabled/disable and Set/Get the 64-bit upcounter
+ * - 2 scaling register for the 2 clock sources
+ * - These registers are used to pre-program the scaling values so
+ * that when hardware based clock switching is implemented there is no
+ * need to program the scaling increment value each time when clock is
+ * switched.
+ * - When counter scaling is enabled, ScaleVal is the amount added to the
+ * Counter Count Value for every period of the counter as determined
+ * by 1/Frequency from the current operating frequency of the system
+ * counter (the “counter tick”).
+ * - ScaleVal is expressed as an unsigned fixed-point number with
+ * a 8 bit integer value and a 24-bit fractional value
+ * - Interrupt for error detection
+ * There are 2 possible reasons for error notification generation from
+ * the Counter:
+ * 1. Security attribute mismatch between register access and security
+ * attribute of the CONTROL frame
+ * 2. Address decode error within a given frame
+ *
+ */
+
+#include "syscounter_armv8-m_cntrl_drv.h"
+
+/** Setter bit manipulation macro */
+#define SET_BIT(WORD, BIT_INDEX) ((WORD) |= (1U << (BIT_INDEX)))
+/** Clearing bit manipulation macro */
+#define CLR_BIT(WORD, BIT_INDEX) ((WORD) &= ~(1U << (BIT_INDEX)))
+/** Getter bit manipulation macro */
+#define GET_BIT(WORD, BIT_INDEX) (bool)(((WORD) & (1U << (BIT_INDEX))))
+/** Clear-and-Set bit manipulation macro */
+#define ASSIGN_BIT(WORD, BIT_INDEX, VALUE) \
+ (WORD = ((WORD & ~(1U << (BIT_INDEX))) | (VALUE << (BIT_INDEX))))
+/** Getter bit-field manipulation macro */
+#define GET_BIT_FIELD(WORD, BIT_MASK, BIT_OFFSET) \
+ ((WORD & BIT_MASK) >> BIT_OFFSET)
+/** Bit mask for given width bit-field manipulation macro */
+#define BITMASK(width) ((1u<<(width))-1)
+
+/**
+ * \brief CNTControlBase Register map structure
+ */
+struct cnt_control_base_reg_map_t {
+ volatile uint32_t cntcr;
+ /*!< Offset: 0x000 (R/W) Counter Control Register */
+ volatile const uint32_t cntsr;
+ /*!< Offset: 0x004 (RO) Counter Status Register */
+ volatile uint32_t cntcv_low;
+ /*!< Offset: 0x008 (R/W) Counter Count Value [31:0] Register */
+ volatile uint32_t cntcv_high;
+ /*!< Offset: 0x00C (R/W) Counter Count Value [63:32] Register */
+ volatile uint32_t cntscr;
+ /*!< Offset: 0x010 (R/W) Counter Scale Register
+ * Aliased with CNTSCR0, meaning that either addresses of CNTSCR and
+ * CNTSCR0 will physically access a single register
+ */
+ volatile const uint32_t reserved0[2];
+ /*!< Offset: 0x014-0x018 Reserved (RAZWI) */
+ volatile const uint32_t cntid;
+ /*!< Offset: 0x01C (RO) Counter ID Register */
+ volatile const uint32_t reserved1[40];
+ /*!< Offset: 0x020-0x0BC Reserved (RAZWI) */
+ volatile const uint32_t reserved2[4];
+ /*!< Offset: 0x0C0-0x0CC Reserved (RAZWI) */
+ volatile uint32_t cntscr0;
+ /*!< Offset: 0x0D0 (R/W) Counter Scale Register 0 */
+ volatile uint32_t cntscr1;
+ /*!< Offset: 0x0D4 (R/W) Counter Scale Register 1 */
+ volatile const uint32_t reserved3[958];
+ /*!< Offset: 0x0D8-0xFCC Reserved (RAZWI) */
+ volatile const uint32_t cntpidr4;
+ /*!< Offset: 0xFD0 (RO) Peripheral ID Register */
+ volatile const uint32_t reserved4[3];
+ /*!< Offset: 0xFD4-0xFDC Reserved (RAZWI) */
+ volatile const uint32_t cntpidr0;
+ /*!< Offset: 0xFE0 (RO) Peripheral ID Register */
+ volatile const uint32_t cntpidr1;
+ /*!< Offset: 0xFE4 (RO) Peripheral ID Register */
+ volatile const uint32_t cntpidr2;
+ /*!< Offset: 0xFE8 (RO) Peripheral ID Register */
+ volatile const uint32_t cntpidr3;
+ /*!< Offset: 0xFEC (RO) Peripheral ID Register */
+ volatile const uint32_t cntcidr0;
+ /*!< Offset: 0xFF0 (RO) Component ID Register */
+ volatile const uint32_t cntcidr1;
+ /*!< Offset: 0xFF4 (RO) Component ID Register */
+ volatile const uint32_t cntcidr2;
+ /*!< Offset: 0xFF8 (RO) Component ID Register */
+ volatile const uint32_t cntcidr3;
+ /*!< Offset: 0xFFC (RO) Component ID Register */
+};
+
+/**
+ * \brief Counter Control Register bit fields
+ */
+#define SYSCOUNTER_ARMV8M_CNTCR_EN_OFF 0u
+ /*!< Counter Control Register Enable Counter bit field offset */
+#define SYSCOUNTER_ARMV8M_CNTCR_HDBG_OFF 1u
+ /*!< Counter Control Register Halt On Debug bit field offset */
+#define SYSCOUNTER_ARMV8M_CNTCR_SCEN_OFF 2u
+ /*!< Counter Control Register Scale enable bit field offset */
+#define SYSCOUNTER_ARMV8M_CNTCR_INTRMASK_OFF 3u
+ /*!< Counter Control Register Interrupt mask bit field offset */
+#define SYSCOUNTER_ARMV8M_CNTCR_PSLVERRDIS_OFF 4u
+ /*!< Counter Control Register PSLVERR disable bit field offset */
+#define SYSCOUNTER_ARMV8M_CNTCR_INTRCLR_OFF 5u
+ /*!< Counter Control Register Interrupt Clear bit field offset */
+
+/**
+ * \brief Counter Status Register bit fields
+ */
+#define SYSCOUNTER_ARMV8M_CNTSR_DBGH_OFF 1u
+ /*!< Counter Status Register Halt-on-Debug bit field offset */
+
+/**
+ * \brief Counter ID Register bit fields
+ */
+#define SYSCOUNTER_ARMV8M_CNTID_CNTSC_OFF 0u
+ /*!< Counter ID Register Counter Scaling is implemented bit field offset */
+#define SYSCOUNTER_ARMV8M_CNTID_CNTCS_OFF 16u
+ /*!< Counter ID Register Clock switching is implemented bit field offset */
+
+/*! Counter ID Register Clock source */
+#define SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_OFF 17u
+#define SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_WIDTH 2u
+#define SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_MASK \
+ (BITMASK(SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_WIDTH) \
+ << SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_OFF)
+
+#define SYSCOUNTER_ARMV8M_CNTID_CNTSCR_OVR_OFF 19u
+ /*!< Counter ID Register Override counter enable condition for
+ * writing to CNTSCR registers bit offset
+ */
+
+enum syscounter_armv8_m_cntrl_error_t syscounter_armv8_m_cntrl_init(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ enum syscounter_armv8_m_cntrl_error_t result = SYSCOUNTER_ARMV8_M_ERR_NONE;
+
+ if (dev->data->is_initialized == false) {
+ syscounter_armv8_m_cntrl_disable_counter(dev);
+ if (syscounter_armv8_m_cntrl_is_counter_scaling_implemented(dev)) {
+ result = syscounter_armv8_m_cntrl_set_counter_scale_value(
+ dev, SYSCOUNTER_ARMV8_M_SCALE_NR_0, dev->cfg->scale0);
+ if (result != SYSCOUNTER_ARMV8_M_ERR_NONE) {
+ return result;
+ }
+ result = syscounter_armv8_m_cntrl_set_counter_scale_value(
+ dev, SYSCOUNTER_ARMV8_M_SCALE_NR_1, dev->cfg->scale1);
+ if (result != SYSCOUNTER_ARMV8_M_ERR_NONE) {
+ return result;
+ }
+ }
+ syscounter_armv8_m_cntrl_set_counter_value(dev,
+ SYSCOUNTER_ARMV8_M_DEFAULT_INIT_CNT_VAL);
+ syscounter_armv8_m_cntrl_disable_interrupt(dev);
+ syscounter_armv8_m_cntrl_disable_scale(dev);
+
+ syscounter_armv8_m_cntrl_enable_counter(dev);
+ dev->data->is_initialized = true;
+ }
+ return SYSCOUNTER_ARMV8_M_ERR_NONE;
+}
+
+void syscounter_armv8_m_cntrl_uninit(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ if (dev->data->is_initialized == true) {
+ syscounter_armv8_m_cntrl_disable_counter(dev);
+ syscounter_armv8_m_cntrl_disable_interrupt(dev);
+ syscounter_armv8_m_cntrl_set_counter_value(dev,
+ SYSCOUNTER_ARMV8_M_DEFAULT_INIT_CNT_VAL);
+ dev->data->is_initialized = false;
+ }
+}
+
+void syscounter_armv8_m_cntrl_enable_counter(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ SET_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_EN_OFF);
+}
+
+void syscounter_armv8_m_cntrl_disable_counter(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_EN_OFF);
+}
+
+bool syscounter_armv8_m_cntrl_is_counter_enabled(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ return GET_BIT(p_cnt->cntcr,
+ SYSCOUNTER_ARMV8M_CNTCR_EN_OFF);
+}
+
+void syscounter_armv8_m_cntrl_enable_halt_on_debug(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ SET_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_HDBG_OFF);
+}
+
+void syscounter_armv8_m_cntrl_disable_halt_on_debug(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_HDBG_OFF);
+}
+
+bool syscounter_armv8_m_cntrl_is_halt_on_debug_enabled(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ return GET_BIT(p_cnt->cntcr,
+ SYSCOUNTER_ARMV8M_CNTCR_HDBG_OFF);
+}
+
+void syscounter_armv8_m_cntrl_enable_scale(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ SET_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_SCEN_OFF);
+}
+
+void syscounter_armv8_m_cntrl_disable_scale(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_SCEN_OFF);
+}
+
+bool syscounter_armv8_m_cntrl_is_scale_enabled(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ return GET_BIT(p_cnt->cntcr,
+ SYSCOUNTER_ARMV8M_CNTCR_SCEN_OFF);
+}
+
+void syscounter_armv8_m_cntrl_enable_interrupt(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ SET_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_INTRMASK_OFF);
+}
+
+void syscounter_armv8_m_cntrl_disable_interrupt(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_INTRMASK_OFF);
+}
+
+bool syscounter_armv8_m_cntrl_is_interrupt_enabled(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ return GET_BIT(p_cnt->cntcr,
+ SYSCOUNTER_ARMV8M_CNTCR_INTRMASK_OFF);
+}
+
+void syscounter_armv8_m_cntrl_enable_pslverr(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ SET_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_PSLVERRDIS_OFF);
+}
+
+void syscounter_armv8_m_cntrl_disable_pslverr(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_PSLVERRDIS_OFF);
+}
+
+bool syscounter_armv8_m_cntrl_is_pslverr_enabled(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ return GET_BIT(p_cnt->cntcr,
+ SYSCOUNTER_ARMV8M_CNTCR_PSLVERRDIS_OFF);
+}
+
+void syscounter_armv8_m_cntrl_clear_interrupt(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ CLR_BIT(p_cnt->cntcr, SYSCOUNTER_ARMV8M_CNTCR_INTRCLR_OFF);
+}
+
+bool syscounter_armv8_m_cntrl_is_counter_halted_on_debug(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ return GET_BIT(p_cnt->cntsr,
+ SYSCOUNTER_ARMV8M_CNTSR_DBGH_OFF);
+}
+
+uint64_t syscounter_armv8_m_cntrl_get_counter_value(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ uint32_t high = 0;
+ uint32_t low = 0;
+ uint32_t high_prev = 0;
+ uint64_t value = 0;
+
+ /* Make sure the 64-bit read will be atomic to avoid overflow between
+ * the low and high registers read
+ */
+ high = p_cnt->cntcv_high;
+ do {
+ high_prev = high;
+ low = p_cnt->cntcv_low;
+ high = p_cnt->cntcv_high;
+ }while(high != high_prev);
+
+ value = low |
+ (((uint64_t)high) << SYSCOUNTER_ARMV8_M_CNTRL_REGISTER_BIT_WIDTH);
+ return value;
+}
+
+void syscounter_armv8_m_cntrl_set_counter_value(
+ struct syscounter_armv8_m_cntrl_dev_t* dev,
+ uint64_t value)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ p_cnt->cntcv_low = value & UINT32_MAX;
+ p_cnt->cntcv_high = value >> SYSCOUNTER_ARMV8_M_CNTRL_REGISTER_BIT_WIDTH;
+}
+
+bool syscounter_armv8_m_cntrl_is_counter_scaling_implemented(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ return GET_BIT(p_cnt->cntid,
+ SYSCOUNTER_ARMV8M_CNTID_CNTSC_OFF);
+}
+
+bool syscounter_armv8_m_cntrl_is_clock_switching_implemented(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ return GET_BIT(p_cnt->cntid,
+ SYSCOUNTER_ARMV8M_CNTID_CNTCS_OFF);
+}
+
+enum syscounter_armv8_m_cntrl_selclk_t
+syscounter_armv8_m_cntrl_get_clock_source(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ return (enum syscounter_armv8_m_cntrl_selclk_t)
+ GET_BIT_FIELD(p_cnt->cntid,
+ SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_MASK,
+ SYSCOUNTER_ARMV8M_CNTID_CNTSELCLK_OFF);
+}
+
+enum syscounter_armv8_m_cntrl_cntscr_ovr_t
+syscounter_armv8_m_cntrl_get_override_cntscr(
+ struct syscounter_armv8_m_cntrl_dev_t* dev)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ return (enum syscounter_armv8_m_cntrl_cntscr_ovr_t)
+ GET_BIT(p_cnt->cntid,
+ SYSCOUNTER_ARMV8M_CNTID_CNTSCR_OVR_OFF);
+}
+
+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)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+
+ switch (nr) {
+ case SYSCOUNTER_ARMV8_M_SCALE_NR_0:
+ val->integer = p_cnt->cntscr0 >> SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_OFF;
+ val->fixed_point_fraction = p_cnt->cntscr0 &
+ SYSCOUNTER_ARMV8_M_SCALE_VAL_FRACT_MAX;
+ break;
+ case SYSCOUNTER_ARMV8_M_SCALE_NR_1:
+ val->integer = p_cnt->cntscr1 >> SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_OFF;
+ val->fixed_point_fraction = p_cnt->cntscr1 &
+ SYSCOUNTER_ARMV8_M_SCALE_VAL_FRACT_MAX;
+ break;
+ default:
+ val->integer = 0;
+ val->fixed_point_fraction = 0;
+ return SYSCOUNTER_ARMV8_M_ERR_INVALID_ARG;
+ }
+
+ return SYSCOUNTER_ARMV8_M_ERR_NONE;
+}
+
+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)
+{
+ struct cnt_control_base_reg_map_t* p_cnt =
+ (struct cnt_control_base_reg_map_t*)dev->cfg->base;
+ uint32_t reg_val = 0;
+
+ if ((syscounter_armv8_m_cntrl_get_override_cntscr(dev) ==
+ SYSCOUNTER_ARMV8_M_CNTSCR_IF_DISABLED) &&
+ syscounter_armv8_m_cntrl_is_counter_enabled(dev)) {
+ return SYSCOUNTER_ARMV8_M_ERR_INVALID;
+ }
+ if (val.integer > SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_MAX ||
+ val.fixed_point_fraction > SYSCOUNTER_ARMV8_M_SCALE_VAL_FRACT_MAX) {
+ return SYSCOUNTER_ARMV8_M_ERR_INVALID_ARG;
+ }
+
+ reg_val = val.integer << SYSCOUNTER_ARMV8_M_SCALE_VAL_INT_OFF;
+ reg_val |= (val.fixed_point_fraction &
+ SYSCOUNTER_ARMV8_M_SCALE_VAL_FRACT_MAX);
+
+ switch (nr) {
+ case SYSCOUNTER_ARMV8_M_SCALE_NR_0:
+ p_cnt->cntscr0 = reg_val;
+ break;
+ case SYSCOUNTER_ARMV8_M_SCALE_NR_1:
+ p_cnt->cntscr1 = reg_val;
+ break;
+ default:
+ return SYSCOUNTER_ARMV8_M_ERR_INVALID_ARG;
+ }
+
+ return SYSCOUNTER_ARMV8_M_ERR_NONE;
+}