blob: ef31a712c7617fceb41b077c0a929446d6d0bf35 [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
Isabella Gottardi8df12f32021-04-07 17:15:31 +010053/** @brief Gets the difference in idle NPU cycle counts
54 * @param[in] st Pointer to time_counter value at start time.
55 * @param[in] end Pointer to time_counter value at end.
56 * @return Idle NPU cycle counts difference between the arguments expressed
57 * as unsigned 64 bit integer.
58 **/
59static uint64_t bm_get_npu_idle_cycle_diff(time_counter *st,
60 time_counter *end);
61
62/** @brief Gets the difference in axi0 bus reads cycle counts
63 * @param[in] st Pointer to time_counter value at start time.
64 * @param[in] end Pointer to time_counter value at end.
65 * @return NPU AXI0 read cycle counts difference between the arguments expressed
66 * as unsigned 64 bit integer.
67 **/
68static uint64_t bm_get_npu_axi0_read_cycle_diff(time_counter *st,
69 time_counter *end);
70
71/** @brief Gets the difference in axi0 bus writes cycle counts
72 * @param[in] st Pointer to time_counter value at start time.
73 * @param[in] end Pointer to time_counter value at end.
74 * @return NPU AXI0 write cycle counts difference between the arguments expressed
75 * as unsigned 64 bit integer.
76 **/
77static uint64_t bm_get_npu_axi0_write_cycle_diff(time_counter *st,
78 time_counter *end);
79
80/** @brief Gets the difference in axi1 bus reads cycle counts
81 * @param[in] st Pointer to time_counter value at start time.
82 * @param[in] end Pointer to time_counter value at end.
83 * @return NPU AXI1 read cycle counts difference between the arguments expressed
84 * as unsigned 64 bit integer.
85 **/
86static uint64_t bm_get_npu_axi1_read_cycle_diff(time_counter *st,
87 time_counter *end);
88
89/** @brief Gets the difference for 6 collected cycle counts:
90 * 1) total NPU
91 * 2) active NPU
92 * 3) idle NPU
93 * 4) axi0 read
94 * 5) axi0 write
95 * 6) axi1 read
96 * */
97static int bm_get_npu_cycle_diff(time_counter *st, time_counter *end,
98 uint64_t* pmu_counters_values, const size_t size);
99
alexander3c798932021-03-26 21:42:19 +0000100#endif /* defined (ARM_NPU) */
101
102#if defined(MPS3_PLATFORM)
103/**
104 * @brief Wrapper for getting milliseconds duration between time counters
105 * @param[in] st Pointer to time_counter value at start time.
106 * @param[in] end Pointer to time_counter value at end.
107 * @return Difference in milliseconds between given time counters.
108 **/
109static time_t bm_get_duration_ms(time_counter *st, time_counter *end);
110
111/**
112 * @brief Wrapper for getting microseconds duration between time counters
113 * @param[in] st Pointer to time_counter value at start time.
114 * @param[in] end Pointer to time_counter value at end.
115 * @return Difference in microseconds between given time counters.
116 **/
117static time_t bm_get_duration_us(time_counter *st, time_counter *end);
118#endif /* defined(MPS3_PLATFORM) */
119
120/**
121 * @brief Wrapper for resetting timer.
122 **/
123static void bm_timer_reset(void);
124
125/**
126 * @brief Wrapper for getting the current timer counter.
127 * @return Current time counter value.
128 **/
129static time_counter bm_get_time_counter(void);
130
131/**
132 * @brief Wrapper for profiler start.
133 * @return Current profiler start timer counter.
134 **/
135static time_counter bm_start_profiling(void);
136
137/**
138 * @brief Wrapper for profiler end.
139 * @return Current profiler end timer counter.
140 **/
141static time_counter bm_stop_profiling(void);
142
143/**
144 * @brief Wrapper for getting CPU cycle difference between time counters.
145 * @return CPU cycle difference between given time counters expressed
146 * as unsigned 32 bit integer.
147 **/
148static uint32_t bm_get_cpu_cycles_diff(time_counter *st, time_counter *end);
149
150/**
151 * @brief Initialiser for bare metal timer.
152 * @param[in] timer Platform timer to initialize.
153 **/
154void init_timer(platform_timer *timer)
155{
156 assert(timer);
157 memset(timer, 0, sizeof(*timer));
158
159 timer->reset = bm_timer_reset;
160 timer->get_time_counter = bm_get_time_counter;
161 timer->start_profiling = bm_start_profiling;
162 timer->stop_profiling = bm_stop_profiling;
163 timer->get_cpu_cycle_diff = bm_get_cpu_cycles_diff;
164 timer->cap.cpu_cycles = 1;
165
166#if defined (MPS3_PLATFORM)
167 timer->cap.duration_ms = 1;
168 timer->cap.duration_us = 1;
169 timer->get_duration_ms = bm_get_duration_ms;
170 timer->get_duration_us = bm_get_duration_us;
171#endif /* defined (MPS3_PLATFORM) */
172
173#if defined (ARM_NPU)
174 /* We are capable of reporting npu cycle counts. */
175 timer->cap.npu_cycles = 1;
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100176 timer->get_npu_cycles_diff = bm_get_npu_cycle_diff;
alexander3c798932021-03-26 21:42:19 +0000177 _init_ethosu_cyclecounter();
178#endif /* defined (ARM_NPU) */
179
180 timer->reset();
181 timer->inited = 1;
182}
183
184#if defined (ARM_NPU)
185
186static void _reset_ethosu_counters(void)
187{
188 /* Reset all cycle and event counters. */
189 ETHOSU_PMU_CYCCNT_Reset();
190 ETHOSU_PMU_EVCNTR_ALL_Reset();
191}
192
193static void _init_ethosu_cyclecounter(void)
194{
195 /* Reset overflow status. */
196 ETHOSU_PMU_Set_CNTR_OVS(ETHOSU_PMU_CNT1_Msk | ETHOSU_PMU_CCNT_Msk);
197
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100198 /* We can retrieve only 4 PMU counters: */
alexander3c798932021-03-26 21:42:19 +0000199 ETHOSU_PMU_Set_EVTYPER(0, ETHOSU_PMU_NPU_IDLE);
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100200 ETHOSU_PMU_Set_EVTYPER(1, ETHOSU_PMU_AXI0_RD_DATA_BEAT_RECEIVED);
201 ETHOSU_PMU_Set_EVTYPER(2, ETHOSU_PMU_AXI0_WR_DATA_BEAT_WRITTEN);
202 ETHOSU_PMU_Set_EVTYPER(3, ETHOSU_PMU_AXI1_RD_DATA_BEAT_RECEIVED);
alexander3c798932021-03-26 21:42:19 +0000203
204 /* Enable PMU. */
205 ETHOSU_PMU_Enable();
206
207 /* Enable counters for cycle and counter# 0. */
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100208 ETHOSU_PMU_CNTR_Enable(ETHOSU_PMU_CNT1_Msk | ETHOSU_PMU_CNT2_Msk | ETHOSU_PMU_CNT3_Msk | ETHOSU_PMU_CNT4_Msk| ETHOSU_PMU_CCNT_Msk);
alexander3c798932021-03-26 21:42:19 +0000209 _reset_ethosu_counters();
210}
211
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100212static int bm_get_npu_cycle_diff(time_counter *st, time_counter *end,
213 uint64_t* pmu_counters_values, const size_t size)
214{
215 if (size == 6) {
216 pmu_counters_values[0] = bm_get_npu_total_cycle_diff(st, end);
217 pmu_counters_values[1] = bm_get_npu_active_cycle_diff(st, end);
218 pmu_counters_values[2] = bm_get_npu_idle_cycle_diff(st, end);
219 pmu_counters_values[3] = bm_get_npu_axi0_read_cycle_diff(st, end);
220 pmu_counters_values[4] = bm_get_npu_axi0_write_cycle_diff(st, end);
221 pmu_counters_values[5] = bm_get_npu_axi1_read_cycle_diff(st, end);
222 return 0;
223 } else {
224 return 1;
225 }
226}
227
alexander3c798932021-03-26 21:42:19 +0000228static uint64_t bm_get_npu_total_cycle_diff(time_counter *st, time_counter *end)
229{
230 return end->npu_total_ccnt - st->npu_total_ccnt;
231}
232
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100233static uint32_t counter_overflow(uint32_t pmu_counter_mask)
alexander3c798932021-03-26 21:42:19 +0000234{
235 /* Check for overflow: The idle counter is 32 bit while the
236 total cycle count is 64 bit. */
237 const uint32_t overflow_status = ETHOSU_PMU_Get_CNTR_OVS();
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100238 return pmu_counter_mask & overflow_status;
239}
alexander3c798932021-03-26 21:42:19 +0000240
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100241static uint64_t bm_get_npu_idle_cycle_diff(time_counter *st, time_counter *end)
242{
243 if (counter_overflow(ETHOSU_PMU_CNT1_Msk)) {
alexander3c798932021-03-26 21:42:19 +0000244 printf_err("EthosU PMU idle counter overflow.\n");
245 return 0;
246 }
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100247 return (uint64_t)(end->npu_idle_ccnt - st->npu_idle_ccnt);
248}
alexander3c798932021-03-26 21:42:19 +0000249
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100250static uint64_t bm_get_npu_active_cycle_diff(time_counter *st, time_counter *end)
251{
alexander3c798932021-03-26 21:42:19 +0000252 /* Active NPU time = total time - idle time */
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100253 return bm_get_npu_total_cycle_diff(st, end) - bm_get_npu_idle_cycle_diff(st, end);
254}
255
256static uint64_t bm_get_npu_axi0_read_cycle_diff(time_counter *st, time_counter *end)
257{
258 if (counter_overflow(ETHOSU_PMU_CNT2_Msk)) {
259 printf_err("EthosU PMU axi0 read counter overflow.\n");
260 return 0;
261 }
262 return (uint64_t)(end->npu_axi0_read_ccnt - st->npu_axi0_read_ccnt);
263}
264
265static uint64_t bm_get_npu_axi0_write_cycle_diff(time_counter *st, time_counter *end)
266{
267 if (counter_overflow(ETHOSU_PMU_CNT3_Msk)) {
268 printf_err("EthosU PMU axi0 write counter overflow.\n");
269 return 0;
270 }
271 return (uint64_t)(end->npu_axi0_write_ccnt - st->npu_axi0_write_ccnt);
272}
273
274static uint64_t bm_get_npu_axi1_read_cycle_diff(time_counter *st, time_counter *end)
275{
276 if (counter_overflow(ETHOSU_PMU_CNT4_Msk)) {
277 printf_err("EthosU PMU axi1 read counter overflow.\n");
278 return 0;
279 }
280 return (uint64_t)(end->npu_axi1_read_ccnt - st->npu_axi1_read_ccnt);
alexander3c798932021-03-26 21:42:19 +0000281}
282
283#endif /* defined (ARM_NPU) */
284
285static void bm_timer_reset(void)
286{
287#if defined (ARM_NPU)
288 _init_ethosu_cyclecounter();
289#endif /* defined (ARM_NPU) */
290
291 timer_reset();
292}
293
294static time_counter bm_get_time_counter(void)
295{
296 time_counter t = {
297 .counter = get_time_counter(),
298
299#if defined (ARM_NPU)
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100300 .npu_total_ccnt = ETHOSU_PMU_Get_CCNTR(),
301 .npu_idle_ccnt = ETHOSU_PMU_Get_EVCNTR(0),
302 .npu_axi0_read_ccnt = ETHOSU_PMU_Get_EVCNTR(1),
303 .npu_axi0_write_ccnt = ETHOSU_PMU_Get_EVCNTR(2),
304 .npu_axi1_read_ccnt = ETHOSU_PMU_Get_EVCNTR(3)
alexander3c798932021-03-26 21:42:19 +0000305#endif /* defined (ARM_NPU) */
306
307 };
308
309#if defined (ARM_NPU)
Isabella Gottardi8df12f32021-04-07 17:15:31 +0100310 debug("NPU total cc: %llu; NPU idle cc: %u; NPU axi0 read cc: %u; NPU axi0 write cc: %u; NPU axi1 read cc: %u\n",
311 t.npu_total_ccnt,
312 t.npu_idle_ccnt,
313 t.npu_axi0_read_ccnt,
314 t.npu_axi0_write_ccnt,
315 t.npu_axi1_read_ccnt);
alexander3c798932021-03-26 21:42:19 +0000316#endif /* defined (ARM_NPU) */
317
318 return t;
319}
320
321static time_counter bm_start_profiling(void)
322{
323 start_cycle_counter();
324 return bm_get_time_counter();
325}
326
327static time_counter bm_stop_profiling(void)
328{
329 stop_cycle_counter();
330 return bm_get_time_counter();
331}
332
333static uint32_t bm_get_cpu_cycles_diff(time_counter *st, time_counter *end)
334{
335 return get_cycle_count_diff(&(st->counter), &(end->counter));
336}
337
338#if defined(MPS3_PLATFORM)
339static time_t bm_get_duration_ms(time_counter *st, time_counter *end)
340{
341 return get_duration_milliseconds(&(st->counter), &(end->counter));
342}
343
344static time_t bm_get_duration_us(time_counter *st, time_counter *end)
345{
346 return get_duration_microseconds(&(st->counter), &(end->counter));
347}
348#endif /* defined(MPS3_PLATFORM) */