blob: 5cf7f39768e0952013e0b1dd0129ea6daa5fcca1 [file] [log] [blame]
Kristofer Jonsson49bdee82020-04-06 13:21:21 +02001/*
Kristofer Jonsson09273d12021-03-15 08:43:08 +01002 * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
Kristofer Jonsson49bdee82020-04-06 13:21:21 +02003 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020019/******************************************************************************
20 * Includes
21 ******************************************************************************/
22
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020023#include "ethosu_driver.h"
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020024#include "ethosu_common.h"
Bhavik Pateldae5be02020-06-18 15:25:15 +020025#include "ethosu_config.h"
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020026#include "ethosu_device.h"
Anton Moberg6eab40b2021-07-07 11:43:51 +020027#include "ethosu_log.h"
Per Åstrand25d78c02020-04-21 14:19:44 +020028
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020029#include <assert.h>
Per Åstrand25d78c02020-04-21 14:19:44 +020030#include <cmsis_compiler.h>
Per Åstrand14ccfee2020-09-25 10:40:20 +020031#include <inttypes.h>
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020032#include <stdbool.h>
Bhavik Patelbf7ae632020-06-11 21:00:16 +020033#include <stddef.h>
Kristofer Jonsson49bdee82020-04-06 13:21:21 +020034#include <stdio.h>
35#include <stdlib.h>
36
Kristofer Jonsson2b201c32020-09-02 16:42:43 +020037/******************************************************************************
38 * Defines
39 ******************************************************************************/
40
41#define MACS_PER_CYCLE_LOG2_MASK 0x000F
42#define SHRAM_SIZE_MASK 0xFF00
43#define SHRAM_SIZE_RIGHT_SHIFT 8
44#define BYTES_IN_32_BITS 4
45#define CUSTOM_OPTION_LENGTH_32_BIT_WORD 1
46#define DRIVER_ACTION_LENGTH_32_BIT_WORD 1
47#define OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD 2
48#define ETHOSU_FOURCC ('1' << 24 | 'P' << 16 | 'O' << 8 | 'C') // "Custom Operator Payload 1"
49#define APB_START_ADDR_MASK 0x0FFF
50#define APB_NUM_REG_BIT_SHIFT 12
51#define BYTES_1KB 1024
52#define PRODUCT_MAJOR_ETHOSU55 (4)
53#define MASK_16_BYTE_ALIGN (0xF)
54#define FAST_MEMORY_BASE_ADDR_INDEX 2
55
56/******************************************************************************
57 * Types
58 ******************************************************************************/
59
60// Driver actions
61enum DRIVER_ACTION_e
62{
63 RESERVED = 0,
64 OPTIMIZER_CONFIG = 1,
65 COMMAND_STREAM = 2,
66 READ_APB_REG = 3,
67 DUMP_SHRAM = 4,
68 NOP = 5,
69};
70
71// Custom data struct
72struct custom_data_s
73{
74 union
75 {
76 // Driver action data
77 struct
78 {
79 // Driver action command (valid values in DRIVER_ACTION_e)
80 uint8_t driver_action_command;
81
82 // reserved
83 uint8_t reserved;
84
85 // Driver action data
86 union
87 {
88 // DA_CMD_OPT_CFG
89 struct
90 {
91 uint16_t rel_nbr : 4;
92 uint16_t patch_nbr : 4;
93 uint16_t opt_cfg_reserved : 8;
94 };
95
96 // DA_CMD_CMSTRM
97 struct
98 {
99 uint16_t length;
100 };
101
102 // DA_CMD_READAPB
103 struct
104 {
105 uint16_t start_address : 12;
106 uint16_t nbr_reg_minus1 : 4;
107 };
108
109 uint16_t driver_action_data;
110 };
111 };
112
113 uint32_t word;
114 };
115};
116
117// optimizer config struct
118struct opt_cfg_s
119{
120 struct custom_data_s da_data;
121 union
122 {
123 struct
124 {
125 uint32_t macs_per_cc : 4;
126 uint32_t cmd_stream_version : 4;
127 uint32_t shram_size : 8;
Anton Mobergb8bcf132021-03-29 10:02:25 +0200128 uint32_t reserved0 : 11;
129 uint32_t custom_dma : 1;
130 uint32_t product : 4;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200131 };
132 uint32_t npu_cfg;
133 };
134 union
135 {
136 struct
137 {
138 uint32_t version_status : 4;
139 uint32_t version_minor : 4;
140 uint32_t version_major : 4;
141 uint32_t product_major : 4;
142 uint32_t arch_patch_rev : 4;
143 uint32_t arch_minor_rev : 8;
144 uint32_t arch_major_rev : 4;
145 };
146 uint32_t ethosu_id;
147 };
148};
149
150/******************************************************************************
Jonny Svärda830f172021-06-07 16:57:00 +0200151 * Variables
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200152 ******************************************************************************/
153
Anton Moberg61da4d32020-12-22 16:00:31 +0100154// Registered drivers linked list HEAD
155static struct ethosu_driver *registered_drivers = NULL;
156
Jonny Svärda830f172021-06-07 16:57:00 +0200157/******************************************************************************
158 * Weak functions - Cache
159 *
160 * Default NOP operations. Override if available on the targeted device.
161 ******************************************************************************/
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100162
Jonny Svärda830f172021-06-07 16:57:00 +0200163/*
164 * Flush/clean the data cache by address and size. Passing NULL as p argument
165 * expects the whole cache to be flushed.
166 */
167void __attribute__((weak)) ethosu_flush_dcache(uint32_t *p, size_t bytes)
168{
169 UNUSED(p);
170 UNUSED(bytes);
171}
172
173/*
174 * Invalidate the data cache by address and size. Passing NULL as p argument
175 * expects the whole cache to be invalidated.
176 */
177void __attribute__((weak)) ethosu_invalidate_dcache(uint32_t *p, size_t bytes)
178{
179 UNUSED(p);
180 UNUSED(bytes);
181}
182
183/******************************************************************************
184 * Weak functions - Semaphore/Mutex for multi NPU
185 *
186 * Following section handles the minimal sempahore and mutex implementation in
187 * case of baremetal applications. Weak symbols will be overridden by RTOS
188 * definitions and implement true thread-safety (in application layer).
189 ******************************************************************************/
190
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100191struct ethosu_semaphore_t
192{
193 int count;
194};
195
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100196static void *ethosu_mutex;
197static void *ethosu_semaphore;
198
Anton Moberg9f346ab2021-05-21 17:20:21 +0200199void *__attribute__((weak)) ethosu_mutex_create(void)
200{
201 return NULL;
202}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100203
Anton Moberg61ec36b2021-04-30 17:10:48 +0200204void __attribute__((weak)) ethosu_mutex_lock(void *mutex)
205{
206 UNUSED(mutex);
207}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100208
Anton Moberg61ec36b2021-04-30 17:10:48 +0200209void __attribute__((weak)) ethosu_mutex_unlock(void *mutex)
210{
211 UNUSED(mutex);
212}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100213
214// Baremetal implementation of creating a semaphore
215void *__attribute__((weak)) ethosu_semaphore_create(void)
216{
217 struct ethosu_semaphore_t *sem = malloc(sizeof(*sem));
218 sem->count = 1;
219 return sem;
220}
221
222// Baremetal simulation of waiting/sleeping for and then taking a semaphore using intrisics
223void __attribute__((weak)) ethosu_semaphore_take(void *sem)
224{
225 struct ethosu_semaphore_t *s = sem;
226 while (s->count <= 0)
227 {
228 __WFE();
229 }
230 s->count--;
231}
232
233// Baremetal simulation of giving a semaphore and waking up processes using intrinsics
234void __attribute__((weak)) ethosu_semaphore_give(void *sem)
235{
236 struct ethosu_semaphore_t *s = sem;
237 s->count++;
238 __SEV();
239}
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100240
Jonny Svärda830f172021-06-07 16:57:00 +0200241/******************************************************************************
242 * Weak functions - Inference begin/end callbacks
243 ******************************************************************************/
Anton Moberg61da4d32020-12-22 16:00:31 +0100244
Jonny Svärda830f172021-06-07 16:57:00 +0200245void __attribute__((weak)) ethosu_inference_begin(struct ethosu_driver *drv, const void *inference_data)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200246{
Jonny Svärda830f172021-06-07 16:57:00 +0200247 UNUSED(inference_data);
248 UNUSED(drv);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200249}
250
Jonny Svärda830f172021-06-07 16:57:00 +0200251void __attribute__((weak)) ethosu_inference_end(struct ethosu_driver *drv, const void *inference_data)
252{
253 UNUSED(inference_data);
254 UNUSED(drv);
255}
256
257/******************************************************************************
258 * Static functions
259 ******************************************************************************/
Bhavik Pateldae5be02020-06-18 15:25:15 +0200260static inline void wait_for_irq(struct ethosu_driver *drv)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200261{
262 while (1)
263 {
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100264 if (drv->irq_triggered || drv->abort_inference)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200265 {
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100266 drv->irq_triggered = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200267 break;
268 }
269
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100270 ethosu_semaphore_take(drv->semaphore);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200271 }
272}
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200273
Jonny Svärda830f172021-06-07 16:57:00 +0200274static void npu_axi_init(struct ethosu_driver *drv)
Jens Elofsson04961a42021-04-08 18:51:38 +0200275{
Jonny Svärda830f172021-06-07 16:57:00 +0200276 ethosu_dev_set_qconfig(&drv->dev, NPU_QCONFIG);
277
278 ethosu_dev_set_regioncfg(&drv->dev, 0, NPU_REGIONCFG_0);
279 ethosu_dev_set_regioncfg(&drv->dev, 1, NPU_REGIONCFG_1);
280 ethosu_dev_set_regioncfg(&drv->dev, 2, NPU_REGIONCFG_2);
281 ethosu_dev_set_regioncfg(&drv->dev, 3, NPU_REGIONCFG_3);
282 ethosu_dev_set_regioncfg(&drv->dev, 4, NPU_REGIONCFG_4);
283 ethosu_dev_set_regioncfg(&drv->dev, 5, NPU_REGIONCFG_5);
284 ethosu_dev_set_regioncfg(&drv->dev, 6, NPU_REGIONCFG_6);
285 ethosu_dev_set_regioncfg(&drv->dev, 7, NPU_REGIONCFG_7);
286
287 (void)ethosu_dev_set_axi_limit0(&drv->dev,
288 AXI_LIMIT0_MAX_BEATS_BYTES,
289 AXI_LIMIT0_MEM_TYPE,
290 AXI_LIMIT0_MAX_OUTSTANDING_READS,
291 AXI_LIMIT0_MAX_OUTSTANDING_WRITES);
292 (void)ethosu_dev_set_axi_limit1(&drv->dev,
293 AXI_LIMIT1_MAX_BEATS_BYTES,
294 AXI_LIMIT1_MEM_TYPE,
295 AXI_LIMIT1_MAX_OUTSTANDING_READS,
296 AXI_LIMIT1_MAX_OUTSTANDING_WRITES);
297 (void)ethosu_dev_set_axi_limit2(&drv->dev,
298 AXI_LIMIT2_MAX_BEATS_BYTES,
299 AXI_LIMIT2_MEM_TYPE,
300 AXI_LIMIT2_MAX_OUTSTANDING_READS,
301 AXI_LIMIT2_MAX_OUTSTANDING_WRITES);
302 (void)ethosu_dev_set_axi_limit3(&drv->dev,
303 AXI_LIMIT3_MAX_BEATS_BYTES,
304 AXI_LIMIT3_MEM_TYPE,
305 AXI_LIMIT3_MAX_OUTSTANDING_READS,
306 AXI_LIMIT3_MAX_OUTSTANDING_WRITES);
Jens Elofsson04961a42021-04-08 18:51:38 +0200307}
308
Jonny Svärda830f172021-06-07 16:57:00 +0200309static void ethosu_register_driver(struct ethosu_driver *drv)
Jens Elofsson04961a42021-04-08 18:51:38 +0200310{
Jonny Svärda830f172021-06-07 16:57:00 +0200311 // Register driver as new HEAD of list
312 drv->next = registered_drivers;
313 registered_drivers = drv;
314
Anton Moberg6eab40b2021-07-07 11:43:51 +0200315 LOG_INFO("New NPU driver registered (handle: 0x%p, NPU: 0x%x)\n", drv, drv->dev.base_address);
Jens Elofsson04961a42021-04-08 18:51:38 +0200316}
317
Jonny Svärda830f172021-06-07 16:57:00 +0200318static int ethosu_deregister_driver(struct ethosu_driver *drv)
319{
320 struct ethosu_driver *cur = registered_drivers;
321 struct ethosu_driver **prev = &registered_drivers;
322
323 while (cur != NULL)
324 {
325 if (cur == drv)
326 {
327 *prev = cur->next;
Anton Moberg6eab40b2021-07-07 11:43:51 +0200328 LOG_INFO("NPU driver handle %p deregistered.\n", drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200329 return 0;
330 }
331
332 prev = &cur->next;
333 cur = cur->next;
334 }
335
Anton Moberg6eab40b2021-07-07 11:43:51 +0200336 LOG_ERR("No NPU driver handle registered at address %p.\n", drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200337
338 return -1;
339}
340
341static struct ethosu_driver *ethosu_find_and_reserve_driver(void)
342{
343 struct ethosu_driver *drv = registered_drivers;
344
345 while (drv != NULL)
346 {
347 if (!drv->reserved)
348 {
349 drv->reserved = true;
Anton Moberg6eab40b2021-07-07 11:43:51 +0200350 LOG_DEBUG("NPU driver handle %p reserved.\n", drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200351 return drv;
352 }
353 drv = drv->next;
354 }
355
Anton Moberg6eab40b2021-07-07 11:43:51 +0200356 LOG_DEBUG("No NPU driver handle available.\n", drv);
Jonny Svärda830f172021-06-07 16:57:00 +0200357
358 return NULL;
359}
360
361static int ethosu_soft_reset_and_restore(struct ethosu_driver *drv)
362{
363
364 if (ETHOSU_SUCCESS != ethosu_dev_soft_reset(&drv->dev))
365 {
366 return -1;
367 }
368
369 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE);
370
371 npu_axi_init(drv);
372 ethosu_dev_restore_pmu_config(&drv->dev);
373
374 return 0;
375}
376
377static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s *opt_cfg_p)
378{
379 struct ethosu_config cfg;
380 struct ethosu_id id;
381 int return_code = 0;
382
Anton Moberg6eab40b2021-07-07 11:43:51 +0200383 LOG_INFO("Optimizer release nbr: %d patch: %d\n", opt_cfg_p->da_data.rel_nbr, opt_cfg_p->da_data.patch_nbr);
384 LOG_INFO("Optimizer config cmd_stream_version: %d macs_per_cc: %d shram_size: %d custom_dma: %d\n",
Jonny Svärda830f172021-06-07 16:57:00 +0200385 opt_cfg_p->cmd_stream_version,
386 opt_cfg_p->macs_per_cc,
387 opt_cfg_p->shram_size,
388 opt_cfg_p->custom_dma);
Anton Moberg6eab40b2021-07-07 11:43:51 +0200389 LOG_INFO("Optimizer config Ethos-U version: %d.%d.%d\n",
Jonny Svärda830f172021-06-07 16:57:00 +0200390 opt_cfg_p->arch_major_rev,
391 opt_cfg_p->arch_minor_rev,
392 opt_cfg_p->arch_patch_rev);
393
394 (void)ethosu_dev_get_config(&drv->dev, &cfg);
395 (void)ethosu_dev_get_id(&drv->dev, &id);
396 LOG_INFO("Ethos-U config cmd_stream_version: %" PRIu32 " macs_per_cc: %" PRIu32 " shram_size: %" PRIu32
Anton Moberg6eab40b2021-07-07 11:43:51 +0200397 " custom_dma: %" PRIu32 "\n",
Jonny Svärda830f172021-06-07 16:57:00 +0200398 cfg.cmd_stream_version,
399 cfg.macs_per_cc,
400 cfg.shram_size,
401 cfg.custom_dma);
Anton Moberg6eab40b2021-07-07 11:43:51 +0200402 LOG_INFO("Ethos-U version: %" PRIu32 ".%" PRIu32 ".%" PRIu32 "\n",
Jonny Svärda830f172021-06-07 16:57:00 +0200403 id.arch_major_rev,
404 id.arch_minor_rev,
405 id.arch_patch_rev);
406
407 if ((cfg.macs_per_cc != opt_cfg_p->macs_per_cc) || (cfg.shram_size != opt_cfg_p->shram_size) ||
408 (cfg.cmd_stream_version != opt_cfg_p->cmd_stream_version) || (!cfg.custom_dma && opt_cfg_p->custom_dma))
409 {
410 if (cfg.macs_per_cc != opt_cfg_p->macs_per_cc)
411 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200412 LOG_ERR("NPU config mismatch: npu.macs_per_cc=%" PRIu32 " optimizer.macs_per_cc=%d\n",
Jonny Svärda830f172021-06-07 16:57:00 +0200413 cfg.macs_per_cc,
414 opt_cfg_p->macs_per_cc);
415 }
416 if (cfg.shram_size != opt_cfg_p->shram_size)
417 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200418 LOG_ERR("NPU config mismatch: npu.shram_size=%" PRIu32 " optimizer.shram_size=%d\n",
Jonny Svärda830f172021-06-07 16:57:00 +0200419 cfg.shram_size,
420 opt_cfg_p->shram_size);
421 }
422 if (cfg.cmd_stream_version != opt_cfg_p->cmd_stream_version)
423 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200424 LOG_ERR("NPU config mismatch: npu.cmd_stream_version=%" PRIu32 " optimizer.cmd_stream_version=%d\n",
Jonny Svärda830f172021-06-07 16:57:00 +0200425 cfg.cmd_stream_version,
426 opt_cfg_p->cmd_stream_version);
427 }
428 if (!cfg.custom_dma && opt_cfg_p->custom_dma)
429 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200430 LOG_ERR("NPU config mismatch: npu.custom_dma=%" PRIu32 " optimize.custom_dma=%d\n",
Jonny Svärda830f172021-06-07 16:57:00 +0200431 cfg.custom_dma,
432 opt_cfg_p->custom_dma);
433 }
434 return_code = -1;
435 }
436
437 if ((id.arch_major_rev != opt_cfg_p->arch_major_rev) || (id.arch_minor_rev < opt_cfg_p->arch_minor_rev))
438 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200439 LOG_ERR("NPU arch mismatch: npu.arch=%" PRIu32 ".%" PRIu32 ".%" PRIu32 " optimizer.arch=%d.%d.%d\n",
Jonny Svärda830f172021-06-07 16:57:00 +0200440 id.arch_major_rev,
441 id.arch_minor_rev,
442 id.arch_patch_rev,
443 opt_cfg_p->arch_major_rev,
444 opt_cfg_p->arch_minor_rev,
445 opt_cfg_p->arch_patch_rev);
446 return_code = -1;
447 }
448
449#if !defined(LOG_ENABLED)
450 UNUSED(opt_cfg_p);
451#endif
452 return return_code;
453}
454
Bhavik Pateldae5be02020-06-18 15:25:15 +0200455static int handle_command_stream(struct ethosu_driver *drv,
456 const uint8_t *cmd_stream,
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200457 const int cms_length,
458 const uint64_t *base_addr,
Per Åstrand3c8afcc2020-10-20 10:29:59 +0200459 const size_t *base_addr_size,
Jonny Svärda830f172021-06-07 16:57:00 +0200460 const int num_base_addr)
461{
462 uint32_t qread = 0;
463 uint32_t cms_bytes = cms_length * BYTES_IN_32_BITS;
464 ptrdiff_t cmd_stream_ptr = (ptrdiff_t)cmd_stream;
465
Anton Moberg6eab40b2021-07-07 11:43:51 +0200466 LOG_INFO("handle_command_stream: cmd_stream=%p, cms_length %d\n", cmd_stream, cms_length);
Jonny Svärda830f172021-06-07 16:57:00 +0200467
468 if (0 != ((ptrdiff_t)cmd_stream & MASK_16_BYTE_ALIGN))
469 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200470 LOG_ERR("Command stream addr %p not aligned to 16 bytes\n", cmd_stream);
Jonny Svärda830f172021-06-07 16:57:00 +0200471 return -1;
472 }
473
474 bool base_addr_invalid = false;
475 for (int i = 0; i < num_base_addr; i++)
476 {
477 if (0 != (base_addr[i] & MASK_16_BYTE_ALIGN))
478 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200479 LOG_ERR("Base addr %d: 0x%llx not aligned to 16 bytes\n", i, base_addr[i]);
Jonny Svärda830f172021-06-07 16:57:00 +0200480 base_addr_invalid = true;
481 }
482 }
483
484 if (base_addr_invalid)
485 {
486 return -1;
487 }
488
489 /* Flush the cache if available on our CPU.
490 * The upcasting to uin32_t* is ok since the pointer never is dereferenced.
491 * The base_addr_size is null if invoking from prior to invoke_V2, in that case
492 * the whole cache is being flushed.
493 */
494
495 if (base_addr_size != NULL)
496 {
497 ethosu_flush_dcache((uint32_t *)cmd_stream_ptr, cms_bytes);
498 for (int i = 0; i < num_base_addr; i++)
499 {
500 ethosu_flush_dcache((uint32_t *)(uintptr_t)base_addr[i], base_addr_size[i]);
501 }
502 }
503 else
504 {
505 ethosu_flush_dcache(NULL, 0);
506 }
507
508 if (ETHOSU_SUCCESS != ethosu_dev_run_command_stream(&drv->dev, cmd_stream, cms_bytes, base_addr, num_base_addr))
509 {
510 return -1;
511 }
512
513 wait_for_irq(drv);
514
515 if (drv->status_error)
516 {
517 return -1;
518 }
519
520 if (base_addr_size != NULL)
521 {
522 for (int i = 0; i < num_base_addr; i++)
523 {
524 ethosu_invalidate_dcache((uint32_t *)(uintptr_t)base_addr[i], base_addr_size[i]);
525 }
526 }
527 else
528 {
529 ethosu_invalidate_dcache(NULL, 0);
530 }
531
532 qread = ethosu_dev_get_qread(&drv->dev);
533 if (qread != cms_bytes)
534 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200535 LOG_WARN("IRQ received but qread (%" PRIu32 ") not at end of stream (%" PRIu32 ").\n", qread, cms_bytes);
Jonny Svärda830f172021-06-07 16:57:00 +0200536 return -1;
537 }
538
539 return 0;
540}
541
542static int read_apb_reg(struct ethosu_driver *drv, uint16_t da_data)
543{
544 uint32_t *reg_p;
545 uint32_t start_address = (uint32_t)(da_data & APB_START_ADDR_MASK);
546 uint16_t num_reg = (da_data >> APB_NUM_REG_BIT_SHIFT) + 1;
547
548 reg_p = (uint32_t *)malloc(num_reg * sizeof(uint32_t));
549 if (reg_p == NULL)
550 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200551 LOG_ERR("Memory allocation failed\n");
Jonny Svärda830f172021-06-07 16:57:00 +0200552 return -1;
553 }
554
555 if (ETHOSU_SUCCESS == ethosu_dev_read_apb_reg(&drv->dev, start_address, num_reg, reg_p))
556 {
557 for (int i = 0; i < num_reg; i++)
558 {
559 LOG_INFO(
Anton Moberg6eab40b2021-07-07 11:43:51 +0200560 "NPU_REG ADDR 0x%04" PRIu32 " = 0x%08" PRIu32 "\n", (start_address + (i * BYTES_IN_32_BITS)), reg_p[i]);
Jonny Svärda830f172021-06-07 16:57:00 +0200561 }
562 }
563 else
564 {
565 free(reg_p);
566 return -1;
567 }
568
569 free(reg_p);
570 return 0;
571}
572
573static int dump_shram(struct ethosu_driver *drv)
574{
575 struct ethosu_config cfg;
576 uint32_t *shram_p;
577 (void)ethosu_dev_get_config(&drv->dev, &cfg);
578
Anton Moberg6eab40b2021-07-07 11:43:51 +0200579 LOG_INFO("dump_shram size = %" PRIu32 " KB\n", cfg.shram_size);
Jonny Svärda830f172021-06-07 16:57:00 +0200580
581 shram_p = (uint32_t *)malloc(BYTES_1KB);
582 if (shram_p == NULL)
583 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200584 LOG_ERR("Memory allocation failed for shram data\n");
Jonny Svärda830f172021-06-07 16:57:00 +0200585 return -1;
586 }
587
588 for (uint32_t i = 0; i < cfg.shram_size; i++)
589 {
590 ethosu_dev_get_shram_data(&drv->dev, i, (uint32_t *)shram_p);
591 // Output 1KB of SHRAM
Anton Moberg6eab40b2021-07-07 11:43:51 +0200592 LOG_INFO("***SHRAM SECTION %" PRIu32 "***\n", i);
Jonny Svärda830f172021-06-07 16:57:00 +0200593 for (int j = 0; j < (BYTES_1KB / BYTES_IN_32_BITS); j++)
594 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200595 LOG_INFO("[0x%04" PRIx32 "] %" PRIx32 "\n", (i * 1024 + j * 4), shram_p[j]);
Jonny Svärda830f172021-06-07 16:57:00 +0200596 }
597 }
598 free(shram_p);
599
600 return 0;
601}
602
603/******************************************************************************
604 * Weak functions - Interrupt handler
605 ******************************************************************************/
606void __attribute__((weak)) ethosu_irq_handler(struct ethosu_driver *drv)
607{
608 uint8_t irq_raised = 0;
609
Anton Moberg6eab40b2021-07-07 11:43:51 +0200610 LOG_DEBUG(
611 "Interrupt. status=0x%08x, qread=%d\n", ethosu_dev_get_status(&drv->dev), ethosu_dev_get_qread(&drv->dev));
Jonny Svärda830f172021-06-07 16:57:00 +0200612
613 // Verify that interrupt has been raised
614 (void)ethosu_dev_is_irq_raised(&drv->dev, &irq_raised);
615 assert(irq_raised == 1);
616 drv->irq_triggered = true;
617
618 // Clear interrupt
619 (void)ethosu_dev_clear_irq_status(&drv->dev);
620
621 // Verify that interrupt has been successfully cleared
622 (void)ethosu_dev_is_irq_raised(&drv->dev, &irq_raised);
623 assert(irq_raised == 0);
624
625 if (ethosu_dev_status_has_error(&drv->dev))
626 {
627 ethosu_soft_reset_and_restore(drv);
628 drv->status_error = true;
629 }
630
631 ethosu_semaphore_give(drv->semaphore);
632}
633
634/******************************************************************************
635 * Functions API
636 ******************************************************************************/
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200637
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200638int ethosu_init(struct ethosu_driver *drv,
639 const void *base_address,
640 const void *fast_memory,
641 const size_t fast_memory_size,
642 uint32_t secure_enable,
643 uint32_t privilege_enable)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200644{
645 int return_code = 0;
Bhavik Pateldae5be02020-06-18 15:25:15 +0200646
Jonny Svärda830f172021-06-07 16:57:00 +0200647 LOG_INFO("Initializing NPU: base_address=%p, fast_memory=%p, fast_memory_size=%zu, secure=%" PRIu32
Anton Moberg6eab40b2021-07-07 11:43:51 +0200648 ", privileged=%" PRIu32 "\n",
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200649 base_address,
650 fast_memory,
Per Åstrande6498f02020-11-09 15:33:12 +0100651 fast_memory_size,
652 secure_enable,
653 privilege_enable);
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200654
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100655 if (!ethosu_mutex)
656 {
657 ethosu_mutex = ethosu_mutex_create();
658 }
659
660 if (!ethosu_semaphore)
661 {
662 ethosu_semaphore = ethosu_semaphore_create();
663 }
664
Anton Moberg61da4d32020-12-22 16:00:31 +0100665 drv->fast_memory = (uint32_t)fast_memory;
666 drv->fast_memory_size = fast_memory_size;
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100667 drv->irq_triggered = false;
668 drv->semaphore = ethosu_semaphore_create();
Anton Moberg61da4d32020-12-22 16:00:31 +0100669
670 if (ETHOSU_SUCCESS != ethosu_dev_init(&drv->dev, base_address, secure_enable, privilege_enable))
Bhavik Pateldae5be02020-06-18 15:25:15 +0200671 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200672 LOG_ERR("Failed to initialize Ethos-U device\n");
Bhavik Pateldae5be02020-06-18 15:25:15 +0200673 return -1;
674 }
675
Anton Moberg0a614292021-03-24 14:08:22 +0100676 if (ETHOSU_SUCCESS !=
677 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_DISABLE, ETHOSU_POWER_Q_DISABLE))
Bhavik Patele645fed2020-06-12 14:46:47 +0200678 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200679 LOG_ERR("Failed to disable clock-q & power-q for Ethos-U\n");
Bhavik Patele645fed2020-06-12 14:46:47 +0200680 return -1;
681 }
682
Jonny Svärda830f172021-06-07 16:57:00 +0200683 if (ETHOSU_SUCCESS != ethosu_dev_soft_reset(&drv->dev))
Per Åstrand849cf692020-11-24 07:39:55 +0100684 {
685 return -1;
686 }
Kristofer Jonssondaa0d202020-05-12 12:23:16 +0200687
Jonny Svärda830f172021-06-07 16:57:00 +0200688 if (ETHOSU_SUCCESS != ethosu_dev_wait_for_reset(&drv->dev))
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200689 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200690 LOG_ERR("Failed reset of Ethos-U\n");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200691 return -1;
692 }
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100693
Anton Moberg61da4d32020-12-22 16:00:31 +0100694 drv->status_error = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200695
Jonny Svärda830f172021-06-07 16:57:00 +0200696 ethosu_register_driver(drv);
697
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200698 return return_code;
699}
700
Anton Moberg547ca532021-06-14 09:43:53 +0200701void ethosu_deinit(struct ethosu_driver *drv)
702{
703 ethosu_deregister_driver(drv);
704}
705
Jonny Svärda830f172021-06-07 16:57:00 +0200706void ethosu_get_driver_version(struct ethosu_driver_version *ver)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200707{
Jonny Svärda830f172021-06-07 16:57:00 +0200708 assert(ver != NULL);
709 ver->major = ETHOSU_DRIVER_VERSION_MAJOR;
710 ver->minor = ETHOSU_DRIVER_VERSION_MINOR;
711 ver->patch = ETHOSU_DRIVER_VERSION_PATCH;
712}
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200713
Jonny Svärda830f172021-06-07 16:57:00 +0200714void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw)
715{
716 assert(hw != NULL);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200717
Jonny Svärda830f172021-06-07 16:57:00 +0200718 (void)ethosu_dev_get_id(&drv->dev, &hw->version);
719 (void)ethosu_dev_get_config(&drv->dev, &hw->cfg);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200720}
721
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200722int ethosu_invoke(struct ethosu_driver *drv,
723 const void *custom_data_ptr,
724 const int custom_data_size,
725 const uint64_t *base_addr,
726 const size_t *base_addr_size,
727 const int num_base_addr)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200728{
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200729 const struct custom_data_s *data_ptr = custom_data_ptr;
730 const struct custom_data_s *data_end = custom_data_ptr + custom_data_size;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200731 int return_code = 0;
732
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200733 // First word in custom_data_ptr should contain "Custom Operator Payload 1"
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200734 if (data_ptr->word != ETHOSU_FOURCC)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200735 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200736 LOG_ERR("Custom Operator Payload: %" PRIu32 " is not correct, expected %x\n", data_ptr->word, ETHOSU_FOURCC);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200737 return -1;
738 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200739
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200740 // Custom data length must be a multiple of 32 bits
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200741 if ((custom_data_size % BYTES_IN_32_BITS) != 0)
742 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200743 LOG_ERR("custom_data_size=0x%x not a multiple of 4\n", custom_data_size);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200744 return -1;
745 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200746
747 ++data_ptr;
748
749 // Adjust base address to fast memory area
Anton Moberg61da4d32020-12-22 16:00:31 +0100750 if (drv->fast_memory != 0 && num_base_addr >= FAST_MEMORY_BASE_ADDR_INDEX)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200751 {
752 uint64_t *fast_memory = (uint64_t *)&base_addr[FAST_MEMORY_BASE_ADDR_INDEX];
753
Anton Moberg61da4d32020-12-22 16:00:31 +0100754 if (base_addr_size != NULL && base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > drv->fast_memory_size)
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200755 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200756 LOG_ERR("Fast memory area too small. fast_memory_size=%u, base_addr_size=%u\n",
Anton Moberg61da4d32020-12-22 16:00:31 +0100757 drv->fast_memory_size,
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100758 base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX]);
759 return -1;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200760 }
Kristofer Jonsson4c94b302020-11-06 10:33:21 +0100761
Anton Moberg61da4d32020-12-22 16:00:31 +0100762 *fast_memory = drv->fast_memory;
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200763 }
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200764
Anton Moberg61da4d32020-12-22 16:00:31 +0100765 if (!drv->dev_power_always_on)
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200766 {
Jonny Svärda830f172021-06-07 16:57:00 +0200767 // Only soft reset if security state or privilege level needs changing
768 if (ethosu_dev_prot_has_changed(&drv->dev))
Per Åstrand849cf692020-11-24 07:39:55 +0100769 {
Jonny Svärda830f172021-06-07 16:57:00 +0200770 if (ETHOSU_SUCCESS != ethosu_dev_soft_reset(&drv->dev))
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100771 {
772 return -1;
773 }
Per Åstrand849cf692020-11-24 07:39:55 +0100774 }
Anton Moberg61da4d32020-12-22 16:00:31 +0100775
776 drv->status_error = false;
Anton Moberg0a614292021-03-24 14:08:22 +0100777 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE);
Jonny Svärda830f172021-06-07 16:57:00 +0200778 ethosu_dev_restore_pmu_config(&drv->dev);
Anton Moberg61da4d32020-12-22 16:00:31 +0100779 npu_axi_init(drv);
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200780 }
Kristofer Jonssonc6e7a1f2020-11-24 09:20:14 +0100781
Anton Moberg61da4d32020-12-22 16:00:31 +0100782 drv->status_error = false;
Kristofer Jonsson125429a2020-08-20 16:52:23 +0200783
Jens Elofsson04961a42021-04-08 18:51:38 +0200784 ethosu_inference_begin(drv, custom_data_ptr);
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200785 while (data_ptr < data_end)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200786 {
Bhavik Patele645fed2020-06-12 14:46:47 +0200787 int ret = 0;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200788 switch (data_ptr->driver_action_command)
789 {
790 case OPTIMIZER_CONFIG:
Anton Moberg6eab40b2021-07-07 11:43:51 +0200791 LOG_DEBUG("OPTIMIZER_CONFIG\n");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200792 struct opt_cfg_s *opt_cfg_p = (struct opt_cfg_s *)data_ptr;
793
Anton Moberg61da4d32020-12-22 16:00:31 +0100794 ret = handle_optimizer_config(drv, opt_cfg_p);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200795 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD;
796 break;
797 case COMMAND_STREAM:
Anton Moberg6eab40b2021-07-07 11:43:51 +0200798 LOG_DEBUG("COMMAND_STREAM\n");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200799 void *command_stream = (uint8_t *)(data_ptr) + sizeof(struct custom_data_s);
800 int cms_length = (data_ptr->reserved << 16) | data_ptr->length;
801
Anton Moberg61da4d32020-12-22 16:00:31 +0100802 drv->abort_inference = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200803 // It is safe to clear this flag without atomic, because npu is not running.
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100804 drv->irq_triggered = false;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200805
Anton Moberg61da4d32020-12-22 16:00:31 +0100806 ret = handle_command_stream(drv, command_stream, cms_length, base_addr, base_addr_size, num_base_addr);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200807
Anton Moberg61da4d32020-12-22 16:00:31 +0100808 if (return_code == -1 && drv->abort_inference)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200809 {
Anton Moberg6eab40b2021-07-07 11:43:51 +0200810 LOG_ERR("NPU timeout. qread=%" PRIu32 "\n", ethosu_dev_get_qread(&drv->dev));
Anton Moberg61da4d32020-12-22 16:00:31 +0100811 dump_shram(drv);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200812 }
813
814 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + cms_length;
815 break;
816 case READ_APB_REG:
Anton Moberg6eab40b2021-07-07 11:43:51 +0200817 LOG_DEBUG("READ_APB_REG\n");
Anton Moberg61da4d32020-12-22 16:00:31 +0100818 ret = read_apb_reg(drv, data_ptr->driver_action_data);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200819 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
820 break;
821 case DUMP_SHRAM:
Anton Moberg6eab40b2021-07-07 11:43:51 +0200822 LOG_DEBUG("DUMP_SHRAM\n");
Anton Moberg61da4d32020-12-22 16:00:31 +0100823 ret = dump_shram(drv);
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200824 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
825 break;
826 case NOP:
Anton Moberg6eab40b2021-07-07 11:43:51 +0200827 LOG_DEBUG("NOP\n");
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200828 data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
829 break;
830 default:
Anton Moberg6eab40b2021-07-07 11:43:51 +0200831 LOG_ERR("UNSUPPORTED driver_action_command: %d \n", data_ptr->driver_action_command);
Bhavik Patele645fed2020-06-12 14:46:47 +0200832 ret = -1;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200833 break;
834 }
Bhavik Patele645fed2020-06-12 14:46:47 +0200835 if (ret != 0)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200836 {
Bhavik Patele645fed2020-06-12 14:46:47 +0200837 return_code = -1;
838 break;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200839 }
840 }
Jens Elofsson04961a42021-04-08 18:51:38 +0200841 ethosu_inference_end(drv, custom_data_ptr);
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200842
Anton Moberg61da4d32020-12-22 16:00:31 +0100843 if (!drv->status_error && !drv->dev_power_always_on)
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200844 {
Jonny Svärda830f172021-06-07 16:57:00 +0200845 ethosu_dev_save_pmu_counters(&drv->dev);
Anton Moberg0a614292021-03-24 14:08:22 +0100846 set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
Bhavik Patel5f8dad12020-09-30 09:06:52 +0200847 }
Kristofer Jonsson2b201c32020-09-02 16:42:43 +0200848
Bhavik Patele645fed2020-06-12 14:46:47 +0200849 return return_code;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200850}
851
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200852void ethosu_abort(struct ethosu_driver *drv)
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200853{
Anton Moberg61da4d32020-12-22 16:00:31 +0100854 drv->abort_inference = true;
Kristofer Jonsson49bdee82020-04-06 13:21:21 +0200855}
856
Anton Mobergeffc7aa2021-05-03 09:25:06 +0200857void ethosu_set_power_mode(struct ethosu_driver *drv, bool always_on)
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100858{
Anton Moberg61da4d32020-12-22 16:00:31 +0100859 drv->dev_power_always_on = always_on;
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100860
861 if (always_on)
862 {
Anton Moberg61da4d32020-12-22 16:00:31 +0100863 npu_axi_init(drv);
864 }
865}
866
Anton Moberg61da4d32020-12-22 16:00:31 +0100867struct ethosu_driver *ethosu_reserve_driver(void)
868{
Anton Mobergdf386e02021-02-02 11:26:48 +0100869 struct ethosu_driver *drv = NULL;
870
871 do
872 {
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100873 ethosu_mutex_lock(ethosu_mutex);
Anton Mobergdf386e02021-02-02 11:26:48 +0100874 drv = ethosu_find_and_reserve_driver();
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100875 ethosu_mutex_unlock(ethosu_mutex);
Anton Mobergdf386e02021-02-02 11:26:48 +0100876
877 if (drv != NULL)
878 {
879 break;
880 }
881
Anton Moberg6eab40b2021-07-07 11:43:51 +0200882 LOG_INFO("Waiting for NPU driver handle to become available...\n");
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100883 ethosu_semaphore_take(ethosu_semaphore);
Anton Mobergdf386e02021-02-02 11:26:48 +0100884
885 } while (1);
886
887 return drv;
888}
889
Anton Moberg61da4d32020-12-22 16:00:31 +0100890void ethosu_release_driver(struct ethosu_driver *drv)
891{
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100892 ethosu_mutex_lock(ethosu_mutex);
Anton Moberg61da4d32020-12-22 16:00:31 +0100893 if (drv != NULL && drv->reserved)
894 {
895 drv->reserved = false;
Anton Moberg6eab40b2021-07-07 11:43:51 +0200896 LOG_DEBUG("NPU driver handle %p released\n", drv);
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100897 ethosu_semaphore_give(ethosu_semaphore);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100898 }
Anton Mobergdfed5fd2021-03-11 14:41:11 +0100899 ethosu_mutex_unlock(ethosu_mutex);
Anton Moberg8d65b6f2020-12-21 09:37:18 +0100900}
901
Anton Moberg0a614292021-03-24 14:08:22 +0100902enum ethosu_error_codes set_clock_and_power_request(struct ethosu_driver *drv,
903 enum ethosu_request_clients client,
904 enum ethosu_clock_q_request clock_request,
905 enum ethosu_power_q_request power_request)
906{
907 // Set clock request bit for client
908 if (clock_request == ETHOSU_CLOCK_Q_DISABLE)
909 {
910 drv->clock_request |= (1 << client);
911 }
912 else
913 {
914 drv->clock_request &= ~(1 << client);
915 }
916 // Get current clock request (ENABLE if both PMU and INFERENCE asks for clock request, else DISABLE)
917 clock_request = drv->clock_request == 0 ? ETHOSU_CLOCK_Q_ENABLE : ETHOSU_CLOCK_Q_DISABLE;
918
919 // Set power request bit for client
Anton Moberg35b5d0e2021-04-13 13:32:17 +0200920 if (power_request == ETHOSU_POWER_Q_DISABLE)
Anton Moberg0a614292021-03-24 14:08:22 +0100921 {
922 drv->power_request |= (1 << client);
923 }
924 else
925 {
926 drv->power_request &= ~(1 << client);
927 }
928 // Get current power request (ENABLE if both PMU and INFERENCE asks for power request, else DISABLE)
929 power_request = drv->power_request == 0 ? ETHOSU_POWER_Q_ENABLE : ETHOSU_POWER_Q_DISABLE;
Anton Moberg35b5d0e2021-04-13 13:32:17 +0200930
Anton Moberg0a614292021-03-24 14:08:22 +0100931 // Set clock and power
Jonny Svärda830f172021-06-07 16:57:00 +0200932 enum ethosu_error_codes ret = ethosu_dev_set_clock_and_power(&drv->dev, clock_request, power_request);
Anton Moberg0a614292021-03-24 14:08:22 +0100933
934 return ret;
935}