blob: 91759918ff3b8edad7566325c2fd52a59706a2fb [file] [log] [blame]
Kristofer Jonsson49bdee82020-04-06 13:21:21 +02001/*
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +01002 * Copyright (c) 2019-2022 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"
Bhavik Pateldae5be02020-06-18 15:25:15 +020024#include "ethosu_config.h"
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020025#include "ethosu_device.h"
Anton Moberg6eab40b2021-07-07 11:43:51 +020026#include "ethosu_log.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
Jonny Svärd136810f2021-10-13 16:04:26 +020040#define UNUSED(x) ((void)x)
41
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020042#define BYTES_IN_32_BITS 4
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020043#define MASK_16_BYTE_ALIGN (0xF)
Jonny Svärd136810f2021-10-13 16:04:26 +020044#define OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD 2
45#define DRIVER_ACTION_LENGTH_32_BIT_WORD 1
46#define ETHOSU_FOURCC ('1' << 24 | 'P' << 16 | 'O' << 8 | 'C') // "Custom Operator Payload 1"
47
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020048#define FAST_MEMORY_BASE_ADDR_INDEX 2
49
50/******************************************************************************
51 * Types
52 ******************************************************************************/
53
54// Driver actions
55enum DRIVER_ACTION_e
56{
57 RESERVED = 0,
58 OPTIMIZER_CONFIG = 1,
59 COMMAND_STREAM = 2,
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020060 NOP = 5,
61};
62
Jonny Svärd136810f2021-10-13 16:04:26 +020063// Custom operator payload data struct
64struct cop_data_s
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020065{
66 union
67 {
68 // Driver action data
69 struct
70 {
Jonny Svärd136810f2021-10-13 16:04:26 +020071 uint8_t driver_action_command; // (valid values in DRIVER_ACTION_e)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020072 uint8_t reserved;
73
74 // Driver action data
75 union
76 {
77 // DA_CMD_OPT_CFG
78 struct
79 {
80 uint16_t rel_nbr : 4;
81 uint16_t patch_nbr : 4;
82 uint16_t opt_cfg_reserved : 8;
83 };
84
85 // DA_CMD_CMSTRM
86 struct
87 {
88 uint16_t length;
89 };
90
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020091 uint16_t driver_action_data;
92 };
93 };
94
95 uint32_t word;
96 };
97};
98
99// optimizer config struct
100struct opt_cfg_s
101{
Jonny Svärd136810f2021-10-13 16:04:26 +0200102 struct cop_data_s da_data;
103 uint32_t cfg;
104 uint32_t id;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200105};
106
107/******************************************************************************
Jonny Svärda830f172021-06-07 16:57:00 +0200108 * Variables
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200109 ******************************************************************************/
110
Anton Moberg61da4d32020-12-22 16:00:31 +0100111// Registered drivers linked list HEAD
112static struct ethosu_driver *registered_drivers = NULL;
113
Jonny Svärda830f172021-06-07 16:57:00 +0200114/******************************************************************************
115 * Weak functions - Cache
116 *
117 * Default NOP operations. Override if available on the targeted device.
118 ******************************************************************************/
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100119
Jonny Svärda830f172021-06-07 16:57:00 +0200120/*
121 * Flush/clean the data cache by address and size. Passing NULL as p argument
122 * expects the whole cache to be flushed.
123 */
124void __attribute__((weak)) ethosu_flush_dcache(uint32_t *p, size_t bytes)
125{
126 UNUSED(p);
127 UNUSED(bytes);
128}
129
130/*
131 * Invalidate the data cache by address and size. Passing NULL as p argument
132 * expects the whole cache to be invalidated.
133 */
134void __attribute__((weak)) ethosu_invalidate_dcache(uint32_t *p, size_t bytes)
135{
136 UNUSED(p);
137 UNUSED(bytes);
138}
139
140/******************************************************************************
141 * Weak functions - Semaphore/Mutex for multi NPU
142 *
143 * Following section handles the minimal sempahore and mutex implementation in
144 * case of baremetal applications. Weak symbols will be overridden by RTOS
145 * definitions and implement true thread-safety (in application layer).
146 ******************************************************************************/
147
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100148struct ethosu_semaphore_t
149{
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100150 uint8_t count;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100151};
152
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100153static void *ethosu_mutex;
154static void *ethosu_semaphore;
155
Anton Moberg9f346ab2021-05-21 17:20:21 +0200156void *__attribute__((weak)) ethosu_mutex_create(void)
157{
158 return NULL;
159}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100160
Jonny Svärd136810f2021-10-13 16:04:26 +0200161void __attribute__((weak)) ethosu_mutex_destroy(void *mutex)
162{
163 UNUSED(mutex);
164}
165
Anton Moberg61ec36b2021-04-30 17:10:48 +0200166void __attribute__((weak)) ethosu_mutex_lock(void *mutex)
167{
168 UNUSED(mutex);
169}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100170
Anton Moberg61ec36b2021-04-30 17:10:48 +0200171void __attribute__((weak)) ethosu_mutex_unlock(void *mutex)
172{
173 UNUSED(mutex);
174}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100175
176// Baremetal implementation of creating a semaphore
177void *__attribute__((weak)) ethosu_semaphore_create(void)
178{
179 struct ethosu_semaphore_t *sem = malloc(sizeof(*sem));
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100180 sem->count = 0;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100181 return sem;
182}
183
Jonny Svärd136810f2021-10-13 16:04:26 +0200184void __attribute__((weak)) ethosu_semaphore_destroy(void *sem)
185{
186 free((struct ethosu_semaphore_t *)sem);
187}
188
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100189// Baremetal simulation of waiting/sleeping for and then taking a semaphore using intrisics
190void __attribute__((weak)) ethosu_semaphore_take(void *sem)
191{
192 struct ethosu_semaphore_t *s = sem;
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100193 while (s->count == 0)
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100194 {
195 __WFE();
196 }
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100197 s->count = 0;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100198}
199
200// Baremetal simulation of giving a semaphore and waking up processes using intrinsics
201void __attribute__((weak)) ethosu_semaphore_give(void *sem)
202{
203 struct ethosu_semaphore_t *s = sem;
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100204 s->count = 1;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100205 __SEV();
206}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100207
Jonny Svärda830f172021-06-07 16:57:00 +0200208/******************************************************************************
209 * Weak functions - Inference begin/end callbacks
210 ******************************************************************************/
Anton Moberg61da4d32020-12-22 16:00:31 +0100211
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100212void __attribute__((weak)) ethosu_inference_begin(struct ethosu_driver *drv, void *user_arg)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200213{
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100214 UNUSED(user_arg);
Jonny Svärda830f172021-06-07 16:57:00 +0200215 UNUSED(drv);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200216}
217
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100218void __attribute__((weak)) ethosu_inference_end(struct ethosu_driver *drv, void *user_arg)
Jonny Svärda830f172021-06-07 16:57:00 +0200219{
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100220 UNUSED(user_arg);
Jonny Svärda830f172021-06-07 16:57:00 +0200221 UNUSED(drv);
222}
223
224/******************************************************************************
225 * Static functions
226 ******************************************************************************/
Jonny Svärda830f172021-06-07 16:57:00 +0200227static void ethosu_register_driver(struct ethosu_driver *drv)
Jens Elofsson04961a42021-04-08 18:51:38 +0200228{
Jonny Svärda830f172021-06-07 16:57:00 +0200229 // Register driver as new HEAD of list
230 drv->next = registered_drivers;
231 registered_drivers = drv;
232
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100233 LOG_INFO("New NPU driver registered (handle: 0x%p, NPU: 0x%p)", drv, drv->dev->reg);
Jens Elofsson04961a42021-04-08 18:51:38 +0200234}
235
Jonny Svärda830f172021-06-07 16:57:00 +0200236static int ethosu_deregister_driver(struct ethosu_driver *drv)
237{
238 struct ethosu_driver *cur = registered_drivers;
239 struct ethosu_driver **prev = &registered_drivers;
240
241 while (cur != NULL)
242 {
243 if (cur == drv)
244 {
245 *prev = cur->next;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100246 LOG_INFO("NPU driver handle %p deregistered.", drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200247 return 0;
248 }
249
250 prev = &cur->next;
251 cur = cur->next;
252 }
253
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100254 LOG_ERR("No NPU driver handle registered at address %p.", drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200255
256 return -1;
257}
258
259static struct ethosu_driver *ethosu_find_and_reserve_driver(void)
260{
261 struct ethosu_driver *drv = registered_drivers;
262
263 while (drv != NULL)
264 {
265 if (!drv->reserved)
266 {
267 drv->reserved = true;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100268 LOG_DEBUG("NPU driver handle %p reserved.", drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200269 return drv;
270 }
271 drv = drv->next;
272 }
273
Jonny Svärd20ce37f2021-12-17 17:00:57 +0100274 LOG_WARN("No NPU driver handle available.");
Jonny Svärda830f172021-06-07 16:57:00 +0200275
276 return NULL;
277}
278
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100279static void ethosu_reset_job(struct ethosu_driver *drv)
280{
281 memset(&drv->job, 0, sizeof(struct ethosu_job));
282}
283
Jonny Svärd136810f2021-10-13 16:04:26 +0200284static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s *opt_cfg_p)
Jonny Svärda830f172021-06-07 16:57:00 +0200285{
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100286 LOG_INFO("Optimizer release nbr: %d patch: %d", opt_cfg_p->da_data.rel_nbr, opt_cfg_p->da_data.patch_nbr);
Jonny Svärda830f172021-06-07 16:57:00 +0200287
Jonny Svärd136810f2021-10-13 16:04:26 +0200288 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 +0200289 {
290 return -1;
291 }
292
Jonny Svärda830f172021-06-07 16:57:00 +0200293 return 0;
294}
295
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100296static 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 +0200297{
Jonny Svärda830f172021-06-07 16:57:00 +0200298 uint32_t cms_bytes = cms_length * BYTES_IN_32_BITS;
299 ptrdiff_t cmd_stream_ptr = (ptrdiff_t)cmd_stream;
300
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100301 LOG_INFO("handle_command_stream: cmd_stream=%p, cms_length %d", cmd_stream, cms_length);
Jonny Svärda830f172021-06-07 16:57:00 +0200302
303 if (0 != ((ptrdiff_t)cmd_stream & MASK_16_BYTE_ALIGN))
304 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100305 LOG_ERR("Command stream addr %p not aligned to 16 bytes", cmd_stream);
Jonny Svärda830f172021-06-07 16:57:00 +0200306 return -1;
307 }
308
Jonny Svärd136810f2021-10-13 16:04:26 +0200309 // Verify 16 byte alignment for base address'
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100310 for (int i = 0; i < drv->job.num_base_addr; i++)
Jonny Svärda830f172021-06-07 16:57:00 +0200311 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100312 if (0 != (drv->job.base_addr[i] & MASK_16_BYTE_ALIGN))
Jonny Svärda830f172021-06-07 16:57:00 +0200313 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100314 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 +0200315 return -1;
Jonny Svärda830f172021-06-07 16:57:00 +0200316 }
317 }
318
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100319 drv->job.state = ETHOSU_JOB_RUNNING;
Jonny Svärda830f172021-06-07 16:57:00 +0200320
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100321 // Flush the cache if available on CPU.
322 // The upcasting to uin32_t* is ok since the pointer never is dereferenced.
323 // The base_addr_size is null if invoking from prior to invoke_V2, in that case
324 // the whole cache is being flushed.
325
326 if (drv->job.base_addr_size != NULL)
Jonny Svärda830f172021-06-07 16:57:00 +0200327 {
328 ethosu_flush_dcache((uint32_t *)cmd_stream_ptr, cms_bytes);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100329 for (int i = 0; i < drv->job.num_base_addr; i++)
Jonny Svärda830f172021-06-07 16:57:00 +0200330 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100331 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 +0200332 }
333 }
334 else
335 {
336 ethosu_flush_dcache(NULL, 0);
337 }
338
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100339 // Request power gating disabled during inference run
340 if (!drv->dev_power_always_on)
341 {
342 // Will soft reset if security state or privilege level needs changing.
343 // Also note that any configurations done in the NPU prior to this point
344 // are lost in case power gating has been in effect.
345 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE);
346
347 // Make sure AXI settings are applied
348 ethosu_dev_axi_init(drv->dev);
349 }
350
351 // Inference begin callback
352 ethosu_inference_begin(drv, drv->job.user_arg);
353
Jonny Svärd136810f2021-10-13 16:04:26 +0200354 // Execute the command stream
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100355 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 +0200356
Jonny Svärda830f172021-06-07 16:57:00 +0200357 return 0;
358}
359
360/******************************************************************************
361 * Weak functions - Interrupt handler
362 ******************************************************************************/
363void __attribute__((weak)) ethosu_irq_handler(struct ethosu_driver *drv)
364{
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100365 LOG_DEBUG("Got interrupt from Ethos-U");
Jonny Svärda830f172021-06-07 16:57:00 +0200366
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100367 drv->job.state = ETHOSU_JOB_DONE;
Jonny Svärd136810f2021-10-13 16:04:26 +0200368 if (!ethosu_dev_handle_interrupt(drv->dev))
Jonny Svärda830f172021-06-07 16:57:00 +0200369 {
Jonny Svärda830f172021-06-07 16:57:00 +0200370 drv->status_error = true;
371 }
Jonny Svärda830f172021-06-07 16:57:00 +0200372 ethosu_semaphore_give(drv->semaphore);
373}
374
375/******************************************************************************
376 * Functions API
377 ******************************************************************************/
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200378
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200379int ethosu_init(struct ethosu_driver *drv,
380 const void *base_address,
381 const void *fast_memory,
382 const size_t fast_memory_size,
383 uint32_t secure_enable,
384 uint32_t privilege_enable)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200385{
Jonny Svärda830f172021-06-07 16:57:00 +0200386 LOG_INFO("Initializing NPU: base_address=%p, fast_memory=%p, fast_memory_size=%zu, secure=%" PRIu32
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100387 ", privileged=%" PRIu32,
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200388 base_address,
389 fast_memory,
Per Åstrande6498f02020-11-09 15:33:12 +0100390 fast_memory_size,
391 secure_enable,
392 privilege_enable);
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200393
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100394 if (!ethosu_mutex)
395 {
396 ethosu_mutex = ethosu_mutex_create();
397 }
398
399 if (!ethosu_semaphore)
400 {
401 ethosu_semaphore = ethosu_semaphore_create();
402 }
403
Anton Moberg61da4d32020-12-22 16:00:31 +0100404 drv->fast_memory = (uint32_t)fast_memory;
405 drv->fast_memory_size = fast_memory_size;
406
Jonny Svärd136810f2021-10-13 16:04:26 +0200407 // Initialize the device and set requested security state and privilege mode
408 drv->dev = ethosu_dev_init(base_address, secure_enable, privilege_enable);
409
410 if (drv->dev == NULL)
Bhavik Pateldae5be02020-06-18 15:25:15 +0200411 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100412 LOG_ERR("Failed to initialize Ethos-U device");
Bhavik Pateldae5be02020-06-18 15:25:15 +0200413 return -1;
414 }
415
Jonny Svärd136810f2021-10-13 16:04:26 +0200416 // Power always ON requested
417 if (drv->dev_power_always_on)
Bhavik Patele645fed2020-06-12 14:46:47 +0200418 {
Jonny Svärd136810f2021-10-13 16:04:26 +0200419 if (set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE) !=
420 ETHOSU_SUCCESS)
421 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100422 LOG_ERR("Failed to disable power-q for Ethos-U");
Jonny Svärd136810f2021-10-13 16:04:26 +0200423 return -1;
424 }
Bhavik Patele645fed2020-06-12 14:46:47 +0200425 }
426
Jonny Svärd136810f2021-10-13 16:04:26 +0200427 drv->semaphore = ethosu_semaphore_create();
Anton Moberg61da4d32020-12-22 16:00:31 +0100428 drv->status_error = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200429
Jonny Svärda830f172021-06-07 16:57:00 +0200430 ethosu_register_driver(drv);
431
Jonny Svärd136810f2021-10-13 16:04:26 +0200432 return 0;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200433}
434
Anton Moberg547ca532021-06-14 09:43:53 +0200435void ethosu_deinit(struct ethosu_driver *drv)
436{
437 ethosu_deregister_driver(drv);
Jonny Svärd136810f2021-10-13 16:04:26 +0200438 ethosu_semaphore_destroy(drv->semaphore);
439 ethosu_dev_deinit(drv->dev);
440 drv->dev = NULL;
Anton Moberg547ca532021-06-14 09:43:53 +0200441}
442
Jonny Svärda830f172021-06-07 16:57:00 +0200443void ethosu_get_driver_version(struct ethosu_driver_version *ver)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200444{
Jonny Svärda830f172021-06-07 16:57:00 +0200445 assert(ver != NULL);
446 ver->major = ETHOSU_DRIVER_VERSION_MAJOR;
447 ver->minor = ETHOSU_DRIVER_VERSION_MINOR;
448 ver->patch = ETHOSU_DRIVER_VERSION_PATCH;
449}
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200450
Jonny Svärda830f172021-06-07 16:57:00 +0200451void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw)
452{
453 assert(hw != NULL);
Jonny Svärd136810f2021-10-13 16:04:26 +0200454 ethosu_dev_get_hw_info(drv->dev, hw);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200455}
456
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100457int ethosu_wait(struct ethosu_driver *drv, bool block)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200458{
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100459 int ret = 0;
460
461 switch (drv->job.state)
462 {
463 case ETHOSU_JOB_IDLE:
464 LOG_ERR("Inference job not running...");
465 ret = -2;
466 break;
467 case ETHOSU_JOB_RUNNING:
468 if (!block)
469 {
470 // Inference still running, do not block
471 ret = 1;
472 break;
473 }
474 // fall through
475 case ETHOSU_JOB_DONE:
476 // Wait for interrupt in blocking mode. In non-blocking mode
477 // the interrupt has already triggered
478 ethosu_semaphore_take(drv->semaphore);
479
480 // Inference done callback
481 ethosu_inference_end(drv, drv->job.user_arg);
482
483 // Check NPU and interrupt status
484 if (drv->status_error)
485 {
486 LOG_ERR("NPU error(s) occured during inference.");
487 ethosu_dev_print_err_status(drv->dev);
488
489 // Reset the NPU
490 (void)ethosu_dev_soft_reset(drv->dev);
491 // NPU is no longer in error state
492 drv->status_error = false;
493
494 ret = -1;
495 }
496
497 // Clear the clock/power gating disable request
498 if (!drv->dev_power_always_on)
499 {
500 // NOTE: Other requesters (like PMU) can be active, keeping
501 // clock/power gating disabled until no requests remain.
502 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
503 }
504
505 if (ret == 0)
506 {
507 // Invalidate cache
508 if (drv->job.base_addr_size != NULL)
509 {
510 for (int i = 0; i < drv->job.num_base_addr; i++)
511 {
512 ethosu_invalidate_dcache((uint32_t *)(uintptr_t)drv->job.base_addr[i], drv->job.base_addr_size[i]);
513 }
514 }
515 else
516 {
517 ethosu_invalidate_dcache(NULL, 0);
518 }
519
520 LOG_DEBUG("Inference finished successfully...");
521 }
522
523 // Reset internal job (state resets to IDLE)
524 ethosu_reset_job(drv);
525 break;
526
527 default:
528 LOG_ERR("Unexpected job state");
529 ethosu_reset_job(drv);
530 ret = -1;
531 break;
532 }
533
534 // Return inference job status
535 return ret;
536}
537
538int ethosu_invoke_async(struct ethosu_driver *drv,
539 const void *custom_data_ptr,
540 const int custom_data_size,
541 const uint64_t *base_addr,
542 const size_t *base_addr_size,
543 const int num_base_addr,
544 void *user_arg)
545{
546
Jonny Svärd136810f2021-10-13 16:04:26 +0200547 const struct cop_data_s *data_ptr = custom_data_ptr;
Kristofer Jonsson24455ee2022-02-08 13:33:22 +0100548 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 +0100549
550 // Make sure an inference is not already running
551 if (drv->job.state != ETHOSU_JOB_IDLE)
552 {
553 LOG_ERR("Inference already running, or waiting to be cleared...");
554 return -1;
555 }
556
557 drv->job.state = ETHOSU_JOB_IDLE;
558 drv->job.custom_data_ptr = custom_data_ptr;
559 drv->job.custom_data_size = custom_data_size;
560 drv->job.base_addr = base_addr;
561 drv->job.base_addr_size = base_addr_size;
562 drv->job.num_base_addr = num_base_addr;
563 drv->job.user_arg = user_arg;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200564
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200565 // First word in custom_data_ptr should contain "Custom Operator Payload 1"
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200566 if (data_ptr->word != ETHOSU_FOURCC)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200567 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100568 LOG_ERR("Custom Operator Payload: %" PRIu32 " is not correct, expected %x", data_ptr->word, ETHOSU_FOURCC);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100569 goto err;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200570 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200571
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200572 // Custom data length must be a multiple of 32 bits
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200573 if ((custom_data_size % BYTES_IN_32_BITS) != 0)
574 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100575 LOG_ERR("custom_data_size=0x%x not a multiple of 4", custom_data_size);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100576 goto err;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200577 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200578
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100579 data_ptr++;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200580
581 // Adjust base address to fast memory area
Anton Moberg61da4d32020-12-22 16:00:31 +0100582 if (drv->fast_memory != 0 && num_base_addr >= FAST_MEMORY_BASE_ADDR_INDEX)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200583 {
584 uint64_t *fast_memory = (uint64_t *)&base_addr[FAST_MEMORY_BASE_ADDR_INDEX];
585
Anton Moberg61da4d32020-12-22 16:00:31 +0100586 if (base_addr_size != NULL && base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > drv->fast_memory_size)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200587 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100588 LOG_ERR("Fast memory area too small. fast_memory_size=%u, base_addr_size=%u",
Anton Moberg61da4d32020-12-22 16:00:31 +0100589 drv->fast_memory_size,
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100590 base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX]);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100591 goto err;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200592 }
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100593
Anton Moberg61da4d32020-12-22 16:00:31 +0100594 *fast_memory = drv->fast_memory;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200595 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200596
Anton Moberg61da4d32020-12-22 16:00:31 +0100597 drv->status_error = false;
Kristofer Jonsson125429a2020-08-20 16:52:23 +0200598
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100599 // Parse Custom Operator Payload data
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200600 while (data_ptr < data_end)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200601 {
602 switch (data_ptr->driver_action_command)
603 {
604 case OPTIMIZER_CONFIG:
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100605 LOG_DEBUG("OPTIMIZER_CONFIG");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200606 struct opt_cfg_s *opt_cfg_p = (struct opt_cfg_s *)data_ptr;
607
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100608 if (handle_optimizer_config(drv, opt_cfg_p) < 0)
609 {
610 goto err;
611 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200612 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD;
613 break;
614 case COMMAND_STREAM:
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100615 // Vela only supports putting one COMMAND_STREAM per op
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100616 LOG_DEBUG("COMMAND_STREAM");
Jonny Svärd136810f2021-10-13 16:04:26 +0200617 void *command_stream = (uint8_t *)(data_ptr) + sizeof(struct cop_data_s);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200618 int cms_length = (data_ptr->reserved << 16) | data_ptr->length;
619
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100620 if (handle_command_stream(drv, command_stream, cms_length) < 0)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200621 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100622 goto err;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200623 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200624 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + cms_length;
625 break;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200626 case NOP:
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100627 LOG_DEBUG("NOP");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200628 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
629 break;
630 default:
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100631 LOG_ERR("UNSUPPORTED driver_action_command: %d", data_ptr->driver_action_command);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100632 goto err;
Bhavik Patele645fed2020-06-12 14:46:47 +0200633 break;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200634 }
635 }
Jonny Svärd136810f2021-10-13 16:04:26 +0200636
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100637 return 0;
638err:
639 LOG_ERR("Failed to invoke inference.");
640 ethosu_reset_job(drv);
641 return -1;
642}
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200643
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100644int ethosu_invoke_v3(struct ethosu_driver *drv,
645 const void *custom_data_ptr,
646 const int custom_data_size,
647 const uint64_t *base_addr,
648 const size_t *base_addr_size,
649 const int num_base_addr,
650 void *user_arg)
651{
652 if (ethosu_invoke_async(
653 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 +0200654 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100655 return -1;
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200656 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200657
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100658 return ethosu_wait(drv, true);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200659}
660
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200661void ethosu_set_power_mode(struct ethosu_driver *drv, bool always_on)
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100662{
Anton Moberg61da4d32020-12-22 16:00:31 +0100663 drv->dev_power_always_on = always_on;
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100664
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100665 if (always_on)
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100666 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100667 if (ethosu_dev_verify_access_state(drv->dev) == false)
Jonny Svärd136810f2021-10-13 16:04:26 +0200668 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100669 // Reset to enter correct security state/privilege mode
670 if (ethosu_dev_soft_reset(drv->dev) == false)
671 {
672 LOG_ERR("Failed to set power mode for Ethos-U");
673 return;
674 }
Jonny Svärd136810f2021-10-13 16:04:26 +0200675 }
Jonny Svärd136810f2021-10-13 16:04:26 +0200676
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100677 ethosu_dev_set_clock_and_power(drv->dev, ETHOSU_CLOCK_Q_UNCHANGED, ETHOSU_POWER_Q_DISABLE);
678 ethosu_dev_axi_init(drv->dev);
679 }
680 else
681 {
682 ethosu_dev_set_clock_and_power(drv->dev, ETHOSU_CLOCK_Q_UNCHANGED, ETHOSU_POWER_Q_ENABLE);
683 }
Anton Moberg61da4d32020-12-22 16:00:31 +0100684}
685
Anton Moberg61da4d32020-12-22 16:00:31 +0100686struct ethosu_driver *ethosu_reserve_driver(void)
687{
Anton Mobergdf386e02021-02-02 11:26:48 +0100688 struct ethosu_driver *drv = NULL;
689
690 do
691 {
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100692 ethosu_mutex_lock(ethosu_mutex);
Anton Mobergdf386e02021-02-02 11:26:48 +0100693 drv = ethosu_find_and_reserve_driver();
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100694 ethosu_mutex_unlock(ethosu_mutex);
Anton Mobergdf386e02021-02-02 11:26:48 +0100695
696 if (drv != NULL)
697 {
698 break;
699 }
700
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100701 LOG_INFO("Waiting for NPU driver handle to become available...");
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100702 ethosu_semaphore_take(ethosu_semaphore);
Anton Mobergdf386e02021-02-02 11:26:48 +0100703
704 } while (1);
705
706 return drv;
707}
708
Anton Moberg61da4d32020-12-22 16:00:31 +0100709void ethosu_release_driver(struct ethosu_driver *drv)
710{
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100711 ethosu_mutex_lock(ethosu_mutex);
Anton Moberg61da4d32020-12-22 16:00:31 +0100712 if (drv != NULL && drv->reserved)
713 {
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100714 if (drv->job.state == ETHOSU_JOB_RUNNING || drv->job.state == ETHOSU_JOB_DONE)
715 {
716 // Give the inference one shot to complete or force kill the job
717 if (ethosu_wait(drv, false) == 1)
718 {
719 // Still running, soft reset the NPU and reset driver
720 ethosu_dev_soft_reset(drv->dev);
721 ethosu_reset_job(drv);
722 drv->status_error = false;
723 ethosu_semaphore_give(drv->semaphore);
724 (void)set_clock_and_power_request(
725 drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
726 }
727 }
728
Anton Moberg61da4d32020-12-22 16:00:31 +0100729 drv->reserved = false;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100730 LOG_DEBUG("NPU driver handle %p released", drv);
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100731 ethosu_semaphore_give(ethosu_semaphore);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100732 }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100733 ethosu_mutex_unlock(ethosu_mutex);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100734}
735
Anton Moberg0a614292021-03-24 14:08:22 +0100736enum ethosu_error_codes set_clock_and_power_request(struct ethosu_driver *drv,
737 enum ethosu_request_clients client,
738 enum ethosu_clock_q_request clock_request,
739 enum ethosu_power_q_request power_request)
740{
Jonny Svärd136810f2021-10-13 16:04:26 +0200741 // Keep track of which client requests clock gating to be disabled
Anton Moberg0a614292021-03-24 14:08:22 +0100742 if (clock_request == ETHOSU_CLOCK_Q_DISABLE)
743 {
744 drv->clock_request |= (1 << client);
745 }
Jonny Svärd136810f2021-10-13 16:04:26 +0200746 else if (clock_request == ETHOSU_CLOCK_Q_ENABLE) // Remove client from bitmask
Anton Moberg0a614292021-03-24 14:08:22 +0100747 {
748 drv->clock_request &= ~(1 << client);
749 }
Jonny Svärd136810f2021-10-13 16:04:26 +0200750
751 // Only enable clock gating when no client has asked for it to be disabled
Anton Moberg0a614292021-03-24 14:08:22 +0100752 clock_request = drv->clock_request == 0 ? ETHOSU_CLOCK_Q_ENABLE : ETHOSU_CLOCK_Q_DISABLE;
753
Jonny Svärd136810f2021-10-13 16:04:26 +0200754 // Keep track of which client requests power gating to be disabled
Anton Moberg35b5d0e2021-04-13 13:32:17 +0200755 if (power_request == ETHOSU_POWER_Q_DISABLE)
Anton Moberg0a614292021-03-24 14:08:22 +0100756 {
757 drv->power_request |= (1 << client);
758 }
Jonny Svärdc1b9dbb2021-11-05 12:41:23 +0100759 else if (power_request == ETHOSU_POWER_Q_ENABLE)
Anton Moberg0a614292021-03-24 14:08:22 +0100760 {
761 drv->power_request &= ~(1 << client);
762 }
Anton Moberg35b5d0e2021-04-13 13:32:17 +0200763
Jonny Svärd136810f2021-10-13 16:04:26 +0200764 // Override if power has been requested to be always on
765 if (drv->dev_power_always_on == true)
766 {
767 power_request = ETHOSU_POWER_Q_DISABLE;
768 }
769 else
770 {
771 // Only enable power gating when no client has asked for it to be disabled
772 power_request = drv->power_request == 0 ? ETHOSU_POWER_Q_ENABLE : ETHOSU_POWER_Q_DISABLE;
773 }
774
775 // Verify security state and privilege mode if power is requested to be on
776 if (power_request == ETHOSU_POWER_Q_DISABLE)
777 {
778 if (ethosu_dev_verify_access_state(drv->dev) == false)
779 {
780 if (ethosu_dev_soft_reset(drv->dev) != ETHOSU_SUCCESS)
781 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100782 LOG_ERR("Failed to set clock and power q channels for Ethos-U");
Jonny Svärd136810f2021-10-13 16:04:26 +0200783 return ETHOSU_GENERIC_FAILURE;
784 }
785 }
786 }
Anton Moberg0a614292021-03-24 14:08:22 +0100787 // Set clock and power
Jonny Svärd136810f2021-10-13 16:04:26 +0200788 return ethosu_dev_set_clock_and_power(drv->dev, clock_request, power_request);
Anton Moberg0a614292021-03-24 14:08:22 +0100789}