1 /*
2  * SPDX-FileCopyrightText: Copyright 2019-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
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=%" PRIu32 ", type=%d, val=%" PRIu32, 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=%" PRIu32 ", type=%d, val=%" PRIu32, 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%08" PRIx32, 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%08" PRIx32, 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%08" PRIx32, 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=%" PRIu32 ", val=%" PRIu32, 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=%" PRIu32 ", val=%" PRIu32, 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%08" PRIx32, 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%08" PRIx32, 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%08" PRIx32, 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 & (1u << 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 
ETHOSU_PMU_Get_QREAD(struct ethosu_driver * drv)289 uint32_t ETHOSU_PMU_Get_QREAD(struct ethosu_driver *drv)
290 {
291     uint32_t val = drv->dev->reg->QREAD.word;
292     LOG_DEBUG("qread=%" PRIu32, val);
293     return val;
294 }
295 
ETHOSU_PMU_Get_STATUS(struct ethosu_driver * drv)296 uint32_t ETHOSU_PMU_Get_STATUS(struct ethosu_driver *drv)
297 {
298     uint32_t val = drv->dev->reg->STATUS.word;
299     LOG_DEBUG("status=0x%" PRIx32, val);
300     return val;
301 }
302