blob: 24d0680cab1a8bfd5e3647afb2de8277cb229860 [file] [log] [blame]
Jonny Svärda830f172021-06-07 16:57:00 +02001/*
2 * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
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#include "ethosu55_interface.h"
19
20#include "ethosu_common.h"
21#include "ethosu_config.h"
22#include "ethosu_device.h"
23
24#include <assert.h>
25#include <stddef.h>
26#include <stdio.h>
27
28#define BASEP_OFFSET 4
29#define REG_OFFSET 4
30#define BYTES_1KB 1024
31
32#define ADDRESS_BITS 48
33#define ADDRESS_MASK ((1ull << ADDRESS_BITS) - 1)
34
35enum ethosu_error_codes ethosu_dev_init(struct ethosu_device *dev,
36 const void *base_address,
37 uint32_t secure_enable,
38 uint32_t privilege_enable)
39{
40 dev->base_address = (volatile uintptr_t)base_address;
41 dev->secure = secure_enable;
42 dev->privileged = privilege_enable;
43
44 ethosu_dev_save_pmu_config(dev);
45
46 return ETHOSU_SUCCESS;
47}
48
49enum ethosu_error_codes ethosu_dev_get_id(struct ethosu_device *dev, struct ethosu_id *id)
50{
51 struct id_r _id;
52
53 _id.word = ethosu_dev_read_reg(dev, NPU_REG_ID);
54
55 id->version_status = _id.version_status;
56 id->version_minor = _id.version_minor;
57 id->version_major = _id.version_major;
58 id->product_major = _id.product_major;
59 id->arch_patch_rev = _id.arch_patch_rev;
60 id->arch_minor_rev = _id.arch_minor_rev;
61 id->arch_major_rev = _id.arch_major_rev;
62
63 return ETHOSU_SUCCESS;
64}
65
66enum ethosu_error_codes ethosu_dev_get_config(struct ethosu_device *dev, struct ethosu_config *config)
67{
68 struct config_r cfg = {.word = 0};
69
70 cfg.word = ethosu_dev_read_reg(dev, NPU_REG_CONFIG);
71
72 config->macs_per_cc = cfg.macs_per_cc;
73 config->cmd_stream_version = cfg.cmd_stream_version;
74 config->shram_size = cfg.shram_size;
75 config->custom_dma = cfg.custom_dma;
76
77 return ETHOSU_SUCCESS;
78}
79
80enum ethosu_error_codes ethosu_dev_run_command_stream(struct ethosu_device *dev,
81 const uint8_t *cmd_stream_ptr,
82 uint32_t cms_length,
83 const uint64_t *base_addr,
84 int num_base_addr)
85{
86 assert(num_base_addr <= ETHOSU_BASEP_INDEXES);
87
88 uint64_t qbase = (uintptr_t)cmd_stream_ptr + BASE_POINTER_OFFSET;
89 assert(qbase <= ADDRESS_MASK);
90 LOG_DEBUG("QBASE=0x%016llx, QSIZE=%u, base_pointer_offset=0x%08x\n", qbase, cms_length, BASE_POINTER_OFFSET);
91
92 ethosu_dev_write_reg(dev, NPU_REG_QBASE0, qbase & 0xffffffff);
93 ethosu_dev_write_reg(dev, NPU_REG_QBASE1, qbase >> 32);
94 ethosu_dev_write_reg(dev, NPU_REG_QSIZE, cms_length);
95
96 for (int i = 0; i < num_base_addr; i++)
97 {
98 uint64_t addr = base_addr[i] + BASE_POINTER_OFFSET;
99 assert(addr <= ADDRESS_MASK);
100 LOG_DEBUG("BASEP%d=0x%016llx\n", i, addr);
101 ethosu_dev_write_reg(dev, NPU_REG_BASEP0 + (2 * i) * BASEP_OFFSET, addr & 0xffffffff);
102 ethosu_dev_write_reg(dev, NPU_REG_BASEP0 + (2 * i + 1) * BASEP_OFFSET, addr >> 32);
103 }
104
105 return ethosu_dev_set_command_run(dev);
106}
107
108enum ethosu_error_codes ethosu_dev_is_irq_raised(struct ethosu_device *dev, uint8_t *irq_raised)
109{
110 struct status_r status;
111
112 status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
113
114 if (status.irq_raised == 1)
115 {
116 *irq_raised = 1;
117 }
118 else
119 {
120 *irq_raised = 0;
121 }
122
123 return ETHOSU_SUCCESS;
124}
125
126enum ethosu_error_codes ethosu_dev_clear_irq_status(struct ethosu_device *dev)
127{
128 struct cmd_r oldcmd;
129 struct cmd_r cmd;
130
131 oldcmd.word = ethosu_dev_read_reg(dev, NPU_REG_CMD);
132
133 cmd.word = 0;
134 cmd.clear_irq = 1;
135 cmd.clock_q_enable = oldcmd.clock_q_enable;
136 cmd.power_q_enable = oldcmd.power_q_enable;
137 ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
138 LOG_DEBUG("CMD=0x%08x\n", cmd.word);
139
140 return ETHOSU_SUCCESS;
141}
142
143enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev)
144{
145 enum ethosu_error_codes return_code = ETHOSU_SUCCESS;
146 struct reset_r reset;
147 struct prot_r prot;
148
149 reset.word = 0;
150 reset.pending_CPL = dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER;
151 reset.pending_CSL = dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE;
152
153 // Reset and set security level
154 LOG_INFO("Soft reset NPU\n");
155 ethosu_dev_write_reg(dev, NPU_REG_RESET, reset.word);
156
157 // Wait for reset to complete
158 return_code = ethosu_dev_wait_for_reset(dev);
159 if (return_code != ETHOSU_SUCCESS)
160 {
161 LOG_ERR("Soft reset timed out\n");
162 return return_code;
163 }
164
165 // Verify that NPU has switched security state and privilege level
166 prot.word = ethosu_dev_read_reg(dev, NPU_REG_PROT);
167 if (prot.active_CPL != reset.pending_CPL || prot.active_CSL != reset.pending_CSL)
168 {
169 LOG_ERR("Failed to switch security state and privilege level\n");
170 // Register access not permitted
171 return ETHOSU_GENERIC_FAILURE;
172 }
173
174 // Save the prot register
175 dev->proto = prot.word;
176
177 // Soft reset will clear the PMU configuration and counters. The shadow PMU counters
178 // are cleared by saving the PMU counters to ram, which will read back zeros.
179 // The PMU configuration will be restored in the invoke function after power save
180 // has been disabled.
181 ethosu_dev_save_pmu_counters(dev);
182
183 return return_code;
184}
185
186enum ethosu_error_codes ethosu_dev_wait_for_reset(struct ethosu_device *dev)
187{
188 struct status_r status;
189
190 // Wait until reset status indicates that reset has been completed
191 for (int i = 0; i < 100000; i++)
192 {
193 status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
194 if (0 == status.reset_status)
195 {
196 break;
197 }
198 }
199
200 if (1 == status.reset_status)
201 {
202 return ETHOSU_GENERIC_FAILURE;
203 }
204
205 return ETHOSU_SUCCESS;
206}
207
208enum ethosu_error_codes ethosu_dev_read_apb_reg(struct ethosu_device *dev,
209 uint32_t start_address,
210 uint16_t num_reg,
211 uint32_t *reg)
212{
213 uint32_t address = start_address;
214
215 assert((start_address + num_reg) < ID_REGISTERS_SIZE);
216
217 for (int i = 0; i < num_reg; i++)
218 {
219 reg[i] = ethosu_dev_read_reg(dev, address);
220 address += REG_OFFSET;
221 }
222
223 return ETHOSU_SUCCESS;
224}
225
226enum ethosu_error_codes ethosu_dev_set_qconfig(struct ethosu_device *dev, enum ethosu_memory_type memory_type)
227{
228 if (memory_type > ETHOSU_AXI1_OUTSTANDING_COUNTER3)
229 {
230 return ETHOSU_INVALID_PARAM;
231 }
232 ethosu_dev_write_reg(dev, NPU_REG_QCONFIG, memory_type);
233 LOG_DEBUG("QCONFIG=0x%08x\n", memory_type);
234
235 return ETHOSU_SUCCESS;
236}
237
238enum ethosu_error_codes ethosu_dev_set_regioncfg(struct ethosu_device *dev,
239 uint8_t region,
240 enum ethosu_memory_type memory_type)
241{
242 struct regioncfg_r regioncfg;
243
244 if (region > 7)
245 {
246 return ETHOSU_INVALID_PARAM;
247 }
248
249 regioncfg.word = ethosu_dev_read_reg(dev, NPU_REG_REGIONCFG);
250 regioncfg.word &= ~(0x3 << (2 * region));
251 regioncfg.word |= (memory_type & 0x3) << (2 * region);
252 ethosu_dev_write_reg(dev, NPU_REG_REGIONCFG, regioncfg.word);
253 LOG_DEBUG("REGIONCFG%u=0x%08x\n", region, regioncfg.word);
254
255 return ETHOSU_SUCCESS;
256}
257
258enum ethosu_error_codes ethosu_dev_set_axi_limit0(struct ethosu_device *dev,
259 enum ethosu_axi_limit_beats max_beats,
260 enum ethosu_axi_limit_mem_type memtype,
261 uint8_t max_reads,
262 uint8_t max_writes)
263{
264 struct axi_limit0_r axi_limit0;
265
266 axi_limit0.word = 0;
267 axi_limit0.max_beats = max_beats;
268 axi_limit0.memtype = memtype;
269 axi_limit0.max_outstanding_read_m1 = max_reads - 1;
270 axi_limit0.max_outstanding_write_m1 = max_writes - 1;
271
272 ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT0, axi_limit0.word);
273 LOG_DEBUG("AXI_LIMIT0=0x%08x\n", axi_limit0.word);
274
275 return ETHOSU_SUCCESS;
276}
277
278enum ethosu_error_codes ethosu_dev_set_axi_limit1(struct ethosu_device *dev,
279 enum ethosu_axi_limit_beats max_beats,
280 enum ethosu_axi_limit_mem_type memtype,
281 uint8_t max_reads,
282 uint8_t max_writes)
283{
284 struct axi_limit1_r axi_limit1;
285
286 axi_limit1.word = 0;
287 axi_limit1.max_beats = max_beats;
288 axi_limit1.memtype = memtype;
289 axi_limit1.max_outstanding_read_m1 = max_reads - 1;
290 axi_limit1.max_outstanding_write_m1 = max_writes - 1;
291
292 ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT1, axi_limit1.word);
293 LOG_DEBUG("AXI_LIMIT1=0x%08x\n", axi_limit1.word);
294
295 return ETHOSU_SUCCESS;
296}
297
298enum ethosu_error_codes ethosu_dev_set_axi_limit2(struct ethosu_device *dev,
299 enum ethosu_axi_limit_beats max_beats,
300 enum ethosu_axi_limit_mem_type memtype,
301 uint8_t max_reads,
302 uint8_t max_writes)
303{
304 struct axi_limit2_r axi_limit2;
305
306 axi_limit2.word = 0;
307 axi_limit2.max_beats = max_beats;
308 axi_limit2.memtype = memtype;
309 axi_limit2.max_outstanding_read_m1 = max_reads - 1;
310 axi_limit2.max_outstanding_write_m1 = max_writes - 1;
311
312 ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT2, axi_limit2.word);
313 LOG_DEBUG("AXI_LIMIT2=0x%08x\n", axi_limit2.word);
314
315 return ETHOSU_SUCCESS;
316}
317
318enum ethosu_error_codes ethosu_dev_set_axi_limit3(struct ethosu_device *dev,
319 enum ethosu_axi_limit_beats max_beats,
320 enum ethosu_axi_limit_mem_type memtype,
321 uint8_t max_reads,
322 uint8_t max_writes)
323{
324 struct axi_limit3_r axi_limit3;
325
326 axi_limit3.word = 0;
327 axi_limit3.max_beats = max_beats;
328 axi_limit3.memtype = memtype;
329 axi_limit3.max_outstanding_read_m1 = max_reads - 1;
330 axi_limit3.max_outstanding_write_m1 = max_writes - 1;
331
332 ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT3, axi_limit3.word);
333 LOG_DEBUG("AXI_LIMIT3=0x%08x\n", axi_limit3.word);
334
335 return ETHOSU_SUCCESS;
336}
337
338enum ethosu_error_codes ethosu_dev_get_revision(struct ethosu_device *dev, uint32_t *revision)
339{
340 *revision = ethosu_dev_read_reg(dev, NPU_REG_REVISION);
341
342 return ETHOSU_SUCCESS;
343}
344
345uint32_t ethosu_dev_get_qread(struct ethosu_device *dev)
346{
347 return ethosu_dev_read_reg(dev, NPU_REG_QREAD);
348}
349
350uint32_t ethosu_dev_get_status(struct ethosu_device *dev)
351{
352 return ethosu_dev_read_reg(dev, NPU_REG_STATUS);
353}
354
355enum ethosu_error_codes ethosu_dev_get_status_mask(struct ethosu_device *dev, uint16_t *status_mask)
356{
357 struct status_r status;
358
359 status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
360 *status_mask = status.word & 0xFFFF;
361
362 return ETHOSU_SUCCESS;
363}
364
365enum ethosu_error_codes ethosu_dev_get_irq_history_mask(struct ethosu_device *dev, uint16_t *irq_history_mask)
366{
367 struct status_r status;
368
369 status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
370 *irq_history_mask = status.irq_history_mask;
371
372 return ETHOSU_SUCCESS;
373}
374
375enum ethosu_error_codes ethosu_dev_clear_irq_history_mask(struct ethosu_device *dev, uint16_t irq_history_clear_mask)
376{
377 struct cmd_r oldcmd;
378 struct cmd_r cmd;
379
380 oldcmd.word = ethosu_dev_read_reg(dev, NPU_REG_CMD);
381
382 cmd.word = 0;
383 cmd.clock_q_enable = oldcmd.clock_q_enable;
384 cmd.power_q_enable = oldcmd.power_q_enable;
385 cmd.clear_irq_history = irq_history_clear_mask;
386
387 ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
388 LOG_DEBUG("CMD=0x%08x\n", cmd.word);
389
390 return ETHOSU_SUCCESS;
391}
392
393enum ethosu_error_codes ethosu_dev_set_command_run(struct ethosu_device *dev)
394{
395 struct cmd_r oldcmd;
396 struct cmd_r cmd;
397
398 oldcmd.word = ethosu_dev_read_reg(dev, NPU_REG_CMD);
399
400 cmd.word = 0;
401 cmd.transition_to_running_state = 1;
402 cmd.clock_q_enable = oldcmd.clock_q_enable;
403 cmd.power_q_enable = oldcmd.power_q_enable;
404
405 ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
406 LOG_DEBUG("CMD=0x%08x\n", cmd.word);
407
408 return ETHOSU_SUCCESS;
409}
410
411enum ethosu_error_codes ethosu_dev_get_shram_data(struct ethosu_device *dev, int section, uint32_t *shram_p)
412{
413 int i = 0;
414 uint32_t address = NPU_REG_SHARED_BUFFER0;
415
416 ethosu_dev_write_reg(dev, NPU_REG_DEBUG_ADDRESS, section * BYTES_1KB);
417
418 while (address <= NPU_REG_SHARED_BUFFER255)
419 {
420 shram_p[i] = ethosu_dev_read_reg(dev, address);
421 address += REG_OFFSET;
422 i++;
423 }
424
425 return ETHOSU_SUCCESS;
426}
427
428enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev,
429 enum ethosu_clock_q_request clock_q,
430 enum ethosu_power_q_request power_q)
431{
432 struct cmd_r cmd;
433
434 cmd.word = 0;
435 cmd.clock_q_enable = clock_q;
436 cmd.power_q_enable = power_q;
437 ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
438 LOG_DEBUG("CMD=0x%08x\n", cmd.word);
439
440 return ETHOSU_SUCCESS;
441}
442
443uint32_t ethosu_dev_read_reg(struct ethosu_device *dev, uint32_t address)
444{
445 assert(dev->base_address != 0);
446 assert(address % 4 == 0);
447
448 volatile uint32_t *reg = (volatile uint32_t *)(dev->base_address + address);
449 return *reg;
450}
451
452void ethosu_dev_write_reg(struct ethosu_device *dev, uint32_t address, uint32_t value)
453{
454 assert(dev->base_address != 0);
455 assert(address % 4 == 0);
456
457 volatile uint32_t *reg = (volatile uint32_t *)(dev->base_address + address);
458 *reg = value;
459}
460
461void ethosu_dev_write_reg_shadow(struct ethosu_device *dev, uint32_t address, uint32_t value, uint32_t *shadow)
462{
463 ethosu_dev_write_reg(dev, address, value);
464 *shadow = ethosu_dev_read_reg(dev, address);
465}
466
467enum ethosu_error_codes ethosu_dev_save_pmu_config(struct ethosu_device *dev)
468{
469 // Save the PMU control register
470 dev->pmcr = ethosu_dev_read_reg(dev, NPU_REG_PMCR);
471
472 // Save IRQ control
473 dev->pmint = ethosu_dev_read_reg(dev, NPU_REG_PMINTSET);
474
475 // Save the enabled events mask
476 dev->pmcnten = ethosu_dev_read_reg(dev, NPU_REG_PMCNTENSET);
477
478 // Save start and stop event
479 dev->pmccntr_cfg = ethosu_dev_read_reg(dev, NPU_REG_PMCCNTR_CFG);
480
481 // Save the event settings and counters
482 for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
483 {
484 dev->pmu_evtypr[i] = ethosu_dev_read_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t));
485 }
486
487 return ETHOSU_SUCCESS;
488}
489
490enum ethosu_error_codes ethosu_dev_restore_pmu_config(struct ethosu_device *dev)
491{
492 // Restore PMU control register
493 ethosu_dev_write_reg(dev, NPU_REG_PMCR, dev->pmcr);
494
495 // Restore IRQ control
496 ethosu_dev_write_reg(dev, NPU_REG_PMINTSET, dev->pmint);
497
498 // Restore enabled event mask
499 ethosu_dev_write_reg(dev, NPU_REG_PMCNTENSET, dev->pmcnten);
500
501 // Restore start and stop event
502 ethosu_dev_write_reg(dev, NPU_REG_PMCCNTR_CFG, dev->pmccntr_cfg);
503
504 // Save the event settings and counters
505 for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
506 {
507 ethosu_dev_write_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t), dev->pmu_evtypr[i]);
508 }
509
510 return ETHOSU_SUCCESS;
511}
512
513enum ethosu_error_codes ethosu_dev_save_pmu_counters(struct ethosu_device *dev)
514{
515 // Save the cycle counter
516 dev->pmccntr[0] = ethosu_dev_read_reg(dev, NPU_REG_PMCCNTR_LO);
517 dev->pmccntr[1] = ethosu_dev_read_reg(dev, NPU_REG_PMCCNTR_HI);
518
519 // Save the event settings and counters
520 for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
521 {
522 dev->pmu_evcntr[i] = ethosu_dev_read_reg(dev, NPU_REG_PMEVCNTR0 + i * sizeof(uint32_t));
523 }
524
525 return ETHOSU_SUCCESS;
526}
527
528bool ethosu_dev_prot_has_changed(struct ethosu_device *dev)
529{
530 if (dev->proto != ethosu_dev_read_reg(dev, NPU_REG_PROT))
531 {
532 return true;
533 }
534
535 return false;
536}
537
538bool ethosu_dev_status_has_error(struct ethosu_device *dev)
539{
540 bool status_error = false;
541 struct status_r status;
542
543 status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
544 status_error = ((1 == status.bus_status) || (1 == status.cmd_parse_error) || (1 == status.wd_fault) ||
545 (1 == status.ecc_fault));
546
547 return status_error;
548}