summaryrefslogtreecommitdiff
path: root/source/hal/source/platform/mps4/source/timer_mps4.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/hal/source/platform/mps4/source/timer_mps4.c')
-rw-r--r--source/hal/source/platform/mps4/source/timer_mps4.c230
1 files changed, 230 insertions, 0 deletions
diff --git a/source/hal/source/platform/mps4/source/timer_mps4.c b/source/hal/source/platform/mps4/source/timer_mps4.c
new file mode 100644
index 0000000..4fc27c7
--- /dev/null
+++ b/source/hal/source/platform/mps4/source/timer_mps4.c
@@ -0,0 +1,230 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2024 Arm Limited and/or its
+ * affiliates <open-source-office@arm.com>
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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.
+ */
+#include "timer_mps4.h"
+
+#include "log_macros.h"
+#include "smm_mps4.h" /* Memory map for MPS4. */
+
+static uint64_t cpu_cycle_count = 0; /* 64-bit cpu cycle counter */
+static const char* unit_cycles = "cycles";
+static const char* unit_ms = "milliseconds";
+
+/**
+ * @brief Gets the system tick triggered cycle counter for the CPU.
+ * @return 64-bit counter value.
+ **/
+static uint64_t Get_SysTick_Cycle_Count(void);
+
+/**
+ * SysTick initialisation
+ */
+static int Init_SysTick(void);
+
+/**
+ * @brief Adds one PMU counter to the counters' array
+ * @param value Value of the counter
+ * @param name Name for the given counter
+ * @param unit Unit for the "value"
+ * @param counters Pointer to the counter struct - the one to be populated.
+ * @return true if successfully added, false otherwise
+ */
+static bool add_pmu_counter(
+ uint64_t value,
+ const char* name,
+ const char* unit,
+ pmu_counters* counters);
+
+/**
+ * @brief Gets the evaluated millisecond timestamp from the given MPS4 counter struct.
+ * @param mps4_counters Pointer to the MPS4 counters.
+ * @return microseconds timestamp as 32 bit unsigned integer.
+ */
+static uint32_t get_tstamp_milliseconds(mps4_pmu_counters* mps4_counters);
+
+void platform_reset_counters(void)
+{
+ MPS4_FPGAIO->CLK1HZ = 0;
+ MPS4_FPGAIO->CLK100HZ = 0;
+ MPS4_FPGAIO->COUNTER = 0;
+
+ if (0 != Init_SysTick()) {
+ printf_err("Failed to initialise system tick config\n");
+ }
+ debug("system tick config ready\n");
+
+#if defined (ARM_NPU)
+ ethosu_pmu_init();
+#endif /* defined (ARM_NPU) */
+}
+
+void platform_get_counters(pmu_counters* counters)
+{
+ counters->num_counters = 0;
+ counters->initialised = true;
+ uint32_t i = 0;
+
+#if defined (ARM_NPU)
+ ethosu_pmu_counters npu_counters = ethosu_get_pmu_counters();
+ for (i = 0; i < ETHOSU_PMU_NCOUNTERS; ++i) {
+ add_pmu_counter(
+ npu_counters.npu_evt_counters[i].counter_value,
+ npu_counters.npu_evt_counters[i].name,
+ npu_counters.npu_evt_counters[i].unit,
+ counters);
+ }
+ for (i = 0; i < ETHOSU_DERIVED_NCOUNTERS; ++i) {
+ add_pmu_counter(
+ npu_counters.npu_derived_counters[i].counter_value,
+ npu_counters.npu_derived_counters[i].name,
+ npu_counters.npu_derived_counters[i].unit,
+ counters);
+ }
+ add_pmu_counter(
+ npu_counters.npu_total_ccnt,
+ "NPU TOTAL",
+ unit_cycles,
+ counters);
+#else
+ UNUSED(i);
+#endif /* defined (ARM_NPU) */
+
+#if defined(CPU_PROFILE_ENABLED)
+ mps4_pmu_counters mps4_counters = {
+ .counter_1Hz = MPS4_FPGAIO->CLK1HZ,
+ .counter_100Hz = MPS4_FPGAIO->CLK100HZ,
+ .counter_fpga = MPS4_FPGAIO->COUNTER,
+ .counter_systick = Get_SysTick_Cycle_Count()
+ };
+
+ add_pmu_counter(
+ mps4_counters.counter_systick,
+ "CPU TOTAL",
+ unit_cycles,
+ counters);
+
+ add_pmu_counter(
+ get_tstamp_milliseconds(&mps4_counters),
+ "DURATION",
+ unit_ms,
+ counters);
+#endif /* defined(CPU_PROFILE_ENABLED) */
+
+#if !defined(CPU_PROFILE_ENABLED)
+ UNUSED(get_tstamp_milliseconds);
+ UNUSED(Get_SysTick_Cycle_Count);
+ UNUSED(unit_ms);
+#if !defined(ARM_NPU)
+ UNUSED(unit_cycles);
+ UNUSED(add_pmu_counter);
+#endif /* !defined(ARM_NPU) */
+#endif /* !defined(CPU_PROFILE_ENABLED) */
+}
+
+uint32_t get_mps4_core_clock(void)
+{
+ const uint32_t default_clock = 32000000 /* 32 MHz clock */;
+ static int warned_once = 0;
+ if (0 != MPS4_SCC->CFG_ACLK) {
+ return MPS4_SCC->CFG_ACLK;
+ }
+
+ if (!warned_once) {
+ warn("MPS4_SCC->CFG_ACLK reads 0. Assuming default clock of %" PRIu32 "\n",
+ default_clock);
+ warned_once = 1;
+ }
+ return default_clock;
+}
+
+void SysTick_Handler(void)
+{
+ /* Increment the cycle counter based on load value. */
+ cpu_cycle_count += SysTick->LOAD + 1;
+}
+
+/**
+ * Gets the current SysTick derived counter value
+ */
+static uint64_t Get_SysTick_Cycle_Count(void)
+{
+ uint32_t systick_val;
+
+ NVIC_DisableIRQ(SysTick_IRQn);
+ systick_val = SysTick->VAL & SysTick_VAL_CURRENT_Msk;
+ NVIC_EnableIRQ(SysTick_IRQn);
+
+ return cpu_cycle_count + (SysTick->LOAD - systick_val);
+}
+
+
+/**
+ * SysTick initialisation
+ */
+static int Init_SysTick(void)
+{
+ const uint32_t ticks_10ms = get_mps4_core_clock()/100 + 1;
+ int err = 0;
+
+ /* Reset CPU cycle count value. */
+ cpu_cycle_count = 0;
+
+ /* Changing configuration for sys tick => guard from being
+ * interrupted. */
+ NVIC_DisableIRQ(SysTick_IRQn);
+
+ /* SysTick init - this will enable interrupt too. */
+ err = SysTick_Config(ticks_10ms);
+
+ /* Enable interrupt again. */
+ NVIC_EnableIRQ(SysTick_IRQn);
+
+ /* Wait for SysTick to kick off */
+ while (!err && !SysTick->VAL) {
+ __NOP();
+ }
+
+ return err;
+}
+
+static bool add_pmu_counter(uint64_t value,
+ const char* name,
+ const char* unit,
+ pmu_counters* counters)
+{
+ const uint32_t idx = counters->num_counters;
+ if (idx < NUM_PMU_COUNTERS) {
+ counters->counters[idx].value = value;
+ counters->counters[idx].name = name;
+ counters->counters[idx].unit = unit;
+ ++counters->num_counters;
+
+ debug("%s: %" PRIu64 " %s\n", name, value, unit);
+ return true;
+ }
+ printf_err("Failed to add PMU counter!\n");
+ return false;
+}
+
+static uint32_t get_tstamp_milliseconds(mps4_pmu_counters* mps4_counters)
+{
+ const uint32_t divisor = get_mps4_core_clock() / 1000;
+ if (mps4_counters->counter_100Hz > 100) {
+ return (mps4_counters->counter_100Hz * 10);
+ }
+ return (mps4_counters->counter_systick/divisor);
+}