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