1 /*
2 * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates <open-source-office@arm.com>
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the License); you may
6 * not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * 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, WITHOUT
13 * 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
18 /*****************************************************************************
19 * Includes
20 *****************************************************************************/
21
22 #include "ethosu_device.h"
23 #include "ethosu_driver.h"
24 #include "ethosu_interface.h"
25 #include "ethosu_log.h"
26 #include "pmu_ethosu.h"
27
28 #include <assert.h>
29 #include <inttypes.h>
30 #include <stddef.h>
31
32 /*****************************************************************************
33 * Defines
34 *****************************************************************************/
35
36 #define MASK_0_31_BITS (0xFFFFFFFF)
37 #define MASK_32_47_BITS (0xFFFF00000000)
38
39 #define COMMA ,
40 #define SEMICOLON ;
41
42 #define EVTYPE(A, name) \
43 case PMU_EVENT_##name: \
44 return ETHOSU_PMU_##name
45
46 #define EVID(A, name) (PMU_EVENT_##name)
47
48 /*****************************************************************************
49 * Variables
50 *****************************************************************************/
51
52 static const enum pmu_event eventbyid[] = {EXPAND_PMU_EVENT(EVID, COMMA)};
53
54 /*****************************************************************************
55 * Static functions
56 *****************************************************************************/
57
pmu_event_type(uint32_t id)58 static enum ethosu_pmu_event_type pmu_event_type(uint32_t id)
59 {
60 switch (id)
61 {
62 EXPAND_PMU_EVENT(EVTYPE, SEMICOLON);
63 default:
64 LOG_ERR("Unknown PMU event id: 0x%" PRIx32, id);
65 }
66
67 return ETHOSU_PMU_SENTINEL;
68 }
69
pmu_event_value(enum ethosu_pmu_event_type event)70 static uint32_t pmu_event_value(enum ethosu_pmu_event_type event)
71 {
72 int a = event;
73 if ((a < ETHOSU_PMU_SENTINEL) && (a >= ETHOSU_PMU_NO_EVENT))
74 {
75 return eventbyid[event];
76 }
77
78 return UINT32_MAX;
79 }
80
81 /*****************************************************************************
82 * Functions
83 *****************************************************************************/
84
ETHOSU_PMU_Enable(struct ethosu_driver * drv)85 void ETHOSU_PMU_Enable(struct ethosu_driver *drv)
86 {
87 LOG_DEBUG("Enable PMU");
88 struct pmcr_r pmcr = {0};
89 pmcr.cnt_en = 1;
90 ethosu_request_power(drv);
91 drv->dev.reg->PMCR.word = pmcr.word;
92 }
93
ETHOSU_PMU_Disable(struct ethosu_driver * drv)94 void ETHOSU_PMU_Disable(struct ethosu_driver *drv)
95 {
96 LOG_DEBUG("Disable PMU");
97 drv->dev.reg->PMCR.word = 0;
98 ethosu_release_power(drv);
99 }
100
ETHOSU_PMU_Get_NumEventCounters(void)101 uint32_t ETHOSU_PMU_Get_NumEventCounters(void)
102 {
103 return NPU_REG_PMEVCNTR_ARRLEN;
104 }
105
ETHOSU_PMU_Set_EVTYPER(struct ethosu_driver * drv,uint32_t num,enum ethosu_pmu_event_type type)106 void ETHOSU_PMU_Set_EVTYPER(struct ethosu_driver *drv, uint32_t num, enum ethosu_pmu_event_type type)
107 {
108 assert(num < ETHOSU_PMU_NCOUNTERS);
109 uint32_t val = pmu_event_value(type);
110 if (val == UINT32_MAX)
111 {
112 LOG_ERR("Invalid ethosu_pmu_event_type: %d", type);
113 return;
114 }
115
116 LOG_DEBUG("num=%" PRIu32 ", type=%d, val=%" PRIu32, num, type, val);
117 drv->dev.reg->PMEVTYPER[num].word = val;
118 }
119
ETHOSU_PMU_Get_EVTYPER(struct ethosu_driver * drv,uint32_t num)120 enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER(struct ethosu_driver *drv, uint32_t num)
121 {
122 assert(num < ETHOSU_PMU_NCOUNTERS);
123 uint32_t val = drv->dev.reg->PMEVTYPER[num].word;
124 enum ethosu_pmu_event_type type = pmu_event_type(val);
125 LOG_DEBUG("num=%" PRIu32 ", type=%d, val=%" PRIu32, num, type, val);
126 return type;
127 }
128
ETHOSU_PMU_CYCCNT_Reset(struct ethosu_driver * drv)129 void ETHOSU_PMU_CYCCNT_Reset(struct ethosu_driver *drv)
130 {
131 LOG_DEBUG("Reset PMU cycle counter");
132 struct pmcr_r pmcr;
133 pmcr.word = drv->dev.reg->PMCR.word;
134 pmcr.cycle_cnt_rst = 1;
135 drv->dev.reg->PMCR.word = pmcr.word;
136 }
137
ETHOSU_PMU_EVCNTR_ALL_Reset(struct ethosu_driver * drv)138 void ETHOSU_PMU_EVCNTR_ALL_Reset(struct ethosu_driver *drv)
139 {
140 LOG_DEBUG("Reset all events");
141 struct pmcr_r pmcr;
142 pmcr.word = drv->dev.reg->PMCR.word;
143 pmcr.event_cnt_rst = 1;
144 drv->dev.reg->PMCR.word = pmcr.word;
145 }
146
ETHOSU_PMU_CNTR_Enable(struct ethosu_driver * drv,uint32_t mask)147 void ETHOSU_PMU_CNTR_Enable(struct ethosu_driver *drv, uint32_t mask)
148 {
149 LOG_DEBUG("mask=0x%08" PRIx32, mask);
150 drv->dev.reg->PMCNTENSET.word = mask;
151 }
152
ETHOSU_PMU_CNTR_Disable(struct ethosu_driver * drv,uint32_t mask)153 void ETHOSU_PMU_CNTR_Disable(struct ethosu_driver *drv, uint32_t mask)
154 {
155 LOG_DEBUG("mask=0x%08" PRIx32, mask);
156 drv->dev.reg->PMCNTENCLR.word = mask;
157 }
158
ETHOSU_PMU_CNTR_Status(struct ethosu_driver * drv)159 uint32_t ETHOSU_PMU_CNTR_Status(struct ethosu_driver *drv)
160 {
161 uint32_t pmcntenset = drv->dev.reg->PMCNTENSET.word;
162 LOG_DEBUG("mask=0x%08" PRIx32, pmcntenset);
163 return pmcntenset;
164 }
165
ETHOSU_PMU_Get_CCNTR(struct ethosu_driver * drv)166 uint64_t ETHOSU_PMU_Get_CCNTR(struct ethosu_driver *drv)
167 {
168 uint32_t val_lo = drv->dev.reg->PMCCNTR.CYCLE_CNT_LO;
169 uint32_t val_hi = drv->dev.reg->PMCCNTR.CYCLE_CNT_HI;
170 uint64_t val = ((uint64_t)val_hi << 32) | val_lo;
171
172 LOG_DEBUG("val=%" PRIu64, val);
173 return val;
174 }
175
ETHOSU_PMU_Set_CCNTR(struct ethosu_driver * drv,uint64_t val)176 void ETHOSU_PMU_Set_CCNTR(struct ethosu_driver *drv, uint64_t val)
177 {
178 uint32_t active = ETHOSU_PMU_CNTR_Status(drv) & ETHOSU_PMU_CCNT_Msk;
179
180 LOG_DEBUG("val=%llu", val);
181
182 if (active)
183 {
184 ETHOSU_PMU_CNTR_Disable(drv, ETHOSU_PMU_CCNT_Msk);
185 }
186
187 drv->dev.reg->PMCCNTR.CYCLE_CNT_LO = val & MASK_0_31_BITS;
188 drv->dev.reg->PMCCNTR.CYCLE_CNT_HI = (val & MASK_32_47_BITS) >> 32;
189
190 if (active)
191 {
192 ETHOSU_PMU_CNTR_Enable(drv, ETHOSU_PMU_CCNT_Msk);
193 }
194 }
195
ETHOSU_PMU_Get_EVCNTR(struct ethosu_driver * drv,uint32_t num)196 uint32_t ETHOSU_PMU_Get_EVCNTR(struct ethosu_driver *drv, uint32_t num)
197 {
198 assert(num < ETHOSU_PMU_NCOUNTERS);
199 uint32_t val = drv->dev.reg->PMEVCNTR[num].word;
200 LOG_DEBUG("num=%" PRIu32 ", val=%" PRIu32, num, val);
201
202 return val;
203 }
204
ETHOSU_PMU_Set_EVCNTR(struct ethosu_driver * drv,uint32_t num,uint32_t val)205 void ETHOSU_PMU_Set_EVCNTR(struct ethosu_driver *drv, uint32_t num, uint32_t val)
206 {
207 assert(num < ETHOSU_PMU_NCOUNTERS);
208 LOG_DEBUG("num=%" PRIu32 ", val=%" PRIu32, num, val);
209 drv->dev.reg->PMEVCNTR[num].word = val;
210 }
211
ETHOSU_PMU_Get_CNTR_OVS(struct ethosu_driver * drv)212 uint32_t ETHOSU_PMU_Get_CNTR_OVS(struct ethosu_driver *drv)
213 {
214 LOG_DEBUG("");
215 return drv->dev.reg->PMOVSSET.word;
216 }
217
ETHOSU_PMU_Set_CNTR_OVS(struct ethosu_driver * drv,uint32_t mask)218 void ETHOSU_PMU_Set_CNTR_OVS(struct ethosu_driver *drv, uint32_t mask)
219 {
220 LOG_DEBUG("");
221 drv->dev.reg->PMOVSCLR.word = mask;
222 }
223
ETHOSU_PMU_Set_CNTR_IRQ_Enable(struct ethosu_driver * drv,uint32_t mask)224 void ETHOSU_PMU_Set_CNTR_IRQ_Enable(struct ethosu_driver *drv, uint32_t mask)
225 {
226 LOG_DEBUG("mask=0x%08" PRIx32, mask);
227 drv->dev.reg->PMINTSET.word = mask;
228 }
229
ETHOSU_PMU_Set_CNTR_IRQ_Disable(struct ethosu_driver * drv,uint32_t mask)230 void ETHOSU_PMU_Set_CNTR_IRQ_Disable(struct ethosu_driver *drv, uint32_t mask)
231 {
232 LOG_DEBUG("mask=0x%08" PRIx32, mask);
233 drv->dev.reg->PMINTCLR.word = mask;
234 }
235
ETHOSU_PMU_Get_IRQ_Enable(struct ethosu_driver * drv)236 uint32_t ETHOSU_PMU_Get_IRQ_Enable(struct ethosu_driver *drv)
237 {
238 uint32_t pmint = drv->dev.reg->PMINTSET.word;
239 LOG_DEBUG("mask=0x%08" PRIx32, pmint);
240 return pmint;
241 }
242
ETHOSU_PMU_CNTR_Increment(struct ethosu_driver * drv,uint32_t mask)243 void ETHOSU_PMU_CNTR_Increment(struct ethosu_driver *drv, uint32_t mask)
244 {
245 LOG_DEBUG("");
246 uint32_t cntrs_active = ETHOSU_PMU_CNTR_Status(drv);
247
248 // Disable counters
249 ETHOSU_PMU_CNTR_Disable(drv, mask);
250
251 // Increment cycle counter
252 if (mask & ETHOSU_PMU_CCNT_Msk)
253 {
254 uint64_t val = ETHOSU_PMU_Get_CCNTR(drv) + 1;
255 drv->dev.reg->PMCCNTR.CYCLE_CNT_LO = val & MASK_0_31_BITS;
256 drv->dev.reg->PMCCNTR.CYCLE_CNT_HI = (val & MASK_32_47_BITS) >> 32;
257 }
258
259 for (int i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
260 {
261 if (mask & (1u << i))
262 {
263 uint32_t val = ETHOSU_PMU_Get_EVCNTR(drv, i);
264 drv->dev.reg->PMEVCNTR[i].word = val + 1;
265 }
266 }
267
268 // Reenable the active counters
269 ETHOSU_PMU_CNTR_Enable(drv, cntrs_active);
270 }
271
ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(struct ethosu_driver * drv,enum ethosu_pmu_event_type start_event)272 void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(struct ethosu_driver *drv, enum ethosu_pmu_event_type start_event)
273 {
274 LOG_DEBUG("start_event=%u", start_event);
275 struct pmccntr_cfg_r cfg;
276 uint32_t val = pmu_event_value(start_event);
277 if (val == UINT32_MAX)
278 {
279 LOG_ERR("Invalid ethosu_pmu_event_type: %d", start_event);
280 return;
281 }
282
283 cfg.word = drv->dev.reg->PMCCNTR_CFG.word;
284 cfg.CYCLE_CNT_CFG_START = val;
285 drv->dev.reg->PMCCNTR_CFG.word = cfg.word;
286 }
287
ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(struct ethosu_driver * drv,enum ethosu_pmu_event_type stop_event)288 void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(struct ethosu_driver *drv, enum ethosu_pmu_event_type stop_event)
289 {
290 LOG_DEBUG("stop_event=%u", stop_event);
291 struct pmccntr_cfg_r cfg;
292 uint32_t val = pmu_event_value(stop_event);
293 if (val == UINT32_MAX)
294 {
295 LOG_ERR("Invalid ethosu_pmu_event_type: %d", stop_event);
296 return;
297 }
298
299 cfg.word = drv->dev.reg->PMCCNTR_CFG.word;
300 cfg.CYCLE_CNT_CFG_STOP = val;
301 drv->dev.reg->PMCCNTR_CFG.word = cfg.word;
302 }
303
ETHOSU_PMU_Get_QREAD(struct ethosu_driver * drv)304 uint32_t ETHOSU_PMU_Get_QREAD(struct ethosu_driver *drv)
305 {
306 uint32_t val = drv->dev.reg->QREAD.word;
307 LOG_DEBUG("qread=%" PRIu32, val);
308 return val;
309 }
310
ETHOSU_PMU_Get_STATUS(struct ethosu_driver * drv)311 uint32_t ETHOSU_PMU_Get_STATUS(struct ethosu_driver *drv)
312 {
313 uint32_t val = drv->dev.reg->STATUS.word;
314 LOG_DEBUG("status=0x%" PRIx32, val);
315 return val;
316 }
317