blob: 2be18afba02d91609e24846bc28f614140d571be [file] [log] [blame]
Kristofer Jonsson49bdee82020-04-06 13:21:21 +02001/*
Kristofer Jonsson09273d12021-03-15 08:43:08 +01002 * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
Kristofer Jonsson49bdee82020-04-06 13:21:21 +02003 *
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
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020019/******************************************************************************
20 * Includes
21 ******************************************************************************/
22
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020023#include "ethosu_driver.h"
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020024#include "ethosu_common.h"
Bhavik Pateldae5be02020-06-18 15:25:15 +020025#include "ethosu_config.h"
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020026#include "ethosu_device.h"
Per Åstrand25d78c02020-04-21 14:19:44 +020027
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020028#include <assert.h>
Per Åstrand25d78c02020-04-21 14:19:44 +020029#include <cmsis_compiler.h>
Per Åstrand14ccfee2020-09-25 10:40:20 +020030#include <inttypes.h>
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020031#include <stdbool.h>
Bhavik Patelbf7ae632020-06-11 21:00:16 +020032#include <stddef.h>
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020033#include <stdio.h>
34#include <stdlib.h>
35
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020036/******************************************************************************
37 * Defines
38 ******************************************************************************/
39
40#define MACS_PER_CYCLE_LOG2_MASK 0x000F
41#define SHRAM_SIZE_MASK 0xFF00
42#define SHRAM_SIZE_RIGHT_SHIFT 8
43#define BYTES_IN_32_BITS 4
44#define CUSTOM_OPTION_LENGTH_32_BIT_WORD 1
45#define DRIVER_ACTION_LENGTH_32_BIT_WORD 1
46#define OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD 2
47#define ETHOSU_FOURCC ('1' << 24 | 'P' << 16 | 'O' << 8 | 'C') // "Custom Operator Payload 1"
48#define APB_START_ADDR_MASK 0x0FFF
49#define APB_NUM_REG_BIT_SHIFT 12
50#define BYTES_1KB 1024
51#define PRODUCT_MAJOR_ETHOSU55 (4)
52#define MASK_16_BYTE_ALIGN (0xF)
53#define FAST_MEMORY_BASE_ADDR_INDEX 2
54
55/******************************************************************************
56 * Types
57 ******************************************************************************/
58
59// Driver actions
60enum DRIVER_ACTION_e
61{
62 RESERVED = 0,
63 OPTIMIZER_CONFIG = 1,
64 COMMAND_STREAM = 2,
65 READ_APB_REG = 3,
66 DUMP_SHRAM = 4,
67 NOP = 5,
68};
69
70// Custom data struct
71struct custom_data_s
72{
73 union
74 {
75 // Driver action data
76 struct
77 {
78 // Driver action command (valid values in DRIVER_ACTION_e)
79 uint8_t driver_action_command;
80
81 // reserved
82 uint8_t reserved;
83
84 // Driver action data
85 union
86 {
87 // DA_CMD_OPT_CFG
88 struct
89 {
90 uint16_t rel_nbr : 4;
91 uint16_t patch_nbr : 4;
92 uint16_t opt_cfg_reserved : 8;
93 };
94
95 // DA_CMD_CMSTRM
96 struct
97 {
98 uint16_t length;
99 };
100
101 // DA_CMD_READAPB
102 struct
103 {
104 uint16_t start_address : 12;
105 uint16_t nbr_reg_minus1 : 4;
106 };
107
108 uint16_t driver_action_data;
109 };
110 };
111
112 uint32_t word;
113 };
114};
115
116// optimizer config struct
117struct opt_cfg_s
118{
119 struct custom_data_s da_data;
120 union
121 {
122 struct
123 {
124 uint32_t macs_per_cc : 4;
125 uint32_t cmd_stream_version : 4;
126 uint32_t shram_size : 8;
Anton Mobergb8bcf132021-03-29 10:02:25 +0200127 uint32_t reserved0 : 11;
128 uint32_t custom_dma : 1;
129 uint32_t product : 4;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200130 };
131 uint32_t npu_cfg;
132 };
133 union
134 {
135 struct
136 {
137 uint32_t version_status : 4;
138 uint32_t version_minor : 4;
139 uint32_t version_major : 4;
140 uint32_t product_major : 4;
141 uint32_t arch_patch_rev : 4;
142 uint32_t arch_minor_rev : 8;
143 uint32_t arch_major_rev : 4;
144 };
145 uint32_t ethosu_id;
146 };
147};
148
149/******************************************************************************
Jonny Svärda830f172021-06-07 16:57:00 +0200150 * Variables
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200151 ******************************************************************************/
152
Anton Moberg61da4d32020-12-22 16:00:31 +0100153// Registered drivers linked list HEAD
154static struct ethosu_driver *registered_drivers = NULL;
155
Jonny Svärda830f172021-06-07 16:57:00 +0200156/******************************************************************************
157 * Weak functions - Cache
158 *
159 * Default NOP operations. Override if available on the targeted device.
160 ******************************************************************************/
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100161
Jonny Svärda830f172021-06-07 16:57:00 +0200162/*
163 * Flush/clean the data cache by address and size. Passing NULL as p argument
164 * expects the whole cache to be flushed.
165 */
166void __attribute__((weak)) ethosu_flush_dcache(uint32_t *p, size_t bytes)
167{
168 UNUSED(p);
169 UNUSED(bytes);
170}
171
172/*
173 * Invalidate the data cache by address and size. Passing NULL as p argument
174 * expects the whole cache to be invalidated.
175 */
176void __attribute__((weak)) ethosu_invalidate_dcache(uint32_t *p, size_t bytes)
177{
178 UNUSED(p);
179 UNUSED(bytes);
180}
181
182/******************************************************************************
183 * Weak functions - Semaphore/Mutex for multi NPU
184 *
185 * Following section handles the minimal sempahore and mutex implementation in
186 * case of baremetal applications. Weak symbols will be overridden by RTOS
187 * definitions and implement true thread-safety (in application layer).
188 ******************************************************************************/
189
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100190struct ethosu_semaphore_t
191{
192 int count;
193};
194
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100195static void *ethosu_mutex;
196static void *ethosu_semaphore;
197
Anton Moberg9f346ab2021-05-21 17:20:21 +0200198void *__attribute__((weak)) ethosu_mutex_create(void)
199{
200 return NULL;
201}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100202
Anton Moberg61ec36b2021-04-30 17:10:48 +0200203void __attribute__((weak)) ethosu_mutex_lock(void *mutex)
204{
205 UNUSED(mutex);
206}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100207
Anton Moberg61ec36b2021-04-30 17:10:48 +0200208void __attribute__((weak)) ethosu_mutex_unlock(void *mutex)
209{
210 UNUSED(mutex);
211}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100212
213// Baremetal implementation of creating a semaphore
214void *__attribute__((weak)) ethosu_semaphore_create(void)
215{
216 struct ethosu_semaphore_t *sem = malloc(sizeof(*sem));
217 sem->count = 1;
218 return sem;
219}
220
221// Baremetal simulation of waiting/sleeping for and then taking a semaphore using intrisics
222void __attribute__((weak)) ethosu_semaphore_take(void *sem)
223{
224 struct ethosu_semaphore_t *s = sem;
225 while (s->count <= 0)
226 {
227 __WFE();
228 }
229 s->count--;
230}
231
232// Baremetal simulation of giving a semaphore and waking up processes using intrinsics
233void __attribute__((weak)) ethosu_semaphore_give(void *sem)
234{
235 struct ethosu_semaphore_t *s = sem;
236 s->count++;
237 __SEV();
238}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100239
Jonny Svärda830f172021-06-07 16:57:00 +0200240/******************************************************************************
241 * Weak functions - Inference begin/end callbacks
242 ******************************************************************************/
Anton Moberg61da4d32020-12-22 16:00:31 +0100243
Jonny Svärda830f172021-06-07 16:57:00 +0200244void __attribute__((weak)) ethosu_inference_begin(struct ethosu_driver *drv, const void *inference_data)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200245{
Jonny Svärda830f172021-06-07 16:57:00 +0200246 UNUSED(inference_data);
247 UNUSED(drv);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200248}
249
Jonny Svärda830f172021-06-07 16:57:00 +0200250void __attribute__((weak)) ethosu_inference_end(struct ethosu_driver *drv, const void *inference_data)
251{
252 UNUSED(inference_data);
253 UNUSED(drv);
254}
255
256/******************************************************************************
257 * Static functions
258 ******************************************************************************/
Bhavik Pateldae5be02020-06-18 15:25:15 +0200259static inline void wait_for_irq(struct ethosu_driver *drv)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200260{
261 while (1)
262 {
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100263 if (drv->irq_triggered || drv->abort_inference)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200264 {
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100265 drv->irq_triggered = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200266 break;
267 }
268
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100269 ethosu_semaphore_take(drv->semaphore);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200270 }
271}
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200272
Jonny Svärda830f172021-06-07 16:57:00 +0200273static void npu_axi_init(struct ethosu_driver *drv)
Jens Elofsson04961a42021-04-08 18:51:38 +0200274{
Jonny Svärda830f172021-06-07 16:57:00 +0200275 ethosu_dev_set_qconfig(&drv->dev, NPU_QCONFIG);
276
277 ethosu_dev_set_regioncfg(&drv->dev, 0, NPU_REGIONCFG_0);
278 ethosu_dev_set_regioncfg(&drv->dev, 1, NPU_REGIONCFG_1);
279 ethosu_dev_set_regioncfg(&drv->dev, 2, NPU_REGIONCFG_2);
280 ethosu_dev_set_regioncfg(&drv->dev, 3, NPU_REGIONCFG_3);
281 ethosu_dev_set_regioncfg(&drv->dev, 4, NPU_REGIONCFG_4);
282 ethosu_dev_set_regioncfg(&drv->dev, 5, NPU_REGIONCFG_5);
283 ethosu_dev_set_regioncfg(&drv->dev, 6, NPU_REGIONCFG_6);
284 ethosu_dev_set_regioncfg(&drv->dev, 7, NPU_REGIONCFG_7);
285
286 (void)ethosu_dev_set_axi_limit0(&drv->dev,
287 AXI_LIMIT0_MAX_BEATS_BYTES,
288 AXI_LIMIT0_MEM_TYPE,
289 AXI_LIMIT0_MAX_OUTSTANDING_READS,
290 AXI_LIMIT0_MAX_OUTSTANDING_WRITES);
291 (void)ethosu_dev_set_axi_limit1(&drv->dev,
292 AXI_LIMIT1_MAX_BEATS_BYTES,
293 AXI_LIMIT1_MEM_TYPE,
294 AXI_LIMIT1_MAX_OUTSTANDING_READS,
295 AXI_LIMIT1_MAX_OUTSTANDING_WRITES);
296 (void)ethosu_dev_set_axi_limit2(&drv->dev,
297 AXI_LIMIT2_MAX_BEATS_BYTES,
298 AXI_LIMIT2_MEM_TYPE,
299 AXI_LIMIT2_MAX_OUTSTANDING_READS,
300 AXI_LIMIT2_MAX_OUTSTANDING_WRITES);
301 (void)ethosu_dev_set_axi_limit3(&drv->dev,
302 AXI_LIMIT3_MAX_BEATS_BYTES,
303 AXI_LIMIT3_MEM_TYPE,
304 AXI_LIMIT3_MAX_OUTSTANDING_READS,
305 AXI_LIMIT3_MAX_OUTSTANDING_WRITES);
Jens Elofsson04961a42021-04-08 18:51:38 +0200306}
307
Jonny Svärda830f172021-06-07 16:57:00 +0200308static void ethosu_register_driver(struct ethosu_driver *drv)
Jens Elofsson04961a42021-04-08 18:51:38 +0200309{
Jonny Svärda830f172021-06-07 16:57:00 +0200310 // Register driver as new HEAD of list
311 drv->next = registered_drivers;
312 registered_drivers = drv;
313
314 LOG_INFO("New NPU driver registered (handle: 0x%p, NPU: 0x%x)", drv, drv->dev.base_address);
Jens Elofsson04961a42021-04-08 18:51:38 +0200315}
316
Jonny Svärda830f172021-06-07 16:57:00 +0200317static int ethosu_deregister_driver(struct ethosu_driver *drv)
318{
319 struct ethosu_driver *cur = registered_drivers;
320 struct ethosu_driver **prev = &registered_drivers;
321
322 while (cur != NULL)
323 {
324 if (cur == drv)
325 {
326 *prev = cur->next;
327 LOG_INFO("NPU driver handle %p deregistered.", drv);
328 return 0;
329 }
330
331 prev = &cur->next;
332 cur = cur->next;
333 }
334
335 LOG_ERR("No NPU driver handle registered at address %p.", drv);
336
337 return -1;
338}
339
340static struct ethosu_driver *ethosu_find_and_reserve_driver(void)
341{
342 struct ethosu_driver *drv = registered_drivers;
343
344 while (drv != NULL)
345 {
346 if (!drv->reserved)
347 {
348 drv->reserved = true;
349 LOG_DEBUG("NPU driver handle %p reserved.", drv);
350 return drv;
351 }
352 drv = drv->next;
353 }
354
355 LOG_DEBUG("No NPU driver handle available.", drv);
356
357 return NULL;
358}
359
360static int ethosu_soft_reset_and_restore(struct ethosu_driver *drv)
361{
362
363 if (ETHOSU_SUCCESS != ethosu_dev_soft_reset(&drv->dev))
364 {
365 return -1;
366 }
367
368 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE);
369
370 npu_axi_init(drv);
371 ethosu_dev_restore_pmu_config(&drv->dev);
372
373 return 0;
374}
375
376static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s *opt_cfg_p)
377{
378 struct ethosu_config cfg;
379 struct ethosu_id id;
380 int return_code = 0;
381
382 LOG_INFO("Optimizer release nbr: %d patch: %d", opt_cfg_p->da_data.rel_nbr, opt_cfg_p->da_data.patch_nbr);
383 LOG_INFO("Optimizer config cmd_stream_version: %d macs_per_cc: %d shram_size: %d custom_dma: %d",
384 opt_cfg_p->cmd_stream_version,
385 opt_cfg_p->macs_per_cc,
386 opt_cfg_p->shram_size,
387 opt_cfg_p->custom_dma);
388 LOG_INFO("Optimizer config Ethos-U version: %d.%d.%d",
389 opt_cfg_p->arch_major_rev,
390 opt_cfg_p->arch_minor_rev,
391 opt_cfg_p->arch_patch_rev);
392
393 (void)ethosu_dev_get_config(&drv->dev, &cfg);
394 (void)ethosu_dev_get_id(&drv->dev, &id);
395 LOG_INFO("Ethos-U config cmd_stream_version: %" PRIu32 " macs_per_cc: %" PRIu32 " shram_size: %" PRIu32
396 " custom_dma: %" PRIu32 "",
397 cfg.cmd_stream_version,
398 cfg.macs_per_cc,
399 cfg.shram_size,
400 cfg.custom_dma);
401 LOG_INFO("Ethos-U version: %" PRIu32 ".%" PRIu32 ".%" PRIu32 "",
402 id.arch_major_rev,
403 id.arch_minor_rev,
404 id.arch_patch_rev);
405
406 if ((cfg.macs_per_cc != opt_cfg_p->macs_per_cc) || (cfg.shram_size != opt_cfg_p->shram_size) ||
407 (cfg.cmd_stream_version != opt_cfg_p->cmd_stream_version) || (!cfg.custom_dma && opt_cfg_p->custom_dma))
408 {
409 if (cfg.macs_per_cc != opt_cfg_p->macs_per_cc)
410 {
411 LOG_ERR("NPU config mismatch: npu.macs_per_cc=%" PRIu32 " optimizer.macs_per_cc=%d",
412 cfg.macs_per_cc,
413 opt_cfg_p->macs_per_cc);
414 }
415 if (cfg.shram_size != opt_cfg_p->shram_size)
416 {
417 LOG_ERR("NPU config mismatch: npu.shram_size=%" PRIu32 " optimizer.shram_size=%d",
418 cfg.shram_size,
419 opt_cfg_p->shram_size);
420 }
421 if (cfg.cmd_stream_version != opt_cfg_p->cmd_stream_version)
422 {
423 LOG_ERR("NPU config mismatch: npu.cmd_stream_version=%" PRIu32 " optimizer.cmd_stream_version=%d",
424 cfg.cmd_stream_version,
425 opt_cfg_p->cmd_stream_version);
426 }
427 if (!cfg.custom_dma && opt_cfg_p->custom_dma)
428 {
429 LOG_ERR("NPU config mismatch: npu.custom_dma=%" PRIu32 " optimize.custom_dma=%d",
430 cfg.custom_dma,
431 opt_cfg_p->custom_dma);
432 }
433 return_code = -1;
434 }
435
436 if ((id.arch_major_rev != opt_cfg_p->arch_major_rev) || (id.arch_minor_rev < opt_cfg_p->arch_minor_rev))
437 {
438 LOG_ERR("NPU arch mismatch: npu.arch=%" PRIu32 ".%" PRIu32 ".%" PRIu32 " optimizer.arch=%d.%d.%d",
439 id.arch_major_rev,
440 id.arch_minor_rev,
441 id.arch_patch_rev,
442 opt_cfg_p->arch_major_rev,
443 opt_cfg_p->arch_minor_rev,
444 opt_cfg_p->arch_patch_rev);
445 return_code = -1;
446 }
447
448#if !defined(LOG_ENABLED)
449 UNUSED(opt_cfg_p);
450#endif
451 return return_code;
452}
453
Bhavik Pateldae5be02020-06-18 15:25:15 +0200454static int handle_command_stream(struct ethosu_driver *drv,
455 const uint8_t *cmd_stream,
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200456 const int cms_length,
457 const uint64_t *base_addr,
Per Åstrand3c8afcc2020-10-20 10:29:59 +0200458 const size_t *base_addr_size,
Jonny Svärda830f172021-06-07 16:57:00 +0200459 const int num_base_addr)
460{
461 uint32_t qread = 0;
462 uint32_t cms_bytes = cms_length * BYTES_IN_32_BITS;
463 ptrdiff_t cmd_stream_ptr = (ptrdiff_t)cmd_stream;
464
465 LOG_INFO("handle_command_stream: cmd_stream=%p, cms_length %d", cmd_stream, cms_length);
466
467 if (0 != ((ptrdiff_t)cmd_stream & MASK_16_BYTE_ALIGN))
468 {
469 LOG_ERR("Command stream addr %p not aligned to 16 bytes", cmd_stream);
470 return -1;
471 }
472
473 bool base_addr_invalid = false;
474 for (int i = 0; i < num_base_addr; i++)
475 {
476 if (0 != (base_addr[i] & MASK_16_BYTE_ALIGN))
477 {
478 LOG_ERR("Base addr %d: 0x%llx not aligned to 16 bytes", i, base_addr[i]);
479 base_addr_invalid = true;
480 }
481 }
482
483 if (base_addr_invalid)
484 {
485 return -1;
486 }
487
488 /* Flush the cache if available on our CPU.
489 * The upcasting to uin32_t* is ok since the pointer never is dereferenced.
490 * The base_addr_size is null if invoking from prior to invoke_V2, in that case
491 * the whole cache is being flushed.
492 */
493
494 if (base_addr_size != NULL)
495 {
496 ethosu_flush_dcache((uint32_t *)cmd_stream_ptr, cms_bytes);
497 for (int i = 0; i < num_base_addr; i++)
498 {
499 ethosu_flush_dcache((uint32_t *)(uintptr_t)base_addr[i], base_addr_size[i]);
500 }
501 }
502 else
503 {
504 ethosu_flush_dcache(NULL, 0);
505 }
506
507 if (ETHOSU_SUCCESS != ethosu_dev_run_command_stream(&drv->dev, cmd_stream, cms_bytes, base_addr, num_base_addr))
508 {
509 return -1;
510 }
511
512 wait_for_irq(drv);
513
514 if (drv->status_error)
515 {
516 return -1;
517 }
518
519 if (base_addr_size != NULL)
520 {
521 for (int i = 0; i < num_base_addr; i++)
522 {
523 ethosu_invalidate_dcache((uint32_t *)(uintptr_t)base_addr[i], base_addr_size[i]);
524 }
525 }
526 else
527 {
528 ethosu_invalidate_dcache(NULL, 0);
529 }
530
531 qread = ethosu_dev_get_qread(&drv->dev);
532 if (qread != cms_bytes)
533 {
534 LOG_WARN("IRQ received but qread (%" PRIu32 ") not at end of stream (%" PRIu32 ").", qread, cms_bytes);
535 return -1;
536 }
537
538 return 0;
539}
540
541static int read_apb_reg(struct ethosu_driver *drv, uint16_t da_data)
542{
543 uint32_t *reg_p;
544 uint32_t start_address = (uint32_t)(da_data & APB_START_ADDR_MASK);
545 uint16_t num_reg = (da_data >> APB_NUM_REG_BIT_SHIFT) + 1;
546
547 reg_p = (uint32_t *)malloc(num_reg * sizeof(uint32_t));
548 if (reg_p == NULL)
549 {
550 LOG_ERR("Memory allocation failed");
551 return -1;
552 }
553
554 if (ETHOSU_SUCCESS == ethosu_dev_read_apb_reg(&drv->dev, start_address, num_reg, reg_p))
555 {
556 for (int i = 0; i < num_reg; i++)
557 {
558 LOG_INFO(
559 "NPU_REG ADDR 0x%04" PRIu32 " = 0x%08" PRIu32 "", (start_address + (i * BYTES_IN_32_BITS)), reg_p[i]);
560 }
561 }
562 else
563 {
564 free(reg_p);
565 return -1;
566 }
567
568 free(reg_p);
569 return 0;
570}
571
572static int dump_shram(struct ethosu_driver *drv)
573{
574 struct ethosu_config cfg;
575 uint32_t *shram_p;
576 (void)ethosu_dev_get_config(&drv->dev, &cfg);
577
578 LOG_INFO("dump_shram size = %" PRIu32 " KB", cfg.shram_size);
579
580 shram_p = (uint32_t *)malloc(BYTES_1KB);
581 if (shram_p == NULL)
582 {
583 LOG_ERR("Memory allocation failed for shram data");
584 return -1;
585 }
586
587 for (uint32_t i = 0; i < cfg.shram_size; i++)
588 {
589 ethosu_dev_get_shram_data(&drv->dev, i, (uint32_t *)shram_p);
590 // Output 1KB of SHRAM
591 LOG_INFO("***SHRAM SECTION %" PRIu32 "***", i);
592 for (int j = 0; j < (BYTES_1KB / BYTES_IN_32_BITS); j++)
593 {
594 LOG_INFO("[0x%04" PRIx32 "] %" PRIx32 "", (i * 1024 + j * 4), shram_p[j]);
595 }
596 }
597 free(shram_p);
598
599 return 0;
600}
601
602/******************************************************************************
603 * Weak functions - Interrupt handler
604 ******************************************************************************/
605void __attribute__((weak)) ethosu_irq_handler(struct ethosu_driver *drv)
606{
607 uint8_t irq_raised = 0;
608
609 LOG_DEBUG("Interrupt. status=0x%08x, qread=%d", ethosu_dev_get_status(&drv->dev), ethosu_dev_get_qread(&drv->dev));
610
611 // Verify that interrupt has been raised
612 (void)ethosu_dev_is_irq_raised(&drv->dev, &irq_raised);
613 assert(irq_raised == 1);
614 drv->irq_triggered = true;
615
616 // Clear interrupt
617 (void)ethosu_dev_clear_irq_status(&drv->dev);
618
619 // Verify that interrupt has been successfully cleared
620 (void)ethosu_dev_is_irq_raised(&drv->dev, &irq_raised);
621 assert(irq_raised == 0);
622
623 if (ethosu_dev_status_has_error(&drv->dev))
624 {
625 ethosu_soft_reset_and_restore(drv);
626 drv->status_error = true;
627 }
628
629 ethosu_semaphore_give(drv->semaphore);
630}
631
632/******************************************************************************
633 * Functions API
634 ******************************************************************************/
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200635
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200636int ethosu_init(struct ethosu_driver *drv,
637 const void *base_address,
638 const void *fast_memory,
639 const size_t fast_memory_size,
640 uint32_t secure_enable,
641 uint32_t privilege_enable)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200642{
643 int return_code = 0;
Bhavik Pateldae5be02020-06-18 15:25:15 +0200644
Jonny Svärda830f172021-06-07 16:57:00 +0200645 LOG_INFO("Initializing NPU: base_address=%p, fast_memory=%p, fast_memory_size=%zu, secure=%" PRIu32
646 ", privileged=%" PRIu32,
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200647 base_address,
648 fast_memory,
Per Åstrande6498f02020-11-09 15:33:12 +0100649 fast_memory_size,
650 secure_enable,
651 privilege_enable);
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200652
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100653 if (!ethosu_mutex)
654 {
655 ethosu_mutex = ethosu_mutex_create();
656 }
657
658 if (!ethosu_semaphore)
659 {
660 ethosu_semaphore = ethosu_semaphore_create();
661 }
662
Anton Moberg61da4d32020-12-22 16:00:31 +0100663 drv->fast_memory = (uint32_t)fast_memory;
664 drv->fast_memory_size = fast_memory_size;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100665 drv->irq_triggered = false;
666 drv->semaphore = ethosu_semaphore_create();
Anton Moberg61da4d32020-12-22 16:00:31 +0100667
668 if (ETHOSU_SUCCESS != ethosu_dev_init(&drv->dev, base_address, secure_enable, privilege_enable))
Bhavik Pateldae5be02020-06-18 15:25:15 +0200669 {
Jonny Svärda830f172021-06-07 16:57:00 +0200670 LOG_ERR("Failed to initialize Ethos-U device");
Bhavik Pateldae5be02020-06-18 15:25:15 +0200671 return -1;
672 }
673
Anton Moberg0a614292021-03-24 14:08:22 +0100674 if (ETHOSU_SUCCESS !=
675 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_DISABLE, ETHOSU_POWER_Q_DISABLE))
Bhavik Patele645fed2020-06-12 14:46:47 +0200676 {
Jonny Svärda830f172021-06-07 16:57:00 +0200677 LOG_ERR("Failed to disable clock-q & power-q for Ethos-U");
Bhavik Patele645fed2020-06-12 14:46:47 +0200678 return -1;
679 }
680
Jonny Svärda830f172021-06-07 16:57:00 +0200681 if (ETHOSU_SUCCESS != ethosu_dev_soft_reset(&drv->dev))
Per Åstrand849cf692020-11-24 07:39:55 +0100682 {
683 return -1;
684 }
Kristofer Jonssondaa0d202020-05-12 12:23:16 +0200685
Jonny Svärda830f172021-06-07 16:57:00 +0200686 if (ETHOSU_SUCCESS != ethosu_dev_wait_for_reset(&drv->dev))
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200687 {
Jonny Svärda830f172021-06-07 16:57:00 +0200688 LOG_ERR("Failed reset of Ethos-U");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200689 return -1;
690 }
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100691
Anton Moberg61da4d32020-12-22 16:00:31 +0100692 drv->status_error = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200693
Jonny Svärda830f172021-06-07 16:57:00 +0200694 ethosu_register_driver(drv);
695
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200696 return return_code;
697}
698
Anton Moberg547ca532021-06-14 09:43:53 +0200699void ethosu_deinit(struct ethosu_driver *drv)
700{
701 ethosu_deregister_driver(drv);
702}
703
Jonny Svärda830f172021-06-07 16:57:00 +0200704void ethosu_get_driver_version(struct ethosu_driver_version *ver)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200705{
Jonny Svärda830f172021-06-07 16:57:00 +0200706 assert(ver != NULL);
707 ver->major = ETHOSU_DRIVER_VERSION_MAJOR;
708 ver->minor = ETHOSU_DRIVER_VERSION_MINOR;
709 ver->patch = ETHOSU_DRIVER_VERSION_PATCH;
710}
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200711
Jonny Svärda830f172021-06-07 16:57:00 +0200712void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw)
713{
714 assert(hw != NULL);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200715
Jonny Svärda830f172021-06-07 16:57:00 +0200716 (void)ethosu_dev_get_id(&drv->dev, &hw->version);
717 (void)ethosu_dev_get_config(&drv->dev, &hw->cfg);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200718}
719
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200720int ethosu_invoke(struct ethosu_driver *drv,
721 const void *custom_data_ptr,
722 const int custom_data_size,
723 const uint64_t *base_addr,
724 const size_t *base_addr_size,
725 const int num_base_addr)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200726{
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200727 const struct custom_data_s *data_ptr = custom_data_ptr;
728 const struct custom_data_s *data_end = custom_data_ptr + custom_data_size;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200729 int return_code = 0;
730
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200731 // First word in custom_data_ptr should contain "Custom Operator Payload 1"
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200732 if (data_ptr->word != ETHOSU_FOURCC)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200733 {
Jonny Svärda830f172021-06-07 16:57:00 +0200734 LOG_ERR("Custom Operator Payload: %" PRIu32 " is not correct, expected %x", data_ptr->word, ETHOSU_FOURCC);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200735 return -1;
736 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200737
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200738 // Custom data length must be a multiple of 32 bits
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200739 if ((custom_data_size % BYTES_IN_32_BITS) != 0)
740 {
Jonny Svärda830f172021-06-07 16:57:00 +0200741 LOG_ERR("custom_data_size=0x%x not a multiple of 4", custom_data_size);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200742 return -1;
743 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200744
745 ++data_ptr;
746
747 // Adjust base address to fast memory area
Anton Moberg61da4d32020-12-22 16:00:31 +0100748 if (drv->fast_memory != 0 && num_base_addr >= FAST_MEMORY_BASE_ADDR_INDEX)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200749 {
750 uint64_t *fast_memory = (uint64_t *)&base_addr[FAST_MEMORY_BASE_ADDR_INDEX];
751
Anton Moberg61da4d32020-12-22 16:00:31 +0100752 if (base_addr_size != NULL && base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > drv->fast_memory_size)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200753 {
Jonny Svärda830f172021-06-07 16:57:00 +0200754 LOG_ERR("Fast memory area too small. fast_memory_size=%u, base_addr_size=%u",
Anton Moberg61da4d32020-12-22 16:00:31 +0100755 drv->fast_memory_size,
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100756 base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX]);
757 return -1;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200758 }
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100759
Anton Moberg61da4d32020-12-22 16:00:31 +0100760 *fast_memory = drv->fast_memory;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200761 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200762
Anton Moberg61da4d32020-12-22 16:00:31 +0100763 if (!drv->dev_power_always_on)
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200764 {
Jonny Svärda830f172021-06-07 16:57:00 +0200765 // Only soft reset if security state or privilege level needs changing
766 if (ethosu_dev_prot_has_changed(&drv->dev))
Per Åstrand849cf692020-11-24 07:39:55 +0100767 {
Jonny Svärda830f172021-06-07 16:57:00 +0200768 if (ETHOSU_SUCCESS != ethosu_dev_soft_reset(&drv->dev))
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100769 {
770 return -1;
771 }
Per Åstrand849cf692020-11-24 07:39:55 +0100772 }
Anton Moberg61da4d32020-12-22 16:00:31 +0100773
774 drv->status_error = false;
Anton Moberg0a614292021-03-24 14:08:22 +0100775 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE);
Jonny Svärda830f172021-06-07 16:57:00 +0200776 ethosu_dev_restore_pmu_config(&drv->dev);
Anton Moberg61da4d32020-12-22 16:00:31 +0100777 npu_axi_init(drv);
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200778 }
Kristofer Jonssonc6e7a1f2020-11-24 09:20:14 +0100779
Anton Moberg61da4d32020-12-22 16:00:31 +0100780 drv->status_error = false;
Kristofer Jonsson125429a2020-08-20 16:52:23 +0200781
Jens Elofsson04961a42021-04-08 18:51:38 +0200782 ethosu_inference_begin(drv, custom_data_ptr);
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200783 while (data_ptr < data_end)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200784 {
Bhavik Patele645fed2020-06-12 14:46:47 +0200785 int ret = 0;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200786 switch (data_ptr->driver_action_command)
787 {
788 case OPTIMIZER_CONFIG:
Jonny Svärda830f172021-06-07 16:57:00 +0200789 LOG_DEBUG("OPTIMIZER_CONFIG");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200790 struct opt_cfg_s *opt_cfg_p = (struct opt_cfg_s *)data_ptr;
791
Anton Moberg61da4d32020-12-22 16:00:31 +0100792 ret = handle_optimizer_config(drv, opt_cfg_p);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200793 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD;
794 break;
795 case COMMAND_STREAM:
Jonny Svärda830f172021-06-07 16:57:00 +0200796 LOG_DEBUG("COMMAND_STREAM");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200797 void *command_stream = (uint8_t *)(data_ptr) + sizeof(struct custom_data_s);
798 int cms_length = (data_ptr->reserved << 16) | data_ptr->length;
799
Anton Moberg61da4d32020-12-22 16:00:31 +0100800 drv->abort_inference = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200801 // It is safe to clear this flag without atomic, because npu is not running.
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100802 drv->irq_triggered = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200803
Anton Moberg61da4d32020-12-22 16:00:31 +0100804 ret = handle_command_stream(drv, command_stream, cms_length, base_addr, base_addr_size, num_base_addr);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200805
Anton Moberg61da4d32020-12-22 16:00:31 +0100806 if (return_code == -1 && drv->abort_inference)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200807 {
Jonny Svärda830f172021-06-07 16:57:00 +0200808 LOG_ERR("NPU timeout. qread=%" PRIu32, ethosu_dev_get_qread(&drv->dev));
Anton Moberg61da4d32020-12-22 16:00:31 +0100809 dump_shram(drv);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200810 }
811
812 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + cms_length;
813 break;
814 case READ_APB_REG:
Jonny Svärda830f172021-06-07 16:57:00 +0200815 LOG_DEBUG("READ_APB_REG");
Anton Moberg61da4d32020-12-22 16:00:31 +0100816 ret = read_apb_reg(drv, data_ptr->driver_action_data);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200817 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
818 break;
819 case DUMP_SHRAM:
Jonny Svärda830f172021-06-07 16:57:00 +0200820 LOG_DEBUG("DUMP_SHRAM");
Anton Moberg61da4d32020-12-22 16:00:31 +0100821 ret = dump_shram(drv);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200822 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
823 break;
824 case NOP:
Jonny Svärda830f172021-06-07 16:57:00 +0200825 LOG_DEBUG("NOP");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200826 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
827 break;
828 default:
Jonny Svärda830f172021-06-07 16:57:00 +0200829 LOG_ERR("UNSUPPORTED driver_action_command: %d ", data_ptr->driver_action_command);
Bhavik Patele645fed2020-06-12 14:46:47 +0200830 ret = -1;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200831 break;
832 }
Bhavik Patele645fed2020-06-12 14:46:47 +0200833 if (ret != 0)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200834 {
Bhavik Patele645fed2020-06-12 14:46:47 +0200835 return_code = -1;
836 break;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200837 }
838 }
Jens Elofsson04961a42021-04-08 18:51:38 +0200839 ethosu_inference_end(drv, custom_data_ptr);
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200840
Anton Moberg61da4d32020-12-22 16:00:31 +0100841 if (!drv->status_error && !drv->dev_power_always_on)
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200842 {
Jonny Svärda830f172021-06-07 16:57:00 +0200843 ethosu_dev_save_pmu_counters(&drv->dev);
Anton Moberg0a614292021-03-24 14:08:22 +0100844 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200845 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200846
Bhavik Patele645fed2020-06-12 14:46:47 +0200847 return return_code;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200848}
849
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200850void ethosu_abort(struct ethosu_driver *drv)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200851{
Anton Moberg61da4d32020-12-22 16:00:31 +0100852 drv->abort_inference = true;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200853}
854
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200855void ethosu_set_power_mode(struct ethosu_driver *drv, bool always_on)
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100856{
Anton Moberg61da4d32020-12-22 16:00:31 +0100857 drv->dev_power_always_on = always_on;
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100858
859 if (always_on)
860 {
Anton Moberg61da4d32020-12-22 16:00:31 +0100861 npu_axi_init(drv);
862 }
863}
864
Anton Moberg61da4d32020-12-22 16:00:31 +0100865struct ethosu_driver *ethosu_reserve_driver(void)
866{
Anton Mobergdf386e02021-02-02 11:26:48 +0100867 struct ethosu_driver *drv = NULL;
868
869 do
870 {
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100871 ethosu_mutex_lock(ethosu_mutex);
Anton Mobergdf386e02021-02-02 11:26:48 +0100872 drv = ethosu_find_and_reserve_driver();
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100873 ethosu_mutex_unlock(ethosu_mutex);
Anton Mobergdf386e02021-02-02 11:26:48 +0100874
875 if (drv != NULL)
876 {
877 break;
878 }
879
Jonny Svärda830f172021-06-07 16:57:00 +0200880 LOG_INFO("Waiting for NPU driver handle to become available...");
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100881 ethosu_semaphore_take(ethosu_semaphore);
Anton Mobergdf386e02021-02-02 11:26:48 +0100882
883 } while (1);
884
885 return drv;
886}
887
Anton Moberg61da4d32020-12-22 16:00:31 +0100888void ethosu_release_driver(struct ethosu_driver *drv)
889{
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100890 ethosu_mutex_lock(ethosu_mutex);
Anton Moberg61da4d32020-12-22 16:00:31 +0100891 if (drv != NULL && drv->reserved)
892 {
893 drv->reserved = false;
Jonny Svärda830f172021-06-07 16:57:00 +0200894 LOG_DEBUG("NPU driver handle %p released", drv);
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100895 ethosu_semaphore_give(ethosu_semaphore);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100896 }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100897 ethosu_mutex_unlock(ethosu_mutex);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100898}
899
Anton Moberg0a614292021-03-24 14:08:22 +0100900enum ethosu_error_codes set_clock_and_power_request(struct ethosu_driver *drv,
901 enum ethosu_request_clients client,
902 enum ethosu_clock_q_request clock_request,
903 enum ethosu_power_q_request power_request)
904{
905 // Set clock request bit for client
906 if (clock_request == ETHOSU_CLOCK_Q_DISABLE)
907 {
908 drv->clock_request |= (1 << client);
909 }
910 else
911 {
912 drv->clock_request &= ~(1 << client);
913 }
914 // Get current clock request (ENABLE if both PMU and INFERENCE asks for clock request, else DISABLE)
915 clock_request = drv->clock_request == 0 ? ETHOSU_CLOCK_Q_ENABLE : ETHOSU_CLOCK_Q_DISABLE;
916
917 // Set power request bit for client
Anton Moberg35b5d0e2021-04-13 13:32:17 +0200918 if (power_request == ETHOSU_POWER_Q_DISABLE)
Anton Moberg0a614292021-03-24 14:08:22 +0100919 {
920 drv->power_request |= (1 << client);
921 }
922 else
923 {
924 drv->power_request &= ~(1 << client);
925 }
926 // Get current power request (ENABLE if both PMU and INFERENCE asks for power request, else DISABLE)
927 power_request = drv->power_request == 0 ? ETHOSU_POWER_Q_ENABLE : ETHOSU_POWER_Q_DISABLE;
Anton Moberg35b5d0e2021-04-13 13:32:17 +0200928
Anton Moberg0a614292021-03-24 14:08:22 +0100929 // Set clock and power
Jonny Svärda830f172021-06-07 16:57:00 +0200930 enum ethosu_error_codes ret = ethosu_dev_set_clock_and_power(&drv->dev, clock_request, power_request);
Anton Moberg0a614292021-03-24 14:08:22 +0100931
932 return ret;
933}