blob: 866b94c6bde479df0a391b3c82ec02c77365e5fc [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{
150 int count;
151};
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));
180 sem->count = 1;
181 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;
193 while (s->count <= 0)
194 {
195 __WFE();
196 }
197 s->count--;
198}
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;
204 s->count++;
205 __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 ******************************************************************************/
Bhavik Pateldae5be02020-06-18 15:25:15 +0200227static inline void wait_for_irq(struct ethosu_driver *drv)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200228{
229 while (1)
230 {
Jonny Svärd136810f2021-10-13 16:04:26 +0200231 if (drv->irq_triggered)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200232 {
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100233 drv->irq_triggered = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200234 break;
235 }
236
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100237 ethosu_semaphore_take(drv->semaphore);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200238 }
239}
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200240
Jonny Svärda830f172021-06-07 16:57:00 +0200241static void ethosu_register_driver(struct ethosu_driver *drv)
Jens Elofsson04961a42021-04-08 18:51:38 +0200242{
Jonny Svärda830f172021-06-07 16:57:00 +0200243 // Register driver as new HEAD of list
244 drv->next = registered_drivers;
245 registered_drivers = drv;
246
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100247 LOG_INFO("New NPU driver registered (handle: 0x%p, NPU: 0x%p)", drv, drv->dev->reg);
Jens Elofsson04961a42021-04-08 18:51:38 +0200248}
249
Jonny Svärda830f172021-06-07 16:57:00 +0200250static int ethosu_deregister_driver(struct ethosu_driver *drv)
251{
252 struct ethosu_driver *cur = registered_drivers;
253 struct ethosu_driver **prev = &registered_drivers;
254
255 while (cur != NULL)
256 {
257 if (cur == drv)
258 {
259 *prev = cur->next;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100260 LOG_INFO("NPU driver handle %p deregistered.", drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200261 return 0;
262 }
263
264 prev = &cur->next;
265 cur = cur->next;
266 }
267
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100268 LOG_ERR("No NPU driver handle registered at address %p.", drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200269
270 return -1;
271}
272
273static struct ethosu_driver *ethosu_find_and_reserve_driver(void)
274{
275 struct ethosu_driver *drv = registered_drivers;
276
277 while (drv != NULL)
278 {
279 if (!drv->reserved)
280 {
281 drv->reserved = true;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100282 LOG_DEBUG("NPU driver handle %p reserved.", drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200283 return drv;
284 }
285 drv = drv->next;
286 }
287
Jonny Svärd20ce37f2021-12-17 17:00:57 +0100288 LOG_WARN("No NPU driver handle available.");
Jonny Svärda830f172021-06-07 16:57:00 +0200289
290 return NULL;
291}
292
Jonny Svärd136810f2021-10-13 16:04:26 +0200293static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s *opt_cfg_p)
Jonny Svärda830f172021-06-07 16:57:00 +0200294{
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100295 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 +0200296
Jonny Svärd136810f2021-10-13 16:04:26 +0200297 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 +0200298 {
299 return -1;
300 }
301
Jonny Svärda830f172021-06-07 16:57:00 +0200302 return 0;
303}
304
Bhavik Pateldae5be02020-06-18 15:25:15 +0200305static int handle_command_stream(struct ethosu_driver *drv,
306 const uint8_t *cmd_stream,
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200307 const int cms_length,
308 const uint64_t *base_addr,
Per Åstrand3c8afcc2020-10-20 10:29:59 +0200309 const size_t *base_addr_size,
Jonny Svärda830f172021-06-07 16:57:00 +0200310 const int num_base_addr)
311{
Jonny Svärda830f172021-06-07 16:57:00 +0200312 uint32_t cms_bytes = cms_length * BYTES_IN_32_BITS;
313 ptrdiff_t cmd_stream_ptr = (ptrdiff_t)cmd_stream;
314
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100315 LOG_INFO("handle_command_stream: cmd_stream=%p, cms_length %d", cmd_stream, cms_length);
Jonny Svärda830f172021-06-07 16:57:00 +0200316
317 if (0 != ((ptrdiff_t)cmd_stream & MASK_16_BYTE_ALIGN))
318 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100319 LOG_ERR("Command stream addr %p not aligned to 16 bytes", cmd_stream);
Jonny Svärda830f172021-06-07 16:57:00 +0200320 return -1;
321 }
322
Jonny Svärd136810f2021-10-13 16:04:26 +0200323 // Verify 16 byte alignment for base address'
Jonny Svärda830f172021-06-07 16:57:00 +0200324 for (int i = 0; i < num_base_addr; i++)
325 {
326 if (0 != (base_addr[i] & MASK_16_BYTE_ALIGN))
327 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100328 LOG_ERR("Base addr %d: 0x%llx not aligned to 16 bytes", i, base_addr[i]);
Jonny Svärd136810f2021-10-13 16:04:26 +0200329 return -1;
Jonny Svärda830f172021-06-07 16:57:00 +0200330 }
331 }
332
Jonny Svärd136810f2021-10-13 16:04:26 +0200333 /* Flush the cache if available on CPU.
Jonny Svärda830f172021-06-07 16:57:00 +0200334 * The upcasting to uin32_t* is ok since the pointer never is dereferenced.
335 * The base_addr_size is null if invoking from prior to invoke_V2, in that case
336 * the whole cache is being flushed.
337 */
338
339 if (base_addr_size != NULL)
340 {
341 ethosu_flush_dcache((uint32_t *)cmd_stream_ptr, cms_bytes);
342 for (int i = 0; i < num_base_addr; i++)
343 {
344 ethosu_flush_dcache((uint32_t *)(uintptr_t)base_addr[i], base_addr_size[i]);
345 }
346 }
347 else
348 {
349 ethosu_flush_dcache(NULL, 0);
350 }
351
Jonny Svärd136810f2021-10-13 16:04:26 +0200352 // Execute the command stream
353 if (ETHOSU_SUCCESS != ethosu_dev_run_command_stream(drv->dev, cmd_stream, cms_bytes, base_addr, num_base_addr))
Jonny Svärda830f172021-06-07 16:57:00 +0200354 {
355 return -1;
356 }
357
358 wait_for_irq(drv);
359
Jonny Svärd136810f2021-10-13 16:04:26 +0200360 // Check if any error occured
Jonny Svärda830f172021-06-07 16:57:00 +0200361 if (drv->status_error)
362 {
363 return -1;
364 }
365
366 if (base_addr_size != NULL)
367 {
368 for (int i = 0; i < num_base_addr; i++)
369 {
370 ethosu_invalidate_dcache((uint32_t *)(uintptr_t)base_addr[i], base_addr_size[i]);
371 }
372 }
373 else
374 {
375 ethosu_invalidate_dcache(NULL, 0);
376 }
377
Jonny Svärda830f172021-06-07 16:57:00 +0200378 return 0;
379}
380
381/******************************************************************************
382 * Weak functions - Interrupt handler
383 ******************************************************************************/
384void __attribute__((weak)) ethosu_irq_handler(struct ethosu_driver *drv)
385{
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100386 LOG_DEBUG("Got interrupt from Ethos-U");
Jonny Svärda830f172021-06-07 16:57:00 +0200387
Jonny Svärda830f172021-06-07 16:57:00 +0200388 drv->irq_triggered = true;
Jonny Svärd136810f2021-10-13 16:04:26 +0200389 if (!ethosu_dev_handle_interrupt(drv->dev))
Jonny Svärda830f172021-06-07 16:57:00 +0200390 {
Jonny Svärda830f172021-06-07 16:57:00 +0200391 drv->status_error = true;
392 }
Jonny Svärda830f172021-06-07 16:57:00 +0200393 ethosu_semaphore_give(drv->semaphore);
394}
395
396/******************************************************************************
397 * Functions API
398 ******************************************************************************/
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200399
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200400int ethosu_init(struct ethosu_driver *drv,
401 const void *base_address,
402 const void *fast_memory,
403 const size_t fast_memory_size,
404 uint32_t secure_enable,
405 uint32_t privilege_enable)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200406{
Jonny Svärda830f172021-06-07 16:57:00 +0200407 LOG_INFO("Initializing NPU: base_address=%p, fast_memory=%p, fast_memory_size=%zu, secure=%" PRIu32
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100408 ", privileged=%" PRIu32,
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200409 base_address,
410 fast_memory,
Per Åstrande6498f02020-11-09 15:33:12 +0100411 fast_memory_size,
412 secure_enable,
413 privilege_enable);
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200414
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100415 if (!ethosu_mutex)
416 {
417 ethosu_mutex = ethosu_mutex_create();
418 }
419
420 if (!ethosu_semaphore)
421 {
422 ethosu_semaphore = ethosu_semaphore_create();
423 }
424
Anton Moberg61da4d32020-12-22 16:00:31 +0100425 drv->fast_memory = (uint32_t)fast_memory;
426 drv->fast_memory_size = fast_memory_size;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100427 drv->irq_triggered = false;
Anton Moberg61da4d32020-12-22 16:00:31 +0100428
Jonny Svärd136810f2021-10-13 16:04:26 +0200429 // Initialize the device and set requested security state and privilege mode
430 drv->dev = ethosu_dev_init(base_address, secure_enable, privilege_enable);
431
432 if (drv->dev == NULL)
Bhavik Pateldae5be02020-06-18 15:25:15 +0200433 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100434 LOG_ERR("Failed to initialize Ethos-U device");
Bhavik Pateldae5be02020-06-18 15:25:15 +0200435 return -1;
436 }
437
Jonny Svärd136810f2021-10-13 16:04:26 +0200438 // Power always ON requested
439 if (drv->dev_power_always_on)
Bhavik Patele645fed2020-06-12 14:46:47 +0200440 {
Jonny Svärd136810f2021-10-13 16:04:26 +0200441 if (set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE) !=
442 ETHOSU_SUCCESS)
443 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100444 LOG_ERR("Failed to disable power-q for Ethos-U");
Jonny Svärd136810f2021-10-13 16:04:26 +0200445 return -1;
446 }
Bhavik Patele645fed2020-06-12 14:46:47 +0200447 }
448
Jonny Svärd136810f2021-10-13 16:04:26 +0200449 drv->semaphore = ethosu_semaphore_create();
Anton Moberg61da4d32020-12-22 16:00:31 +0100450 drv->status_error = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200451
Jonny Svärda830f172021-06-07 16:57:00 +0200452 ethosu_register_driver(drv);
453
Jonny Svärd136810f2021-10-13 16:04:26 +0200454 return 0;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200455}
456
Anton Moberg547ca532021-06-14 09:43:53 +0200457void ethosu_deinit(struct ethosu_driver *drv)
458{
459 ethosu_deregister_driver(drv);
Jonny Svärd136810f2021-10-13 16:04:26 +0200460 ethosu_semaphore_destroy(drv->semaphore);
461 ethosu_dev_deinit(drv->dev);
462 drv->dev = NULL;
Anton Moberg547ca532021-06-14 09:43:53 +0200463}
464
Jonny Svärda830f172021-06-07 16:57:00 +0200465void ethosu_get_driver_version(struct ethosu_driver_version *ver)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200466{
Jonny Svärda830f172021-06-07 16:57:00 +0200467 assert(ver != NULL);
468 ver->major = ETHOSU_DRIVER_VERSION_MAJOR;
469 ver->minor = ETHOSU_DRIVER_VERSION_MINOR;
470 ver->patch = ETHOSU_DRIVER_VERSION_PATCH;
471}
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200472
Jonny Svärda830f172021-06-07 16:57:00 +0200473void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw)
474{
475 assert(hw != NULL);
Jonny Svärd136810f2021-10-13 16:04:26 +0200476 ethosu_dev_get_hw_info(drv->dev, hw);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200477}
478
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100479int ethosu_invoke_v3(struct ethosu_driver *drv,
480 const void *custom_data_ptr,
481 const int custom_data_size,
482 const uint64_t *base_addr,
483 const size_t *base_addr_size,
484 const int num_base_addr,
485 void *user_arg)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200486{
Jonny Svärd136810f2021-10-13 16:04:26 +0200487 const struct cop_data_s *data_ptr = custom_data_ptr;
Kristofer Jonsson24455ee2022-02-08 13:33:22 +0100488 const struct cop_data_s *data_end = (struct cop_data_s *)((ptrdiff_t)custom_data_ptr + custom_data_size);
Jonny Svärd136810f2021-10-13 16:04:26 +0200489 int return_code = 0;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200490
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200491 // First word in custom_data_ptr should contain "Custom Operator Payload 1"
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200492 if (data_ptr->word != ETHOSU_FOURCC)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200493 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100494 LOG_ERR("Custom Operator Payload: %" PRIu32 " is not correct, expected %x", data_ptr->word, ETHOSU_FOURCC);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200495 return -1;
496 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200497
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200498 // Custom data length must be a multiple of 32 bits
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200499 if ((custom_data_size % BYTES_IN_32_BITS) != 0)
500 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100501 LOG_ERR("custom_data_size=0x%x not a multiple of 4", custom_data_size);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200502 return -1;
503 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200504
505 ++data_ptr;
506
507 // Adjust base address to fast memory area
Anton Moberg61da4d32020-12-22 16:00:31 +0100508 if (drv->fast_memory != 0 && num_base_addr >= FAST_MEMORY_BASE_ADDR_INDEX)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200509 {
510 uint64_t *fast_memory = (uint64_t *)&base_addr[FAST_MEMORY_BASE_ADDR_INDEX];
511
Anton Moberg61da4d32020-12-22 16:00:31 +0100512 if (base_addr_size != NULL && base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > drv->fast_memory_size)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200513 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100514 LOG_ERR("Fast memory area too small. fast_memory_size=%u, base_addr_size=%u",
Anton Moberg61da4d32020-12-22 16:00:31 +0100515 drv->fast_memory_size,
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100516 base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX]);
517 return -1;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200518 }
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100519
Anton Moberg61da4d32020-12-22 16:00:31 +0100520 *fast_memory = drv->fast_memory;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200521 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200522
Jonny Svärd136810f2021-10-13 16:04:26 +0200523 // NPU might have lost power and thus its settings and state
Anton Moberg61da4d32020-12-22 16:00:31 +0100524 if (!drv->dev_power_always_on)
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200525 {
Jonny Svärd6d5b0832021-11-30 14:54:07 +0100526 // Set power ON during the inference. Will soft reset if security state or
527 // privilege level needs changing
Anton Moberg0a614292021-03-24 14:08:22 +0100528 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE);
Jonny Svärd136810f2021-10-13 16:04:26 +0200529
Jonny Svärd6d5b0832021-11-30 14:54:07 +0100530 // Make sure AXI settings are applied
531 ethosu_dev_axi_init(drv->dev);
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200532 }
Kristofer Jonssonc6e7a1f2020-11-24 09:20:14 +0100533
Anton Moberg61da4d32020-12-22 16:00:31 +0100534 drv->status_error = false;
Kristofer Jonsson125429a2020-08-20 16:52:23 +0200535
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100536 ethosu_inference_begin(drv, user_arg);
537
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200538 while (data_ptr < data_end)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200539 {
Bhavik Patele645fed2020-06-12 14:46:47 +0200540 int ret = 0;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200541 switch (data_ptr->driver_action_command)
542 {
543 case OPTIMIZER_CONFIG:
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100544 LOG_DEBUG("OPTIMIZER_CONFIG");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200545 struct opt_cfg_s *opt_cfg_p = (struct opt_cfg_s *)data_ptr;
546
Anton Moberg61da4d32020-12-22 16:00:31 +0100547 ret = handle_optimizer_config(drv, opt_cfg_p);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200548 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD;
549 break;
550 case COMMAND_STREAM:
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100551 LOG_DEBUG("COMMAND_STREAM");
Jonny Svärd136810f2021-10-13 16:04:26 +0200552 void *command_stream = (uint8_t *)(data_ptr) + sizeof(struct cop_data_s);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200553 int cms_length = (data_ptr->reserved << 16) | data_ptr->length;
554
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200555 // It is safe to clear this flag without atomic, because npu is not running.
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100556 drv->irq_triggered = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200557
Anton Moberg61da4d32020-12-22 16:00:31 +0100558 ret = handle_command_stream(drv, command_stream, cms_length, base_addr, base_addr_size, num_base_addr);
Jonny Svärd136810f2021-10-13 16:04:26 +0200559 if (ret < 0)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200560 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100561 LOG_ERR("Inference failed.");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200562 }
563
564 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + cms_length;
565 break;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200566 case NOP:
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100567 LOG_DEBUG("NOP");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200568 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
569 break;
570 default:
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100571 LOG_ERR("UNSUPPORTED driver_action_command: %d", data_ptr->driver_action_command);
Bhavik Patele645fed2020-06-12 14:46:47 +0200572 ret = -1;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200573 break;
574 }
Bhavik Patele645fed2020-06-12 14:46:47 +0200575 if (ret != 0)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200576 {
Bhavik Patele645fed2020-06-12 14:46:47 +0200577 return_code = -1;
578 break;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200579 }
580 }
Jonny Svärd136810f2021-10-13 16:04:26 +0200581
Kristofer Jonssonb3cde3c2022-01-27 17:30:15 +0100582 ethosu_inference_end(drv, user_arg);
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200583
Anton Moberg61da4d32020-12-22 16:00:31 +0100584 if (!drv->status_error && !drv->dev_power_always_on)
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200585 {
Anton Moberg0a614292021-03-24 14:08:22 +0100586 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200587 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200588
Bhavik Patele645fed2020-06-12 14:46:47 +0200589 return return_code;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200590}
591
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200592void ethosu_set_power_mode(struct ethosu_driver *drv, bool always_on)
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100593{
Anton Moberg61da4d32020-12-22 16:00:31 +0100594 drv->dev_power_always_on = always_on;
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100595
Jonny Svärd136810f2021-10-13 16:04:26 +0200596 if (always_on && ethosu_dev_verify_access_state(drv->dev) == false)
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100597 {
Jonny Svärd136810f2021-10-13 16:04:26 +0200598 // Reset to enter correct security state/privilege mode
599 if (ethosu_dev_soft_reset(drv->dev) == false)
600 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100601 LOG_ERR("Failed to set power mode for Ethos-U");
Jonny Svärd136810f2021-10-13 16:04:26 +0200602 return;
603 }
Anton Moberg61da4d32020-12-22 16:00:31 +0100604 }
Jonny Svärd136810f2021-10-13 16:04:26 +0200605
606 ethosu_dev_set_clock_and_power(
607 drv->dev, ETHOSU_CLOCK_Q_UNCHANGED, always_on ? ETHOSU_POWER_Q_DISABLE : ETHOSU_POWER_Q_ENABLE);
Anton Moberg61da4d32020-12-22 16:00:31 +0100608}
609
Anton Moberg61da4d32020-12-22 16:00:31 +0100610struct ethosu_driver *ethosu_reserve_driver(void)
611{
Anton Mobergdf386e02021-02-02 11:26:48 +0100612 struct ethosu_driver *drv = NULL;
613
614 do
615 {
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100616 ethosu_mutex_lock(ethosu_mutex);
Anton Mobergdf386e02021-02-02 11:26:48 +0100617 drv = ethosu_find_and_reserve_driver();
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100618 ethosu_mutex_unlock(ethosu_mutex);
Anton Mobergdf386e02021-02-02 11:26:48 +0100619
620 if (drv != NULL)
621 {
622 break;
623 }
624
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100625 LOG_INFO("Waiting for NPU driver handle to become available...");
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100626 ethosu_semaphore_take(ethosu_semaphore);
Anton Mobergdf386e02021-02-02 11:26:48 +0100627
628 } while (1);
629
630 return drv;
631}
632
Anton Moberg61da4d32020-12-22 16:00:31 +0100633void ethosu_release_driver(struct ethosu_driver *drv)
634{
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100635 ethosu_mutex_lock(ethosu_mutex);
Anton Moberg61da4d32020-12-22 16:00:31 +0100636 if (drv != NULL && drv->reserved)
637 {
638 drv->reserved = false;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100639 LOG_DEBUG("NPU driver handle %p released", drv);
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100640 ethosu_semaphore_give(ethosu_semaphore);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100641 }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100642 ethosu_mutex_unlock(ethosu_mutex);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100643}
644
Anton Moberg0a614292021-03-24 14:08:22 +0100645enum ethosu_error_codes set_clock_and_power_request(struct ethosu_driver *drv,
646 enum ethosu_request_clients client,
647 enum ethosu_clock_q_request clock_request,
648 enum ethosu_power_q_request power_request)
649{
Jonny Svärd136810f2021-10-13 16:04:26 +0200650 // Keep track of which client requests clock gating to be disabled
Anton Moberg0a614292021-03-24 14:08:22 +0100651 if (clock_request == ETHOSU_CLOCK_Q_DISABLE)
652 {
653 drv->clock_request |= (1 << client);
654 }
Jonny Svärd136810f2021-10-13 16:04:26 +0200655 else if (clock_request == ETHOSU_CLOCK_Q_ENABLE) // Remove client from bitmask
Anton Moberg0a614292021-03-24 14:08:22 +0100656 {
657 drv->clock_request &= ~(1 << client);
658 }
Jonny Svärd136810f2021-10-13 16:04:26 +0200659
660 // Only enable clock gating when no client has asked for it to be disabled
Anton Moberg0a614292021-03-24 14:08:22 +0100661 clock_request = drv->clock_request == 0 ? ETHOSU_CLOCK_Q_ENABLE : ETHOSU_CLOCK_Q_DISABLE;
662
Jonny Svärd136810f2021-10-13 16:04:26 +0200663 // Keep track of which client requests power gating to be disabled
Anton Moberg35b5d0e2021-04-13 13:32:17 +0200664 if (power_request == ETHOSU_POWER_Q_DISABLE)
Anton Moberg0a614292021-03-24 14:08:22 +0100665 {
666 drv->power_request |= (1 << client);
667 }
Jonny Svärdc1b9dbb2021-11-05 12:41:23 +0100668 else if (power_request == ETHOSU_POWER_Q_ENABLE)
Anton Moberg0a614292021-03-24 14:08:22 +0100669 {
670 drv->power_request &= ~(1 << client);
671 }
Anton Moberg35b5d0e2021-04-13 13:32:17 +0200672
Jonny Svärd136810f2021-10-13 16:04:26 +0200673 // Override if power has been requested to be always on
674 if (drv->dev_power_always_on == true)
675 {
676 power_request = ETHOSU_POWER_Q_DISABLE;
677 }
678 else
679 {
680 // Only enable power gating when no client has asked for it to be disabled
681 power_request = drv->power_request == 0 ? ETHOSU_POWER_Q_ENABLE : ETHOSU_POWER_Q_DISABLE;
682 }
683
684 // Verify security state and privilege mode if power is requested to be on
685 if (power_request == ETHOSU_POWER_Q_DISABLE)
686 {
687 if (ethosu_dev_verify_access_state(drv->dev) == false)
688 {
689 if (ethosu_dev_soft_reset(drv->dev) != ETHOSU_SUCCESS)
690 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100691 LOG_ERR("Failed to set clock and power q channels for Ethos-U");
Jonny Svärd136810f2021-10-13 16:04:26 +0200692 return ETHOSU_GENERIC_FAILURE;
693 }
694 }
695 }
Anton Moberg0a614292021-03-24 14:08:22 +0100696 // Set clock and power
Jonny Svärd136810f2021-10-13 16:04:26 +0200697 return ethosu_dev_set_clock_and_power(drv->dev, clock_request, power_request);
Anton Moberg0a614292021-03-24 14:08:22 +0100698}