blob: 7257c1df054243a09cc6cb5061d3118839a5be8c [file] [log] [blame]
alexander3c798932021-03-26 21:42:19 +00001/*
2 * Copyright (c) 2021 Arm Limited. All rights reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17#include "bsp.h"
18#include "timer.h"
19
20#include <assert.h>
21#include <string.h>
22
23#if defined (ARM_NPU)
24
25#include "pmu_ethosu.h"
26
27/**
28 * @brief Initialises the PMU and enables the cycle counter.
29 **/
30static void _init_ethosu_cyclecounter(void);
31
32/**
33 * @brief Gets the difference of total NPU cycle counts.
34 * (includes active and idle)
35 * @param[in] st Pointer to time_counter value at start time.
36 * @param[in] end Pointer to time_counter value at end.
37 * @return Total NPU cycle counts difference between the arguments expressed
38 * as unsigned 64 bit integer.
39 **/
40static uint64_t bm_get_npu_total_cycle_diff(time_counter *st,
41 time_counter *end);
42
43/**
44 * @brief Gets the difference in active NPU cycle counts.
45 * @param[in] st Pointer to time_counter value at start time.
46 * @param[in] end Pointer to time_counter value at end.
47 * @return Active NPU cycle counts difference between the arguments expressed
48 * as unsigned 64 bit integer.
49 **/
50static uint64_t bm_get_npu_active_cycle_diff(time_counter *st,
51 time_counter *end);
52
53#endif /* defined (ARM_NPU) */
54
55#if defined(MPS3_PLATFORM)
56/**
57 * @brief Wrapper for getting milliseconds duration between time counters
58 * @param[in] st Pointer to time_counter value at start time.
59 * @param[in] end Pointer to time_counter value at end.
60 * @return Difference in milliseconds between given time counters.
61 **/
62static time_t bm_get_duration_ms(time_counter *st, time_counter *end);
63
64/**
65 * @brief Wrapper for getting microseconds duration between time counters
66 * @param[in] st Pointer to time_counter value at start time.
67 * @param[in] end Pointer to time_counter value at end.
68 * @return Difference in microseconds between given time counters.
69 **/
70static time_t bm_get_duration_us(time_counter *st, time_counter *end);
71#endif /* defined(MPS3_PLATFORM) */
72
73/**
74 * @brief Wrapper for resetting timer.
75 **/
76static void bm_timer_reset(void);
77
78/**
79 * @brief Wrapper for getting the current timer counter.
80 * @return Current time counter value.
81 **/
82static time_counter bm_get_time_counter(void);
83
84/**
85 * @brief Wrapper for profiler start.
86 * @return Current profiler start timer counter.
87 **/
88static time_counter bm_start_profiling(void);
89
90/**
91 * @brief Wrapper for profiler end.
92 * @return Current profiler end timer counter.
93 **/
94static time_counter bm_stop_profiling(void);
95
96/**
97 * @brief Wrapper for getting CPU cycle difference between time counters.
98 * @return CPU cycle difference between given time counters expressed
99 * as unsigned 32 bit integer.
100 **/
101static uint32_t bm_get_cpu_cycles_diff(time_counter *st, time_counter *end);
102
103/**
104 * @brief Initialiser for bare metal timer.
105 * @param[in] timer Platform timer to initialize.
106 **/
107void init_timer(platform_timer *timer)
108{
109 assert(timer);
110 memset(timer, 0, sizeof(*timer));
111
112 timer->reset = bm_timer_reset;
113 timer->get_time_counter = bm_get_time_counter;
114 timer->start_profiling = bm_start_profiling;
115 timer->stop_profiling = bm_stop_profiling;
116 timer->get_cpu_cycle_diff = bm_get_cpu_cycles_diff;
117 timer->cap.cpu_cycles = 1;
118
119#if defined (MPS3_PLATFORM)
120 timer->cap.duration_ms = 1;
121 timer->cap.duration_us = 1;
122 timer->get_duration_ms = bm_get_duration_ms;
123 timer->get_duration_us = bm_get_duration_us;
124#endif /* defined (MPS3_PLATFORM) */
125
126#if defined (ARM_NPU)
127 /* We are capable of reporting npu cycle counts. */
128 timer->cap.npu_cycles = 1;
129 timer->get_npu_total_cycle_diff = bm_get_npu_total_cycle_diff;
130 timer->get_npu_active_cycle_diff = bm_get_npu_active_cycle_diff;
131 _init_ethosu_cyclecounter();
132#endif /* defined (ARM_NPU) */
133
134 timer->reset();
135 timer->inited = 1;
136}
137
138#if defined (ARM_NPU)
139
140static void _reset_ethosu_counters(void)
141{
142 /* Reset all cycle and event counters. */
143 ETHOSU_PMU_CYCCNT_Reset();
144 ETHOSU_PMU_EVCNTR_ALL_Reset();
145}
146
147static void _init_ethosu_cyclecounter(void)
148{
149 /* Reset overflow status. */
150 ETHOSU_PMU_Set_CNTR_OVS(ETHOSU_PMU_CNT1_Msk | ETHOSU_PMU_CCNT_Msk);
151
152 /* Set the counter #0 to count idle cycles. */
153 ETHOSU_PMU_Set_EVTYPER(0, ETHOSU_PMU_NPU_IDLE);
154
155 /* Enable PMU. */
156 ETHOSU_PMU_Enable();
157
158 /* Enable counters for cycle and counter# 0. */
159 ETHOSU_PMU_CNTR_Enable(ETHOSU_PMU_CNT1_Msk | ETHOSU_PMU_CCNT_Msk);
160
161 _reset_ethosu_counters();
162}
163
164static uint64_t bm_get_npu_total_cycle_diff(time_counter *st, time_counter *end)
165{
166 return end->npu_total_ccnt - st->npu_total_ccnt;
167}
168
169static uint64_t bm_get_npu_active_cycle_diff(time_counter *st, time_counter *end)
170{
171 /* Check for overflow: The idle counter is 32 bit while the
172 total cycle count is 64 bit. */
173 const uint32_t overflow_status = ETHOSU_PMU_Get_CNTR_OVS();
174
175 if (ETHOSU_PMU_CNT1_Msk & overflow_status) {
176 printf_err("EthosU PMU idle counter overflow.\n");
177 return 0;
178 }
179
180 /* Active NPU time = total time - idle time */
181 return (bm_get_npu_total_cycle_diff(st, end) +
182 (uint64_t)(st->npu_idle_ccnt)) - (uint64_t)(end->npu_idle_ccnt);
183}
184
185#endif /* defined (ARM_NPU) */
186
187static void bm_timer_reset(void)
188{
189#if defined (ARM_NPU)
190 _init_ethosu_cyclecounter();
191#endif /* defined (ARM_NPU) */
192
193 timer_reset();
194}
195
196static time_counter bm_get_time_counter(void)
197{
198 time_counter t = {
199 .counter = get_time_counter(),
200
201#if defined (ARM_NPU)
202 .npu_idle_ccnt = ETHOSU_PMU_Get_EVCNTR(0),
203 .npu_total_ccnt = ETHOSU_PMU_Get_CCNTR()
204#endif /* defined (ARM_NPU) */
205
206 };
207
208#if defined (ARM_NPU)
209 debug("NPU total cc: %llu; NPU idle cc: %u\n",
210 t.npu_total_ccnt, t.npu_idle_ccnt);
211#endif /* defined (ARM_NPU) */
212
213 return t;
214}
215
216static time_counter bm_start_profiling(void)
217{
218 start_cycle_counter();
219 return bm_get_time_counter();
220}
221
222static time_counter bm_stop_profiling(void)
223{
224 stop_cycle_counter();
225 return bm_get_time_counter();
226}
227
228static uint32_t bm_get_cpu_cycles_diff(time_counter *st, time_counter *end)
229{
230 return get_cycle_count_diff(&(st->counter), &(end->counter));
231}
232
233#if defined(MPS3_PLATFORM)
234static time_t bm_get_duration_ms(time_counter *st, time_counter *end)
235{
236 return get_duration_milliseconds(&(st->counter), &(end->counter));
237}
238
239static time_t bm_get_duration_us(time_counter *st, time_counter *end)
240{
241 return get_duration_microseconds(&(st->counter), &(end->counter));
242}
243#endif /* defined(MPS3_PLATFORM) */