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