blob: 8fac9362d000821d15b4c26a0b151e2a5af7d9d9 [file] [log] [blame]
Kristofer Jonsson49bdee82020-04-06 13:21:21 +02001/*
Jonny Svärdc9644242023-01-09 15:54:24 +01002 * SPDX-FileCopyrightText: Copyright 2019-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
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_device.h"
Anton Moberg6eab40b2021-07-07 11:43:51 +020025#include "ethosu_log.h"
Per Åstrand25d78c02020-04-21 14:19:44 +020026
Kristofer Jonsson1c0e7ae2022-05-12 11:35:33 +020027#ifdef ETHOSU55
28#include "ethosu_config_u55.h"
29#else
30#include "ethosu_config_u65.h"
31#endif
32
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020033#include <assert.h>
Per Åstrand25d78c02020-04-21 14:19:44 +020034#include <cmsis_compiler.h>
Per Åstrand14ccfee2020-09-25 10:40:20 +020035#include <inttypes.h>
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020036#include <stdbool.h>
Bhavik Patelbf7ae632020-06-11 21:00:16 +020037#include <stddef.h>
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020038#include <stdio.h>
39#include <stdlib.h>
40
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020041/******************************************************************************
42 * Defines
43 ******************************************************************************/
44
Jonny Svärd136810f2021-10-13 16:04:26 +020045#define UNUSED(x) ((void)x)
46
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020047#define BYTES_IN_32_BITS 4
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020048#define MASK_16_BYTE_ALIGN (0xF)
Jonny Svärd136810f2021-10-13 16:04:26 +020049#define OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD 2
50#define DRIVER_ACTION_LENGTH_32_BIT_WORD 1
51#define ETHOSU_FOURCC ('1' << 24 | 'P' << 16 | 'O' << 8 | 'C') // "Custom Operator Payload 1"
52
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020053#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,
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020065 NOP = 5,
66};
67
Jonny Svärd136810f2021-10-13 16:04:26 +020068// Custom operator payload data struct
69struct cop_data_s
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020070{
71 union
72 {
73 // Driver action data
74 struct
75 {
Jonny Svärd136810f2021-10-13 16:04:26 +020076 uint8_t driver_action_command; // (valid values in DRIVER_ACTION_e)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020077 uint8_t reserved;
78
79 // Driver action data
80 union
81 {
82 // DA_CMD_OPT_CFG
83 struct
84 {
85 uint16_t rel_nbr : 4;
86 uint16_t patch_nbr : 4;
87 uint16_t opt_cfg_reserved : 8;
88 };
89
90 // DA_CMD_CMSTRM
91 struct
92 {
93 uint16_t length;
94 };
95
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020096 uint16_t driver_action_data;
97 };
98 };
99
100 uint32_t word;
101 };
102};
103
104// optimizer config struct
105struct opt_cfg_s
106{
Jonny Svärd136810f2021-10-13 16:04:26 +0200107 struct cop_data_s da_data;
108 uint32_t cfg;
109 uint32_t id;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200110};
111
112/******************************************************************************
Jonny Svärda830f172021-06-07 16:57:00 +0200113 * Variables
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200114 ******************************************************************************/
115
Anton Moberg61da4d32020-12-22 16:00:31 +0100116// Registered drivers linked list HEAD
117static struct ethosu_driver *registered_drivers = NULL;
118
Jonny Svärda830f172021-06-07 16:57:00 +0200119/******************************************************************************
120 * Weak functions - Cache
121 *
122 * Default NOP operations. Override if available on the targeted device.
123 ******************************************************************************/
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100124
Jonny Svärda830f172021-06-07 16:57:00 +0200125/*
126 * Flush/clean the data cache by address and size. Passing NULL as p argument
127 * expects the whole cache to be flushed.
128 */
129void __attribute__((weak)) ethosu_flush_dcache(uint32_t *p, size_t bytes)
130{
131 UNUSED(p);
132 UNUSED(bytes);
133}
134
135/*
136 * Invalidate the data cache by address and size. Passing NULL as p argument
137 * expects the whole cache to be invalidated.
138 */
139void __attribute__((weak)) ethosu_invalidate_dcache(uint32_t *p, size_t bytes)
140{
141 UNUSED(p);
142 UNUSED(bytes);
143}
144
145/******************************************************************************
146 * Weak functions - Semaphore/Mutex for multi NPU
147 *
148 * Following section handles the minimal sempahore and mutex implementation in
149 * case of baremetal applications. Weak symbols will be overridden by RTOS
150 * definitions and implement true thread-safety (in application layer).
151 ******************************************************************************/
152
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100153struct ethosu_semaphore_t
154{
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100155 uint8_t count;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100156};
157
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100158static void *ethosu_mutex;
159static void *ethosu_semaphore;
160
Anton Moberg9f346ab2021-05-21 17:20:21 +0200161void *__attribute__((weak)) ethosu_mutex_create(void)
162{
163 return NULL;
164}
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
Ledion Dajac6505f32022-04-20 09:55:21 +0200200int __attribute__((weak)) ethosu_semaphore_take(void *sem)
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100201{
202 struct ethosu_semaphore_t *s = sem;
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100203 while (s->count == 0)
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100204 {
205 __WFE();
206 }
Jonny Svärdc9644242023-01-09 15:54:24 +0100207 s->count--;
Ledion Dajac6505f32022-04-20 09:55:21 +0200208 return 0;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100209}
210
211// Baremetal simulation of giving a semaphore and waking up processes using intrinsics
Ledion Dajac6505f32022-04-20 09:55:21 +0200212int __attribute__((weak)) ethosu_semaphore_give(void *sem)
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100213{
214 struct ethosu_semaphore_t *s = sem;
Jonny Svärdc9644242023-01-09 15:54:24 +0100215 s->count++;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100216 __SEV();
Ledion Dajac6505f32022-04-20 09:55:21 +0200217 return 0;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100218}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100219
Jonny Svärda830f172021-06-07 16:57:00 +0200220/******************************************************************************
221 * Weak functions - Inference begin/end callbacks
222 ******************************************************************************/
Anton Moberg61da4d32020-12-22 16:00:31 +0100223
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100224void __attribute__((weak)) ethosu_inference_begin(struct ethosu_driver *drv, void *user_arg)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200225{
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100226 UNUSED(user_arg);
Jonny Svärda830f172021-06-07 16:57:00 +0200227 UNUSED(drv);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200228}
229
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100230void __attribute__((weak)) ethosu_inference_end(struct ethosu_driver *drv, void *user_arg)
Jonny Svärda830f172021-06-07 16:57:00 +0200231{
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100232 UNUSED(user_arg);
Jonny Svärda830f172021-06-07 16:57:00 +0200233 UNUSED(drv);
234}
235
236/******************************************************************************
237 * Static functions
238 ******************************************************************************/
Jonny Svärda830f172021-06-07 16:57:00 +0200239static void ethosu_register_driver(struct ethosu_driver *drv)
Jens Elofsson04961a42021-04-08 18:51:38 +0200240{
Jonny Svärdc9644242023-01-09 15:54:24 +0100241 ethosu_mutex_lock(ethosu_mutex);
Jonny Svärda830f172021-06-07 16:57:00 +0200242 drv->next = registered_drivers;
243 registered_drivers = drv;
Jonny Svärdc9644242023-01-09 15:54:24 +0100244 ethosu_mutex_unlock(ethosu_mutex);
245
246 ethosu_semaphore_give(ethosu_semaphore);
Jonny Svärda830f172021-06-07 16:57:00 +0200247
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100248 LOG_INFO("New NPU driver registered (handle: 0x%p, NPU: 0x%p)", drv, drv->dev->reg);
Jens Elofsson04961a42021-04-08 18:51:38 +0200249}
250
Jonny Svärda830f172021-06-07 16:57:00 +0200251static int ethosu_deregister_driver(struct ethosu_driver *drv)
252{
Jonny Svärdc9644242023-01-09 15:54:24 +0100253 struct ethosu_driver *curr;
254 struct ethosu_driver **prev;
Jonny Svärda830f172021-06-07 16:57:00 +0200255
Jonny Svärdc9644242023-01-09 15:54:24 +0100256 ethosu_mutex_lock(ethosu_mutex);
257 curr = registered_drivers;
258 prev = &registered_drivers;
259
260 while (curr != NULL)
Jonny Svärda830f172021-06-07 16:57:00 +0200261 {
Jonny Svärdc9644242023-01-09 15:54:24 +0100262 if (curr == drv)
Jonny Svärda830f172021-06-07 16:57:00 +0200263 {
Jonny Svärdc9644242023-01-09 15:54:24 +0100264 *prev = curr->next;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100265 LOG_INFO("NPU driver handle %p deregistered.", drv);
Jonny Svärdc9644242023-01-09 15:54:24 +0100266 ethosu_semaphore_take(ethosu_semaphore);
267 break;
Jonny Svärda830f172021-06-07 16:57:00 +0200268 }
269
Jonny Svärdc9644242023-01-09 15:54:24 +0100270 prev = &curr->next;
271 curr = curr->next;
Jonny Svärda830f172021-06-07 16:57:00 +0200272 }
273
Jonny Svärdc9644242023-01-09 15:54:24 +0100274 ethosu_mutex_unlock(ethosu_mutex);
Jonny Svärda830f172021-06-07 16:57:00 +0200275
Jonny Svärdc9644242023-01-09 15:54:24 +0100276 if (curr == NULL)
Jonny Svärda830f172021-06-07 16:57:00 +0200277 {
Jonny Svärdc9644242023-01-09 15:54:24 +0100278 LOG_ERR("No NPU driver handle registered at address %p.", drv);
279 return -1;
Jonny Svärda830f172021-06-07 16:57:00 +0200280 }
281
Jonny Svärdc9644242023-01-09 15:54:24 +0100282 return 0;
Jonny Svärda830f172021-06-07 16:57:00 +0200283}
284
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100285static void ethosu_reset_job(struct ethosu_driver *drv)
286{
287 memset(&drv->job, 0, sizeof(struct ethosu_job));
288}
289
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100290static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s const *opt_cfg_p)
Jonny Svärda830f172021-06-07 16:57:00 +0200291{
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100292 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 +0200293
Jonny Svärd136810f2021-10-13 16:04:26 +0200294 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 +0200295 {
296 return -1;
297 }
298
Jonny Svärda830f172021-06-07 16:57:00 +0200299 return 0;
300}
301
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100302static 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 +0200303{
Jonny Svärda830f172021-06-07 16:57:00 +0200304 uint32_t cms_bytes = cms_length * BYTES_IN_32_BITS;
305 ptrdiff_t cmd_stream_ptr = (ptrdiff_t)cmd_stream;
306
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100307 LOG_INFO("handle_command_stream: cmd_stream=%p, cms_length %d", cmd_stream, cms_length);
Jonny Svärda830f172021-06-07 16:57:00 +0200308
309 if (0 != ((ptrdiff_t)cmd_stream & MASK_16_BYTE_ALIGN))
310 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100311 LOG_ERR("Command stream addr %p not aligned to 16 bytes", cmd_stream);
Jonny Svärda830f172021-06-07 16:57:00 +0200312 return -1;
313 }
314
Jonny Svärd136810f2021-10-13 16:04:26 +0200315 // Verify 16 byte alignment for base address'
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100316 for (int i = 0; i < drv->job.num_base_addr; i++)
Jonny Svärda830f172021-06-07 16:57:00 +0200317 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100318 if (0 != (drv->job.base_addr[i] & MASK_16_BYTE_ALIGN))
Jonny Svärda830f172021-06-07 16:57:00 +0200319 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100320 LOG_ERR("Base addr %d: 0x%llx not aligned to 16 bytes", i, drv->job.base_addr[i]);
Jonny Svärd136810f2021-10-13 16:04:26 +0200321 return -1;
Jonny Svärda830f172021-06-07 16:57:00 +0200322 }
323 }
324
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100325 // Flush the cache if available on CPU.
326 // The upcasting to uin32_t* is ok since the pointer never is dereferenced.
327 // The base_addr_size is null if invoking from prior to invoke_V2, in that case
328 // the whole cache is being flushed.
329
330 if (drv->job.base_addr_size != NULL)
Jonny Svärda830f172021-06-07 16:57:00 +0200331 {
332 ethosu_flush_dcache((uint32_t *)cmd_stream_ptr, cms_bytes);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100333 for (int i = 0; i < drv->job.num_base_addr; i++)
Jonny Svärda830f172021-06-07 16:57:00 +0200334 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100335 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 +0200336 }
337 }
338 else
339 {
340 ethosu_flush_dcache(NULL, 0);
341 }
342
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100343 // Request power gating disabled during inference run
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100344 if (ethosu_request_power(drv))
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100345 {
Jonny Svärd301399d2022-04-26 18:31:24 +0200346 LOG_ERR("Failed to request power");
347 return -1;
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100348 }
349
Jonny Svärd301399d2022-04-26 18:31:24 +0200350 drv->job.state = ETHOSU_JOB_RUNNING;
351
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100352 // Inference begin callback
353 ethosu_inference_begin(drv, drv->job.user_arg);
354
Jonny Svärd136810f2021-10-13 16:04:26 +0200355 // Execute the command stream
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100356 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 +0200357
Jonny Svärda830f172021-06-07 16:57:00 +0200358 return 0;
359}
360
361/******************************************************************************
362 * Weak functions - Interrupt handler
363 ******************************************************************************/
364void __attribute__((weak)) ethosu_irq_handler(struct ethosu_driver *drv)
365{
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100366 LOG_DEBUG("Got interrupt from Ethos-U");
Jonny Svärda830f172021-06-07 16:57:00 +0200367
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100368 drv->job.state = ETHOSU_JOB_DONE;
Jonny Svärd136810f2021-10-13 16:04:26 +0200369 if (!ethosu_dev_handle_interrupt(drv->dev))
Jonny Svärda830f172021-06-07 16:57:00 +0200370 {
Jonny Svärda830f172021-06-07 16:57:00 +0200371 drv->status_error = true;
372 }
Jonny Svärda830f172021-06-07 16:57:00 +0200373 ethosu_semaphore_give(drv->semaphore);
374}
375
376/******************************************************************************
377 * Functions API
378 ******************************************************************************/
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200379
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200380int ethosu_init(struct ethosu_driver *drv,
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100381 void *const base_address,
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200382 const void *fast_memory,
383 const size_t fast_memory_size,
384 uint32_t secure_enable,
385 uint32_t privilege_enable)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200386{
Jonny Svärda830f172021-06-07 16:57:00 +0200387 LOG_INFO("Initializing NPU: base_address=%p, fast_memory=%p, fast_memory_size=%zu, secure=%" PRIu32
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100388 ", privileged=%" PRIu32,
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200389 base_address,
390 fast_memory,
Per Åstrande6498f02020-11-09 15:33:12 +0100391 fast_memory_size,
392 secure_enable,
393 privilege_enable);
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200394
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100395 if (!ethosu_mutex)
396 {
397 ethosu_mutex = ethosu_mutex_create();
398 }
399
400 if (!ethosu_semaphore)
401 {
402 ethosu_semaphore = ethosu_semaphore_create();
Jonny Svärdc9644242023-01-09 15:54:24 +0100403 if (!ethosu_semaphore)
404 {
405 LOG_ERR("Failed to create global driver semaphore");
406 return -1;
407 }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100408 }
409
Jonny Svärd301399d2022-04-26 18:31:24 +0200410 drv->fast_memory = (uint32_t)fast_memory;
411 drv->fast_memory_size = fast_memory_size;
412 drv->power_request_counter = 0;
Anton Moberg61da4d32020-12-22 16:00:31 +0100413
Jonny Svärd136810f2021-10-13 16:04:26 +0200414 // Initialize the device and set requested security state and privilege mode
415 drv->dev = ethosu_dev_init(base_address, secure_enable, privilege_enable);
416
417 if (drv->dev == NULL)
Bhavik Pateldae5be02020-06-18 15:25:15 +0200418 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100419 LOG_ERR("Failed to initialize Ethos-U device");
Bhavik Pateldae5be02020-06-18 15:25:15 +0200420 return -1;
421 }
422
Jonny Svärdc9644242023-01-09 15:54:24 +0100423 drv->semaphore = ethosu_semaphore_create();
424 if (!drv->semaphore)
425 {
426 LOG_ERR("Failed to create driver semaphore");
427 ethosu_dev_deinit(drv->dev);
428 drv->dev = NULL;
429 return -1;
430 }
431
Anton Moberg61da4d32020-12-22 16:00:31 +0100432 drv->status_error = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200433
Jonny Svärd301399d2022-04-26 18:31:24 +0200434 ethosu_reset_job(drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200435 ethosu_register_driver(drv);
436
Jonny Svärd136810f2021-10-13 16:04:26 +0200437 return 0;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200438}
439
Anton Moberg547ca532021-06-14 09:43:53 +0200440void ethosu_deinit(struct ethosu_driver *drv)
441{
442 ethosu_deregister_driver(drv);
Jonny Svärd136810f2021-10-13 16:04:26 +0200443 ethosu_semaphore_destroy(drv->semaphore);
444 ethosu_dev_deinit(drv->dev);
445 drv->dev = NULL;
Anton Moberg547ca532021-06-14 09:43:53 +0200446}
447
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100448int ethosu_soft_reset(struct ethosu_driver *drv)
Jonny Svärd301399d2022-04-26 18:31:24 +0200449{
450 // Soft reset the NPU
451 if (ethosu_dev_soft_reset(drv->dev) != ETHOSU_SUCCESS)
452 {
453 LOG_ERR("Failed to soft-reset NPU");
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100454 return -1;
Jonny Svärd301399d2022-04-26 18:31:24 +0200455 }
456
457 // Update power and clock gating after the soft reset
458 ethosu_dev_set_clock_and_power(drv->dev,
459 drv->power_request_counter > 0 ? ETHOSU_CLOCK_Q_DISABLE : ETHOSU_CLOCK_Q_ENABLE,
460 drv->power_request_counter > 0 ? ETHOSU_POWER_Q_DISABLE : ETHOSU_POWER_Q_ENABLE);
461
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100462 return 0;
Jonny Svärd301399d2022-04-26 18:31:24 +0200463}
464
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100465int ethosu_request_power(struct ethosu_driver *drv)
Jonny Svärd301399d2022-04-26 18:31:24 +0200466{
467 // Check if this is the first power request, increase counter
468 if (drv->power_request_counter++ == 0)
469 {
470 // Always reset to a known state. Changes to requested
471 // security state/privilege mode if necessary.
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100472 if (ethosu_soft_reset(drv))
Jonny Svärd301399d2022-04-26 18:31:24 +0200473 {
474 LOG_ERR("Failed to request power for Ethos-U");
475 drv->power_request_counter--;
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100476 return -1;
Jonny Svärd301399d2022-04-26 18:31:24 +0200477 }
478 }
Kristofer Jonsson68b5c912022-11-14 10:52:38 +0100479 return 0;
Jonny Svärd301399d2022-04-26 18:31:24 +0200480}
481
482void ethosu_release_power(struct ethosu_driver *drv)
483{
484 if (drv->power_request_counter == 0)
485 {
486 LOG_WARN("No power request left to release, reference counter is 0");
487 }
488 else
489 {
490 // Decrement ref counter and enable power gating if no requests remain
491 if (--drv->power_request_counter == 0)
492 {
493 ethosu_dev_set_clock_and_power(drv->dev, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
494 }
495 }
496}
497
Jonny Svärda830f172021-06-07 16:57:00 +0200498void ethosu_get_driver_version(struct ethosu_driver_version *ver)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200499{
Jonny Svärda830f172021-06-07 16:57:00 +0200500 assert(ver != NULL);
501 ver->major = ETHOSU_DRIVER_VERSION_MAJOR;
502 ver->minor = ETHOSU_DRIVER_VERSION_MINOR;
503 ver->patch = ETHOSU_DRIVER_VERSION_PATCH;
504}
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200505
Jonny Svärda830f172021-06-07 16:57:00 +0200506void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw)
507{
508 assert(hw != NULL);
Jonny Svärd136810f2021-10-13 16:04:26 +0200509 ethosu_dev_get_hw_info(drv->dev, hw);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200510}
511
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100512int ethosu_wait(struct ethosu_driver *drv, bool block)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200513{
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100514 int ret = 0;
515
516 switch (drv->job.state)
517 {
518 case ETHOSU_JOB_IDLE:
519 LOG_ERR("Inference job not running...");
520 ret = -2;
521 break;
522 case ETHOSU_JOB_RUNNING:
523 if (!block)
524 {
525 // Inference still running, do not block
526 ret = 1;
527 break;
528 }
529 // fall through
530 case ETHOSU_JOB_DONE:
531 // Wait for interrupt in blocking mode. In non-blocking mode
532 // the interrupt has already triggered
533 ethosu_semaphore_take(drv->semaphore);
534
535 // Inference done callback
536 ethosu_inference_end(drv, drv->job.user_arg);
537
Jonny Svärd301399d2022-04-26 18:31:24 +0200538 // Relase power gating disabled requirement
539 ethosu_release_power(drv);
540
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100541 // Check NPU and interrupt status
542 if (drv->status_error)
543 {
544 LOG_ERR("NPU error(s) occured during inference.");
545 ethosu_dev_print_err_status(drv->dev);
546
547 // Reset the NPU
Jonny Svärd301399d2022-04-26 18:31:24 +0200548 (void)ethosu_soft_reset(drv);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100549 // NPU is no longer in error state
550 drv->status_error = false;
551
552 ret = -1;
553 }
554
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100555 if (ret == 0)
556 {
557 // Invalidate cache
558 if (drv->job.base_addr_size != NULL)
559 {
560 for (int i = 0; i < drv->job.num_base_addr; i++)
561 {
562 ethosu_invalidate_dcache((uint32_t *)(uintptr_t)drv->job.base_addr[i], drv->job.base_addr_size[i]);
563 }
564 }
565 else
566 {
567 ethosu_invalidate_dcache(NULL, 0);
568 }
569
570 LOG_DEBUG("Inference finished successfully...");
571 }
572
573 // Reset internal job (state resets to IDLE)
574 ethosu_reset_job(drv);
575 break;
576
577 default:
578 LOG_ERR("Unexpected job state");
579 ethosu_reset_job(drv);
580 ret = -1;
581 break;
582 }
583
584 // Return inference job status
585 return ret;
586}
587
588int ethosu_invoke_async(struct ethosu_driver *drv,
589 const void *custom_data_ptr,
590 const int custom_data_size,
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100591 uint64_t *const base_addr,
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100592 const size_t *base_addr_size,
593 const int num_base_addr,
594 void *user_arg)
595{
596
Jonny Svärd136810f2021-10-13 16:04:26 +0200597 const struct cop_data_s *data_ptr = custom_data_ptr;
Kristofer Jonsson24455ee2022-02-08 13:33:22 +0100598 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 +0100599
600 // Make sure an inference is not already running
601 if (drv->job.state != ETHOSU_JOB_IDLE)
602 {
603 LOG_ERR("Inference already running, or waiting to be cleared...");
604 return -1;
605 }
606
607 drv->job.state = ETHOSU_JOB_IDLE;
608 drv->job.custom_data_ptr = custom_data_ptr;
609 drv->job.custom_data_size = custom_data_size;
610 drv->job.base_addr = base_addr;
611 drv->job.base_addr_size = base_addr_size;
612 drv->job.num_base_addr = num_base_addr;
613 drv->job.user_arg = user_arg;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200614
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200615 // First word in custom_data_ptr should contain "Custom Operator Payload 1"
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200616 if (data_ptr->word != ETHOSU_FOURCC)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200617 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100618 LOG_ERR("Custom Operator Payload: %" PRIu32 " is not correct, expected %x", data_ptr->word, ETHOSU_FOURCC);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100619 goto err;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200620 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200621
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200622 // Custom data length must be a multiple of 32 bits
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200623 if ((custom_data_size % BYTES_IN_32_BITS) != 0)
624 {
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100625 LOG_ERR("custom_data_size=0x%x not a multiple of 4", (unsigned)custom_data_size);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100626 goto err;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200627 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200628
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100629 data_ptr++;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200630
631 // Adjust base address to fast memory area
Anton Moberg61da4d32020-12-22 16:00:31 +0100632 if (drv->fast_memory != 0 && num_base_addr >= FAST_MEMORY_BASE_ADDR_INDEX)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200633 {
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200634
Anton Moberg61da4d32020-12-22 16:00:31 +0100635 if (base_addr_size != NULL && base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > drv->fast_memory_size)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200636 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100637 LOG_ERR("Fast memory area too small. fast_memory_size=%u, base_addr_size=%u",
Anton Moberg61da4d32020-12-22 16:00:31 +0100638 drv->fast_memory_size,
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100639 base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX]);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100640 goto err;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200641 }
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100642
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100643 base_addr[FAST_MEMORY_BASE_ADDR_INDEX] = drv->fast_memory;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200644 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200645
Anton Moberg61da4d32020-12-22 16:00:31 +0100646 drv->status_error = false;
Kristofer Jonsson125429a2020-08-20 16:52:23 +0200647
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100648 // Parse Custom Operator Payload data
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200649 while (data_ptr < data_end)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200650 {
651 switch (data_ptr->driver_action_command)
652 {
653 case OPTIMIZER_CONFIG:
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100654 LOG_DEBUG("OPTIMIZER_CONFIG");
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100655 struct opt_cfg_s const *opt_cfg_p = (const struct opt_cfg_s *)data_ptr;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200656
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100657 if (handle_optimizer_config(drv, opt_cfg_p) < 0)
658 {
659 goto err;
660 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200661 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD;
662 break;
663 case COMMAND_STREAM:
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100664 // Vela only supports putting one COMMAND_STREAM per op
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100665 LOG_DEBUG("COMMAND_STREAM");
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100666 const uint8_t *command_stream = (const uint8_t *)(data_ptr + 1);
667 int cms_length = (data_ptr->reserved << 16) | data_ptr->length;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200668
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100669 if (handle_command_stream(drv, command_stream, cms_length) < 0)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200670 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100671 goto err;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200672 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200673 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + cms_length;
674 break;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200675 case NOP:
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100676 LOG_DEBUG("NOP");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200677 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
678 break;
679 default:
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100680 LOG_ERR("UNSUPPORTED driver_action_command: %u", data_ptr->driver_action_command);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100681 goto err;
Bhavik Patele645fed2020-06-12 14:46:47 +0200682 break;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200683 }
684 }
Jonny Svärd136810f2021-10-13 16:04:26 +0200685
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100686 return 0;
687err:
688 LOG_ERR("Failed to invoke inference.");
689 ethosu_reset_job(drv);
690 return -1;
691}
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200692
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100693int ethosu_invoke_v3(struct ethosu_driver *drv,
694 const void *custom_data_ptr,
695 const int custom_data_size,
Ledion Dajaecdce6c2023-01-16 15:39:29 +0100696 uint64_t *const base_addr,
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100697 const size_t *base_addr_size,
698 const int num_base_addr,
699 void *user_arg)
700{
701 if (ethosu_invoke_async(
702 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 +0200703 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100704 return -1;
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200705 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200706
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100707 return ethosu_wait(drv, true);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200708}
709
Anton Moberg61da4d32020-12-22 16:00:31 +0100710struct ethosu_driver *ethosu_reserve_driver(void)
711{
Anton Mobergdf386e02021-02-02 11:26:48 +0100712 struct ethosu_driver *drv = NULL;
713
Jonny Svärdc9644242023-01-09 15:54:24 +0100714 LOG_INFO("Acquiring NPU driver handle");
715 ethosu_semaphore_take(ethosu_semaphore); // This is meant to block until available
Anton Mobergdf386e02021-02-02 11:26:48 +0100716
Jonny Svärdc9644242023-01-09 15:54:24 +0100717 ethosu_mutex_lock(ethosu_mutex);
718 drv = registered_drivers;
719
720 while (drv != NULL)
721 {
722 if (!drv->reserved)
Anton Mobergdf386e02021-02-02 11:26:48 +0100723 {
Jonny Svärdc9644242023-01-09 15:54:24 +0100724 drv->reserved = true;
725 LOG_DEBUG("NPU driver handle %p reserved", drv);
Anton Mobergdf386e02021-02-02 11:26:48 +0100726 break;
727 }
Jonny Svärdc9644242023-01-09 15:54:24 +0100728 drv = drv->next;
729 }
730 ethosu_mutex_unlock(ethosu_mutex);
Anton Mobergdf386e02021-02-02 11:26:48 +0100731
Jonny Svärdc9644242023-01-09 15:54:24 +0100732 if (!drv)
733 {
734 LOG_ERR("No NPU driver handle available, but semaphore taken");
735 }
Anton Mobergdf386e02021-02-02 11:26:48 +0100736
737 return drv;
738}
739
Anton Moberg61da4d32020-12-22 16:00:31 +0100740void ethosu_release_driver(struct ethosu_driver *drv)
741{
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100742 ethosu_mutex_lock(ethosu_mutex);
Anton Moberg61da4d32020-12-22 16:00:31 +0100743 if (drv != NULL && drv->reserved)
744 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100745 if (drv->job.state == ETHOSU_JOB_RUNNING || drv->job.state == ETHOSU_JOB_DONE)
746 {
747 // Give the inference one shot to complete or force kill the job
748 if (ethosu_wait(drv, false) == 1)
749 {
750 // Still running, soft reset the NPU and reset driver
Jonny Svärd301399d2022-04-26 18:31:24 +0200751 drv->power_request_counter = 0;
752 ethosu_soft_reset(drv);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100753 ethosu_reset_job(drv);
754 drv->status_error = false;
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100755 }
756 }
757
Anton Moberg61da4d32020-12-22 16:00:31 +0100758 drv->reserved = false;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100759 LOG_DEBUG("NPU driver handle %p released", drv);
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100760 ethosu_semaphore_give(ethosu_semaphore);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100761 }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100762 ethosu_mutex_unlock(ethosu_mutex);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100763}