blob: dead0b94c675fe4410679b1c91274a927557ff5e [file] [log] [blame]
Kristofer Jonsson49bdee82020-04-06 13:21:21 +02001/*
Rajasekaran Kalidoss2fa2bf02024-04-22 09:11:02 +02002 * SPDX-FileCopyrightText: Copyright 2019-2024 Arm Limited and/or its affiliates <open-source-office@arm.com>
Kristofer Jonsson49bdee82020-04-06 13:21:21 +02003 * 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
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020018/******************************************************************************
19 * Includes
20 ******************************************************************************/
21
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020022#include "ethosu_driver.h"
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020023#include "ethosu_device.h"
Anton Moberg6eab40b2021-07-07 11:43:51 +020024#include "ethosu_log.h"
Per Åstrand25d78c02020-04-21 14:19:44 +020025
Kristofer Jonsson1c0e7ae2022-05-12 11:35:33 +020026#ifdef ETHOSU55
27#include "ethosu_config_u55.h"
28#else
29#include "ethosu_config_u65.h"
30#endif
31
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020032#include <assert.h>
Per Åstrand25d78c02020-04-21 14:19:44 +020033#include <cmsis_compiler.h>
Per Åstrand14ccfee2020-09-25 10:40:20 +020034#include <inttypes.h>
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020035#include <stdbool.h>
Bhavik Patelbf7ae632020-06-11 21:00:16 +020036#include <stddef.h>
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020037#include <stdio.h>
38#include <stdlib.h>
39
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020040/******************************************************************************
41 * Defines
42 ******************************************************************************/
43
Jonny Svärd136810f2021-10-13 16:04:26 +020044#define UNUSED(x) ((void)x)
45
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020046#define BYTES_IN_32_BITS 4
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020047#define MASK_16_BYTE_ALIGN (0xF)
Jonny Svärd136810f2021-10-13 16:04:26 +020048#define OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD 2
49#define DRIVER_ACTION_LENGTH_32_BIT_WORD 1
50#define ETHOSU_FOURCC ('1' << 24 | 'P' << 16 | 'O' << 8 | 'C') // "Custom Operator Payload 1"
51
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020052#define FAST_MEMORY_BASE_ADDR_INDEX 2
53
54/******************************************************************************
55 * Types
56 ******************************************************************************/
57
58// Driver actions
59enum DRIVER_ACTION_e
60{
61 RESERVED = 0,
62 OPTIMIZER_CONFIG = 1,
63 COMMAND_STREAM = 2,
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020064 NOP = 5,
65};
66
Jonny Svärd136810f2021-10-13 16:04:26 +020067// Custom operator payload data struct
68struct cop_data_s
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020069{
70 union
71 {
72 // Driver action data
73 struct
74 {
Jonny Svärd136810f2021-10-13 16:04:26 +020075 uint8_t driver_action_command; // (valid values in DRIVER_ACTION_e)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020076 uint8_t reserved;
77
78 // Driver action data
79 union
80 {
81 // DA_CMD_OPT_CFG
82 struct
83 {
84 uint16_t rel_nbr : 4;
85 uint16_t patch_nbr : 4;
86 uint16_t opt_cfg_reserved : 8;
87 };
88
89 // DA_CMD_CMSTRM
90 struct
91 {
92 uint16_t length;
93 };
94
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020095 uint16_t driver_action_data;
96 };
97 };
98
99 uint32_t word;
100 };
101};
102
103// optimizer config struct
104struct opt_cfg_s
105{
Jonny Svärd136810f2021-10-13 16:04:26 +0200106 struct cop_data_s da_data;
107 uint32_t cfg;
108 uint32_t id;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200109};
110
111/******************************************************************************
Jonny Svärda830f172021-06-07 16:57:00 +0200112 * Variables
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200113 ******************************************************************************/
114
Anton Moberg61da4d32020-12-22 16:00:31 +0100115// Registered drivers linked list HEAD
116static struct ethosu_driver *registered_drivers = NULL;
117
Jonny Svärda830f172021-06-07 16:57:00 +0200118/******************************************************************************
119 * Weak functions - Cache
120 *
121 * Default NOP operations. Override if available on the targeted device.
122 ******************************************************************************/
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100123
Jonny Svärda830f172021-06-07 16:57:00 +0200124/*
125 * Flush/clean the data cache by address and size. Passing NULL as p argument
126 * expects the whole cache to be flushed.
127 */
128void __attribute__((weak)) ethosu_flush_dcache(uint32_t *p, size_t bytes)
129{
130 UNUSED(p);
131 UNUSED(bytes);
132}
133
134/*
135 * Invalidate the data cache by address and size. Passing NULL as p argument
136 * expects the whole cache to be invalidated.
137 */
138void __attribute__((weak)) ethosu_invalidate_dcache(uint32_t *p, size_t bytes)
139{
140 UNUSED(p);
141 UNUSED(bytes);
142}
143
144/******************************************************************************
145 * Weak functions - Semaphore/Mutex for multi NPU
146 *
147 * Following section handles the minimal sempahore and mutex implementation in
148 * case of baremetal applications. Weak symbols will be overridden by RTOS
149 * definitions and implement true thread-safety (in application layer).
150 ******************************************************************************/
151
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100152struct ethosu_semaphore_t
153{
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100154 uint8_t count;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100155};
156
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100157static void *ethosu_mutex;
158static void *ethosu_semaphore;
159
Anton Moberg9f346ab2021-05-21 17:20:21 +0200160void *__attribute__((weak)) ethosu_mutex_create(void)
161{
Jonny Svärda2732ec2023-12-18 17:19:15 +0100162 static uint8_t mutex_placeholder;
163 return &mutex_placeholder;
Anton Moberg9f346ab2021-05-21 17:20:21 +0200164}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100165
Jonny Svärd136810f2021-10-13 16:04:26 +0200166void __attribute__((weak)) ethosu_mutex_destroy(void *mutex)
167{
168 UNUSED(mutex);
169}
170
Ledion Dajac6505f32022-04-20 09:55:21 +0200171int __attribute__((weak)) ethosu_mutex_lock(void *mutex)
Anton Moberg61ec36b2021-04-30 17:10:48 +0200172{
173 UNUSED(mutex);
Ledion Dajac6505f32022-04-20 09:55:21 +0200174 return 0;
Anton Moberg61ec36b2021-04-30 17:10:48 +0200175}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100176
Ledion Dajac6505f32022-04-20 09:55:21 +0200177int __attribute__((weak)) ethosu_mutex_unlock(void *mutex)
Anton Moberg61ec36b2021-04-30 17:10:48 +0200178{
179 UNUSED(mutex);
Ledion Dajac6505f32022-04-20 09:55:21 +0200180 return 0;
Anton Moberg61ec36b2021-04-30 17:10:48 +0200181}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100182
183// Baremetal implementation of creating a semaphore
184void *__attribute__((weak)) ethosu_semaphore_create(void)
185{
186 struct ethosu_semaphore_t *sem = malloc(sizeof(*sem));
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100187 if (sem != NULL)
188 {
189 sem->count = 0;
190 }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100191 return sem;
192}
193
Jonny Svärd136810f2021-10-13 16:04:26 +0200194void __attribute__((weak)) ethosu_semaphore_destroy(void *sem)
195{
196 free((struct ethosu_semaphore_t *)sem);
197}
198
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100199// Baremetal simulation of waiting/sleeping for and then taking a semaphore using intrisics
Jonny Svärda2732ec2023-12-18 17:19:15 +0100200int __attribute__((weak)) ethosu_semaphore_take(void *sem, uint64_t timeout)
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100201{
Jonny Svärda2732ec2023-12-18 17:19:15 +0100202 UNUSED(timeout);
203 // Baremetal pseudo-example on how to trigger a timeout:
204 // if (timeout != ETHOSU_SEMAPHORE_WAIT_FOREVER) {
205 // setup_a_timer_to_call_SEV_after_time(timeout);
206 // }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100207 struct ethosu_semaphore_t *s = sem;
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100208 while (s->count == 0)
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100209 {
210 __WFE();
Jonny Svärda2732ec2023-12-18 17:19:15 +0100211 // Baremetal pseudo-example check if timeout triggered:
212 // if (SEV_timer_triggered()) {
213 // return -1;
214 // }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100215 }
Jonny Svärdc9644242023-01-09 15:54:24 +0100216 s->count--;
Ledion Dajac6505f32022-04-20 09:55:21 +0200217 return 0;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100218}
219
220// Baremetal simulation of giving a semaphore and waking up processes using intrinsics
Ledion Dajac6505f32022-04-20 09:55:21 +0200221int __attribute__((weak)) ethosu_semaphore_give(void *sem)
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100222{
223 struct ethosu_semaphore_t *s = sem;
Jonny Svärdc9644242023-01-09 15:54:24 +0100224 s->count++;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100225 __SEV();
Ledion Dajac6505f32022-04-20 09:55:21 +0200226 return 0;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100227}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100228
Jonny Svärda830f172021-06-07 16:57:00 +0200229/******************************************************************************
230 * Weak functions - Inference begin/end callbacks
231 ******************************************************************************/
Anton Moberg61da4d32020-12-22 16:00:31 +0100232
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100233void __attribute__((weak)) ethosu_inference_begin(struct ethosu_driver *drv, void *user_arg)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200234{
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100235 UNUSED(user_arg);
Jonny Svärda830f172021-06-07 16:57:00 +0200236 UNUSED(drv);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200237}
238
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100239void __attribute__((weak)) ethosu_inference_end(struct ethosu_driver *drv, void *user_arg)
Jonny Svärda830f172021-06-07 16:57:00 +0200240{
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100241 UNUSED(user_arg);
Jonny Svärda830f172021-06-07 16:57:00 +0200242 UNUSED(drv);
243}
244
245/******************************************************************************
246 * Static functions
247 ******************************************************************************/
Jonny Svärda830f172021-06-07 16:57:00 +0200248static void ethosu_register_driver(struct ethosu_driver *drv)
Jens Elofsson04961a42021-04-08 18:51:38 +0200249{
Jonny Svärdc9644242023-01-09 15:54:24 +0100250 ethosu_mutex_lock(ethosu_mutex);
Jonny Svärda830f172021-06-07 16:57:00 +0200251 drv->next = registered_drivers;
252 registered_drivers = drv;
Jonny Svärdc9644242023-01-09 15:54:24 +0100253 ethosu_mutex_unlock(ethosu_mutex);
254
255 ethosu_semaphore_give(ethosu_semaphore);
Jonny Svärda830f172021-06-07 16:57:00 +0200256
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100257 LOG_INFO("New NPU driver registered (handle: 0x%p, NPU: 0x%p)", drv, drv->dev->reg);
Jens Elofsson04961a42021-04-08 18:51:38 +0200258}
259
Jonny Svärda830f172021-06-07 16:57:00 +0200260static int ethosu_deregister_driver(struct ethosu_driver *drv)
261{
Jonny Svärdc9644242023-01-09 15:54:24 +0100262 struct ethosu_driver *curr;
263 struct ethosu_driver **prev;
Jonny Svärda830f172021-06-07 16:57:00 +0200264
Jonny Svärdc9644242023-01-09 15:54:24 +0100265 ethosu_mutex_lock(ethosu_mutex);
266 curr = registered_drivers;
267 prev = &registered_drivers;
268
269 while (curr != NULL)
Jonny Svärda830f172021-06-07 16:57:00 +0200270 {
Jonny Svärdc9644242023-01-09 15:54:24 +0100271 if (curr == drv)
Jonny Svärda830f172021-06-07 16:57:00 +0200272 {
Jonny Svärdc9644242023-01-09 15:54:24 +0100273 *prev = curr->next;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100274 LOG_INFO("NPU driver handle %p deregistered.", drv);
Jonny Svärda2732ec2023-12-18 17:19:15 +0100275 ethosu_semaphore_take(ethosu_semaphore, ETHOSU_SEMAPHORE_WAIT_FOREVER);
Jonny Svärdc9644242023-01-09 15:54:24 +0100276 break;
Jonny Svärda830f172021-06-07 16:57:00 +0200277 }
278
Jonny Svärdc9644242023-01-09 15:54:24 +0100279 prev = &curr->next;
280 curr = curr->next;
Jonny Svärda830f172021-06-07 16:57:00 +0200281 }
282
Jonny Svärdc9644242023-01-09 15:54:24 +0100283 ethosu_mutex_unlock(ethosu_mutex);
Jonny Svärda830f172021-06-07 16:57:00 +0200284
Jonny Svärdc9644242023-01-09 15:54:24 +0100285 if (curr == NULL)
Jonny Svärda830f172021-06-07 16:57:00 +0200286 {
Jonny Svärdc9644242023-01-09 15:54:24 +0100287 LOG_ERR("No NPU driver handle registered at address %p.", drv);
288 return -1;
Jonny Svärda830f172021-06-07 16:57:00 +0200289 }
290
Jonny Svärdc9644242023-01-09 15:54:24 +0100291 return 0;
Jonny Svärda830f172021-06-07 16:57:00 +0200292}
293
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100294static void ethosu_reset_job(struct ethosu_driver *drv)
295{
296 memset(&drv->job, 0, sizeof(struct ethosu_job));
297}
298
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100299static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s const *opt_cfg_p)
Jonny Svärda830f172021-06-07 16:57:00 +0200300{
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100301 LOG_INFO("Optimizer release nbr: %u patch: %u", opt_cfg_p->da_data.rel_nbr, opt_cfg_p->da_data.patch_nbr);
Jonny Svärda830f172021-06-07 16:57:00 +0200302
Jonny Svärd136810f2021-10-13 16:04:26 +0200303 if (ethosu_dev_verify_optimizer_config(drv->dev, opt_cfg_p->cfg, opt_cfg_p->id) != true)
Jonny Svärda830f172021-06-07 16:57:00 +0200304 {
305 return -1;
306 }
307
Jonny Svärda830f172021-06-07 16:57:00 +0200308 return 0;
309}
310
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100311static int handle_command_stream(struct ethosu_driver *drv, const uint8_t *cmd_stream, const int cms_length)
Jonny Svärda830f172021-06-07 16:57:00 +0200312{
Jonny Svärda830f172021-06-07 16:57:00 +0200313 uint32_t cms_bytes = cms_length * BYTES_IN_32_BITS;
314 ptrdiff_t cmd_stream_ptr = (ptrdiff_t)cmd_stream;
315
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100316 LOG_INFO("handle_command_stream: cmd_stream=%p, cms_length %d", cmd_stream, cms_length);
Jonny Svärda830f172021-06-07 16:57:00 +0200317
318 if (0 != ((ptrdiff_t)cmd_stream & MASK_16_BYTE_ALIGN))
319 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100320 LOG_ERR("Command stream addr %p not aligned to 16 bytes", cmd_stream);
Jonny Svärda830f172021-06-07 16:57:00 +0200321 return -1;
322 }
323
Jonny Svärd136810f2021-10-13 16:04:26 +0200324 // Verify 16 byte alignment for base address'
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100325 for (int i = 0; i < drv->job.num_base_addr; i++)
Jonny Svärda830f172021-06-07 16:57:00 +0200326 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100327 if (0 != (drv->job.base_addr[i] & MASK_16_BYTE_ALIGN))
Jonny Svärda830f172021-06-07 16:57:00 +0200328 {
Rajasekaran Kalidoss2fa2bf02024-04-22 09:11:02 +0200329 LOG_ERR("Base addr %d: 0x%" PRIx64 "not aligned to 16 bytes", i, drv->job.base_addr[i]);
Jonny Svärd136810f2021-10-13 16:04:26 +0200330 return -1;
Jonny Svärda830f172021-06-07 16:57:00 +0200331 }
332 }
333
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100334 // Flush the cache if available on CPU.
335 // The upcasting to uin32_t* is ok since the pointer never is dereferenced.
336 // The base_addr_size is null if invoking from prior to invoke_V2, in that case
337 // the whole cache is being flushed.
338
339 if (drv->job.base_addr_size != NULL)
Jonny Svärda830f172021-06-07 16:57:00 +0200340 {
341 ethosu_flush_dcache((uint32_t *)cmd_stream_ptr, cms_bytes);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100342 for (int i = 0; i < drv->job.num_base_addr; i++)
Jonny Svärda830f172021-06-07 16:57:00 +0200343 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100344 ethosu_flush_dcache((uint32_t *)(uintptr_t)drv->job.base_addr[i], drv->job.base_addr_size[i]);
Jonny Svärda830f172021-06-07 16:57:00 +0200345 }
346 }
347 else
348 {
349 ethosu_flush_dcache(NULL, 0);
350 }
351
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100352 // Request power gating disabled during inference run
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100353 if (ethosu_request_power(drv))
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100354 {
Jonny Svärd301399d2022-04-26 18:31:24 +0200355 LOG_ERR("Failed to request power");
356 return -1;
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100357 }
358
Jonny Svärd301399d2022-04-26 18:31:24 +0200359 drv->job.state = ETHOSU_JOB_RUNNING;
360
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100361 // Inference begin callback
362 ethosu_inference_begin(drv, drv->job.user_arg);
363
Jonny Svärd136810f2021-10-13 16:04:26 +0200364 // Execute the command stream
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100365 ethosu_dev_run_command_stream(drv->dev, cmd_stream, cms_bytes, drv->job.base_addr, drv->job.num_base_addr);
Jonny Svärda830f172021-06-07 16:57:00 +0200366
Jonny Svärda830f172021-06-07 16:57:00 +0200367 return 0;
368}
369
370/******************************************************************************
371 * Weak functions - Interrupt handler
372 ******************************************************************************/
373void __attribute__((weak)) ethosu_irq_handler(struct ethosu_driver *drv)
374{
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100375 LOG_DEBUG("Got interrupt from Ethos-U");
Jonny Svärda830f172021-06-07 16:57:00 +0200376
Jonny Svärda2732ec2023-12-18 17:19:15 +0100377 // Prevent race condition where interrupt triggered after a timeout waiting
378 // for semaphore, but before NPU is reset.
379 if (drv->job.result == ETHOSU_JOB_RESULT_TIMEOUT)
Jonny Svärda830f172021-06-07 16:57:00 +0200380 {
Jonny Svärda2732ec2023-12-18 17:19:15 +0100381 return;
Jonny Svärda830f172021-06-07 16:57:00 +0200382 }
Jonny Svärda2732ec2023-12-18 17:19:15 +0100383
384 drv->job.state = ETHOSU_JOB_DONE;
385 drv->job.result = ethosu_dev_handle_interrupt(drv->dev) ? ETHOSU_JOB_RESULT_OK : ETHOSU_JOB_RESULT_ERROR;
Jonny Svärda830f172021-06-07 16:57:00 +0200386 ethosu_semaphore_give(drv->semaphore);
387}
388
389/******************************************************************************
390 * Functions API
391 ******************************************************************************/
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200392
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200393int ethosu_init(struct ethosu_driver *drv,
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100394 void *const base_address,
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200395 const void *fast_memory,
396 const size_t fast_memory_size,
397 uint32_t secure_enable,
398 uint32_t privilege_enable)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200399{
Jonny Svärda830f172021-06-07 16:57:00 +0200400 LOG_INFO("Initializing NPU: base_address=%p, fast_memory=%p, fast_memory_size=%zu, secure=%" PRIu32
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100401 ", privileged=%" PRIu32,
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200402 base_address,
403 fast_memory,
Per Åstrande6498f02020-11-09 15:33:12 +0100404 fast_memory_size,
405 secure_enable,
406 privilege_enable);
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200407
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100408 if (!ethosu_mutex)
409 {
410 ethosu_mutex = ethosu_mutex_create();
Jonny Svärda2732ec2023-12-18 17:19:15 +0100411 if (!ethosu_mutex)
412 {
413 LOG_ERR("Failed to create global driver mutex");
414 return -1;
415 }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100416 }
417
418 if (!ethosu_semaphore)
419 {
420 ethosu_semaphore = ethosu_semaphore_create();
Jonny Svärdc9644242023-01-09 15:54:24 +0100421 if (!ethosu_semaphore)
422 {
423 LOG_ERR("Failed to create global driver semaphore");
424 return -1;
425 }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100426 }
427
Rajasekaran Kalidoss2fa2bf02024-04-22 09:11:02 +0200428 drv->fast_memory = (uint64_t)fast_memory;
Jonny Svärd301399d2022-04-26 18:31:24 +0200429 drv->fast_memory_size = fast_memory_size;
430 drv->power_request_counter = 0;
Anton Moberg61da4d32020-12-22 16:00:31 +0100431
Jonny Svärd136810f2021-10-13 16:04:26 +0200432 // Initialize the device and set requested security state and privilege mode
433 drv->dev = ethosu_dev_init(base_address, secure_enable, privilege_enable);
434
435 if (drv->dev == NULL)
Bhavik Pateldae5be02020-06-18 15:25:15 +0200436 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100437 LOG_ERR("Failed to initialize Ethos-U device");
Bhavik Pateldae5be02020-06-18 15:25:15 +0200438 return -1;
439 }
440
Jonny Svärdc9644242023-01-09 15:54:24 +0100441 drv->semaphore = ethosu_semaphore_create();
442 if (!drv->semaphore)
443 {
444 LOG_ERR("Failed to create driver semaphore");
445 ethosu_dev_deinit(drv->dev);
446 drv->dev = NULL;
447 return -1;
448 }
449
Jonny Svärd301399d2022-04-26 18:31:24 +0200450 ethosu_reset_job(drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200451 ethosu_register_driver(drv);
452
Jonny Svärd136810f2021-10-13 16:04:26 +0200453 return 0;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200454}
455
Anton Moberg547ca532021-06-14 09:43:53 +0200456void ethosu_deinit(struct ethosu_driver *drv)
457{
458 ethosu_deregister_driver(drv);
Jonny Svärd136810f2021-10-13 16:04:26 +0200459 ethosu_semaphore_destroy(drv->semaphore);
460 ethosu_dev_deinit(drv->dev);
461 drv->dev = NULL;
Anton Moberg547ca532021-06-14 09:43:53 +0200462}
463
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100464int ethosu_soft_reset(struct ethosu_driver *drv)
Jonny Svärd301399d2022-04-26 18:31:24 +0200465{
466 // Soft reset the NPU
467 if (ethosu_dev_soft_reset(drv->dev) != ETHOSU_SUCCESS)
468 {
469 LOG_ERR("Failed to soft-reset NPU");
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100470 return -1;
Jonny Svärd301399d2022-04-26 18:31:24 +0200471 }
472
473 // Update power and clock gating after the soft reset
474 ethosu_dev_set_clock_and_power(drv->dev,
475 drv->power_request_counter > 0 ? ETHOSU_CLOCK_Q_DISABLE : ETHOSU_CLOCK_Q_ENABLE,
476 drv->power_request_counter > 0 ? ETHOSU_POWER_Q_DISABLE : ETHOSU_POWER_Q_ENABLE);
477
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100478 return 0;
Jonny Svärd301399d2022-04-26 18:31:24 +0200479}
480
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100481int ethosu_request_power(struct ethosu_driver *drv)
Jonny Svärd301399d2022-04-26 18:31:24 +0200482{
483 // Check if this is the first power request, increase counter
484 if (drv->power_request_counter++ == 0)
485 {
486 // Always reset to a known state. Changes to requested
487 // security state/privilege mode if necessary.
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100488 if (ethosu_soft_reset(drv))
Jonny Svärd301399d2022-04-26 18:31:24 +0200489 {
490 LOG_ERR("Failed to request power for Ethos-U");
491 drv->power_request_counter--;
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100492 return -1;
Jonny Svärd301399d2022-04-26 18:31:24 +0200493 }
494 }
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100495 return 0;
Jonny Svärd301399d2022-04-26 18:31:24 +0200496}
497
498void ethosu_release_power(struct ethosu_driver *drv)
499{
500 if (drv->power_request_counter == 0)
501 {
502 LOG_WARN("No power request left to release, reference counter is 0");
503 }
504 else
505 {
506 // Decrement ref counter and enable power gating if no requests remain
507 if (--drv->power_request_counter == 0)
508 {
509 ethosu_dev_set_clock_and_power(drv->dev, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
510 }
511 }
512}
513
Jonny Svärda830f172021-06-07 16:57:00 +0200514void ethosu_get_driver_version(struct ethosu_driver_version *ver)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200515{
Jonny Svärda830f172021-06-07 16:57:00 +0200516 assert(ver != NULL);
517 ver->major = ETHOSU_DRIVER_VERSION_MAJOR;
518 ver->minor = ETHOSU_DRIVER_VERSION_MINOR;
519 ver->patch = ETHOSU_DRIVER_VERSION_PATCH;
520}
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200521
Jonny Svärda830f172021-06-07 16:57:00 +0200522void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw)
523{
524 assert(hw != NULL);
Jonny Svärd136810f2021-10-13 16:04:26 +0200525 ethosu_dev_get_hw_info(drv->dev, hw);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200526}
527
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100528int ethosu_wait(struct ethosu_driver *drv, bool block)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200529{
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100530 int ret = 0;
531
532 switch (drv->job.state)
533 {
534 case ETHOSU_JOB_IDLE:
535 LOG_ERR("Inference job not running...");
536 ret = -2;
537 break;
538 case ETHOSU_JOB_RUNNING:
539 if (!block)
540 {
541 // Inference still running, do not block
542 ret = 1;
543 break;
544 }
545 // fall through
546 case ETHOSU_JOB_DONE:
547 // Wait for interrupt in blocking mode. In non-blocking mode
548 // the interrupt has already triggered
Jonny Svärda2732ec2023-12-18 17:19:15 +0100549 ret = ethosu_semaphore_take(drv->semaphore, ETHOSU_SEMAPHORE_WAIT_INFERENCE);
550 if (ret < 0)
551 {
552 drv->job.result = ETHOSU_JOB_RESULT_TIMEOUT;
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100553
Jonny Svärda2732ec2023-12-18 17:19:15 +0100554 // There's a race where the NPU interrupt can have fired between semaphore
555 // timing out and setting the result above (checked in interrupt handler).
556 // By checking if the job state has been changed (only set to DONE by interrupt
557 // handler), we know if the interrupt handler has run, if so decrement the
558 // semaphore count by one (given in interrupt handler).
559 if (drv->job.state == ETHOSU_JOB_DONE)
560 {
561 drv->job.result = ETHOSU_JOB_RESULT_TIMEOUT; // Reset back to timeout
562 ethosu_semaphore_take(drv->semaphore, ETHOSU_SEMAPHORE_WAIT_INFERENCE);
563 }
564 }
565
566 // Inference done callback - always called even in case of timeout
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100567 ethosu_inference_end(drv, drv->job.user_arg);
568
Jonny Svärda2732ec2023-12-18 17:19:15 +0100569 // Release power gating disabled requirement
Jonny Svärd301399d2022-04-26 18:31:24 +0200570 ethosu_release_power(drv);
571
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100572 // Check NPU and interrupt status
Jonny Svärda2732ec2023-12-18 17:19:15 +0100573 if (drv->job.result)
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100574 {
Jonny Svärda2732ec2023-12-18 17:19:15 +0100575 if (drv->job.result == ETHOSU_JOB_RESULT_ERROR)
576 {
577 LOG_ERR("NPU error(s) occured during inference.");
578 ethosu_dev_print_err_status(drv->dev);
579 }
580 else
581 {
582 LOG_ERR("NPU inference timed out.");
583 }
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100584
585 // Reset the NPU
Jonny Svärd301399d2022-04-26 18:31:24 +0200586 (void)ethosu_soft_reset(drv);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100587
588 ret = -1;
589 }
Jonny Svärda2732ec2023-12-18 17:19:15 +0100590 else
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100591 {
592 // Invalidate cache
593 if (drv->job.base_addr_size != NULL)
594 {
595 for (int i = 0; i < drv->job.num_base_addr; i++)
596 {
597 ethosu_invalidate_dcache((uint32_t *)(uintptr_t)drv->job.base_addr[i], drv->job.base_addr_size[i]);
598 }
599 }
600 else
601 {
602 ethosu_invalidate_dcache(NULL, 0);
603 }
604
605 LOG_DEBUG("Inference finished successfully...");
Jonny Svärda2732ec2023-12-18 17:19:15 +0100606 ret = 0;
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100607 }
608
609 // Reset internal job (state resets to IDLE)
610 ethosu_reset_job(drv);
611 break;
612
613 default:
614 LOG_ERR("Unexpected job state");
615 ethosu_reset_job(drv);
616 ret = -1;
617 break;
618 }
619
620 // Return inference job status
621 return ret;
622}
623
624int ethosu_invoke_async(struct ethosu_driver *drv,
625 const void *custom_data_ptr,
626 const int custom_data_size,
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100627 uint64_t *const base_addr,
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100628 const size_t *base_addr_size,
629 const int num_base_addr,
630 void *user_arg)
631{
632
Jonny Svärd136810f2021-10-13 16:04:26 +0200633 const struct cop_data_s *data_ptr = custom_data_ptr;
Kristofer Jonsson24455ee2022-02-08 13:33:22 +0100634 const struct cop_data_s *data_end = (struct cop_data_s *)((ptrdiff_t)custom_data_ptr + custom_data_size);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100635
636 // Make sure an inference is not already running
637 if (drv->job.state != ETHOSU_JOB_IDLE)
638 {
639 LOG_ERR("Inference already running, or waiting to be cleared...");
640 return -1;
641 }
642
643 drv->job.state = ETHOSU_JOB_IDLE;
644 drv->job.custom_data_ptr = custom_data_ptr;
645 drv->job.custom_data_size = custom_data_size;
646 drv->job.base_addr = base_addr;
647 drv->job.base_addr_size = base_addr_size;
648 drv->job.num_base_addr = num_base_addr;
649 drv->job.user_arg = user_arg;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200650
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200651 // First word in custom_data_ptr should contain "Custom Operator Payload 1"
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200652 if (data_ptr->word != ETHOSU_FOURCC)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200653 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100654 LOG_ERR("Custom Operator Payload: %" PRIu32 " is not correct, expected %x", data_ptr->word, ETHOSU_FOURCC);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100655 goto err;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200656 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200657
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200658 // Custom data length must be a multiple of 32 bits
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200659 if ((custom_data_size % BYTES_IN_32_BITS) != 0)
660 {
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100661 LOG_ERR("custom_data_size=0x%x not a multiple of 4", (unsigned)custom_data_size);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100662 goto err;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200663 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200664
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100665 data_ptr++;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200666
667 // Adjust base address to fast memory area
Anton Moberg61da4d32020-12-22 16:00:31 +0100668 if (drv->fast_memory != 0 && num_base_addr >= FAST_MEMORY_BASE_ADDR_INDEX)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200669 {
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200670
Anton Moberg61da4d32020-12-22 16:00:31 +0100671 if (base_addr_size != NULL && base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > drv->fast_memory_size)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200672 {
Rajasekaran Kalidoss2fa2bf02024-04-22 09:11:02 +0200673 LOG_ERR("Fast memory area too small. fast_memory_size=%zu, base_addr_size=%zu",
Anton Moberg61da4d32020-12-22 16:00:31 +0100674 drv->fast_memory_size,
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100675 base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX]);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100676 goto err;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200677 }
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100678
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100679 base_addr[FAST_MEMORY_BASE_ADDR_INDEX] = drv->fast_memory;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200680 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200681
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100682 // Parse Custom Operator Payload data
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200683 while (data_ptr < data_end)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200684 {
685 switch (data_ptr->driver_action_command)
686 {
687 case OPTIMIZER_CONFIG:
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100688 LOG_DEBUG("OPTIMIZER_CONFIG");
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100689 struct opt_cfg_s const *opt_cfg_p = (const struct opt_cfg_s *)data_ptr;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200690
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100691 if (handle_optimizer_config(drv, opt_cfg_p) < 0)
692 {
693 goto err;
694 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200695 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD;
696 break;
697 case COMMAND_STREAM:
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100698 // Vela only supports putting one COMMAND_STREAM per op
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100699 LOG_DEBUG("COMMAND_STREAM");
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100700 const uint8_t *command_stream = (const uint8_t *)(data_ptr + 1);
701 int cms_length = (data_ptr->reserved << 16) | data_ptr->length;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200702
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100703 if (handle_command_stream(drv, command_stream, cms_length) < 0)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200704 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100705 goto err;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200706 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200707 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + cms_length;
708 break;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200709 case NOP:
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100710 LOG_DEBUG("NOP");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200711 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
712 break;
713 default:
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100714 LOG_ERR("UNSUPPORTED driver_action_command: %u", data_ptr->driver_action_command);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100715 goto err;
Bhavik Patele645fed2020-06-12 14:46:47 +0200716 break;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200717 }
718 }
Jonny Svärd136810f2021-10-13 16:04:26 +0200719
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100720 return 0;
721err:
722 LOG_ERR("Failed to invoke inference.");
723 ethosu_reset_job(drv);
724 return -1;
725}
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200726
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100727int ethosu_invoke_v3(struct ethosu_driver *drv,
728 const void *custom_data_ptr,
729 const int custom_data_size,
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100730 uint64_t *const base_addr,
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100731 const size_t *base_addr_size,
732 const int num_base_addr,
733 void *user_arg)
734{
735 if (ethosu_invoke_async(
736 drv, custom_data_ptr, custom_data_size, base_addr, base_addr_size, num_base_addr, user_arg) < 0)
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200737 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100738 return -1;
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200739 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200740
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100741 return ethosu_wait(drv, true);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200742}
743
Anton Moberg61da4d32020-12-22 16:00:31 +0100744struct ethosu_driver *ethosu_reserve_driver(void)
745{
Anton Mobergdf386e02021-02-02 11:26:48 +0100746 struct ethosu_driver *drv = NULL;
747
Jonny Svärdc9644242023-01-09 15:54:24 +0100748 LOG_INFO("Acquiring NPU driver handle");
Jonny Svärda2732ec2023-12-18 17:19:15 +0100749 ethosu_semaphore_take(ethosu_semaphore, ETHOSU_SEMAPHORE_WAIT_FOREVER); // This is meant to block until available
Anton Mobergdf386e02021-02-02 11:26:48 +0100750
Jonny Svärdc9644242023-01-09 15:54:24 +0100751 ethosu_mutex_lock(ethosu_mutex);
752 drv = registered_drivers;
753
754 while (drv != NULL)
755 {
756 if (!drv->reserved)
Anton Mobergdf386e02021-02-02 11:26:48 +0100757 {
Jonny Svärdc9644242023-01-09 15:54:24 +0100758 drv->reserved = true;
759 LOG_DEBUG("NPU driver handle %p reserved", drv);
Anton Mobergdf386e02021-02-02 11:26:48 +0100760 break;
761 }
Jonny Svärdc9644242023-01-09 15:54:24 +0100762 drv = drv->next;
763 }
764 ethosu_mutex_unlock(ethosu_mutex);
Anton Mobergdf386e02021-02-02 11:26:48 +0100765
Jonny Svärdc9644242023-01-09 15:54:24 +0100766 if (!drv)
767 {
768 LOG_ERR("No NPU driver handle available, but semaphore taken");
769 }
Anton Mobergdf386e02021-02-02 11:26:48 +0100770
771 return drv;
772}
773
Anton Moberg61da4d32020-12-22 16:00:31 +0100774void ethosu_release_driver(struct ethosu_driver *drv)
775{
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100776 ethosu_mutex_lock(ethosu_mutex);
Anton Moberg61da4d32020-12-22 16:00:31 +0100777 if (drv != NULL && drv->reserved)
778 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100779 if (drv->job.state == ETHOSU_JOB_RUNNING || drv->job.state == ETHOSU_JOB_DONE)
780 {
781 // Give the inference one shot to complete or force kill the job
782 if (ethosu_wait(drv, false) == 1)
783 {
784 // Still running, soft reset the NPU and reset driver
Jonny Svärd301399d2022-04-26 18:31:24 +0200785 drv->power_request_counter = 0;
786 ethosu_soft_reset(drv);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100787 ethosu_reset_job(drv);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100788 }
789 }
790
Anton Moberg61da4d32020-12-22 16:00:31 +0100791 drv->reserved = false;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100792 LOG_DEBUG("NPU driver handle %p released", drv);
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100793 ethosu_semaphore_give(ethosu_semaphore);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100794 }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100795 ethosu_mutex_unlock(ethosu_mutex);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100796}