ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_npu.c
Go to the documentation of this file.
1
26
27#include "ra8_attributes.h"
28#include "ra8_device.h"
29
30#ifdef RA8_HAS_NPU
31
32#include <stdint.h>
33
34#include "ra8_check.h"
35#include "ra8_err.h"
36#include "ra8_log.h"
37#include "ra8_mstp.h"
38#include "ra8_npu.h"
39#include "ra8_npu_regs.h"
40
48static const char* s_tag = "NPU";
49
63typedef enum : uint16_t {
64 k_ra8_npu_mstp_reg_shift = 8U,
65 k_ra8_npu_mstp_bit = 16U,
66} ra8_npu_mstp_enc_t;
67
80typedef enum : uint32_t {
81 k_ra8_npu_reset_poll_iters = 100000U,
82 k_ra8_npu_job_poll_iters = 2000000U,
83} ra8_npu_budget_t;
84
95typedef enum : uint8_t {
96 k_ra8_npu_addr_hi_shift = 32U,
97} ra8_npu_split_t;
98
110typedef enum : uint32_t {
111 k_ra8_npu_status_fault_mask =
112 ((uint32_t)1U << k_ra8_npu_status_bus_error_bit) |
113 ((uint32_t)1U << k_ra8_npu_status_cmd_parse_bit) |
114 ((uint32_t)1U << k_ra8_npu_status_wd_fault_bit) |
115 ((uint32_t)1U << k_ra8_npu_status_ecc_fault_bit),
116} ra8_npu_mask_t;
117
125static const ra8_mstp_t s_npu_mstp_id =
126 (ra8_mstp_t)(((uint16_t)k_ra8_mstp_reg_a << k_ra8_npu_mstp_reg_shift) | k_ra8_npu_mstp_bit);
127
135static bool s_npu_initialized = false;
136
144static bool s_npu_job_submitted = false;
145
157typedef enum : uint8_t {
158 k_ra8_npu_irq_idle = 0U,
159 k_ra8_npu_irq_armed = 1U,
160 k_ra8_npu_irq_done = 2U,
161 k_ra8_npu_irq_fault = 3U,
162} ra8_npu_irq_state_t;
163
172static volatile ra8_npu_irq_state_t s_npu_irq_state = k_ra8_npu_irq_idle;
173
193static inline void internal_npu_wait_for_irq(void)
194{
195#ifdef __ARM_ARCH
196 __asm__ volatile("wfi");
197#endif
198}
199
219static ra8_err_t internal_npu_apply_reset(void)
220{
221 /* Ethos-U55 NPU TRM "NPU_RESET" reg @ 0x0C -- request reset, privileged +
222 * secure pending level (both pending-level bits written 0). */
224 for (uint32_t i = 0U; i < k_ra8_npu_reset_poll_iters; i++) {
225 /* Ethos-U55 NPU TRM "NPU_STATUS" reg @ 0x04 -- reset bit clears when done. */
226 const uint32_t status = *ra8_npu_reg(k_ra8_npu_off_status);
227 if ((status & ((uint32_t)1U << k_ra8_npu_status_reset_bit)) == 0U) {
228 return k_ra8_ok;
229 }
230 }
232}
233
255static void internal_npu_write_region(ra8_npu_region_idx_t idx, uint64_t base)
256{
257 const uint32_t lo_off =
258 (uint32_t)k_ra8_npu_off_basep0_lo + ((uint32_t)idx * (uint32_t)k_ra8_npu_basep_stride_bytes);
259 const uint32_t hi_off = lo_off + (uint32_t)k_ra8_npu_reg_hi_offset;
260 /* Ethos-U55 NPU TRM "BASEPn" regs @ 0x80 + n*8 -- tensor arena AXI base. */
261 *ra8_npu_reg(lo_off) = (uint32_t)base;
262 *ra8_npu_reg(hi_off) = (uint32_t)(base >> k_ra8_npu_addr_hi_shift);
263}
264
266{
267 const ra8_err_t mst = ra8_mstp_enable(s_npu_mstp_id);
268 RA8_RETURN_ON_ERROR(mst, s_tag, "npu_init: mstp enable");
269 const ra8_err_t rst = internal_npu_apply_reset();
270 RA8_RETURN_ON_ERROR(rst, s_tag, "npu_init: reset");
271 s_npu_initialized = true;
272 s_npu_job_submitted = false;
273 s_npu_irq_state = k_ra8_npu_irq_idle;
274 ra8_log_info(s_tag, "npu_init");
275 return k_ra8_ok;
276}
277
279{
280 RA8_VALIDATE_INIT(s_npu_initialized, s_tag, "npu_deinit: not initialized");
281 const ra8_err_t dis = ra8_mstp_disable(s_npu_mstp_id);
282 RA8_RETURN_ON_ERROR(dis, s_tag, "npu_deinit: mstp disable");
283 s_npu_initialized = false;
284 s_npu_job_submitted = false;
285 s_npu_irq_state = k_ra8_npu_irq_idle;
286 return k_ra8_ok;
287}
288
290{
291 RA8_VALIDATE_INIT(s_npu_initialized, s_tag, "npu_reset: not initialized");
292 const ra8_err_t rst = internal_npu_apply_reset();
293 RA8_RETURN_ON_ERROR(rst, s_tag, "npu_reset");
294 s_npu_job_submitted = false;
295 s_npu_irq_state = k_ra8_npu_irq_idle;
296 return k_ra8_ok;
297}
298
299ra8_err_t ra8_npu_read_id(uint32_t* out_id)
300{
301 RA8_CHECK_NULL_PTR(out_id, s_tag, "out_id must not be nullptr");
302 RA8_VALIDATE_INIT(s_npu_initialized, s_tag, "npu_read_id: not initialized");
303 /* Ethos-U55 NPU TRM "NPU_ID" reg @ 0x00 -- architecture / product id. */
304 *out_id = *ra8_npu_reg(k_ra8_npu_off_id);
305 return k_ra8_ok;
306}
307
309{
310 RA8_CHECK_NULL_PTR(job, s_tag, "job must not be nullptr");
311 RA8_CHECK_NULL_PTR(job->cmd_stream, s_tag, "job->cmd_stream must not be nullptr");
312 RA8_VALIDATE_INIT(s_npu_initialized, s_tag, "npu_submit: not initialized");
313 if (job->cmd_stream_bytes == 0U) {
314 ra8_log_error(s_tag, "npu_submit: empty command stream");
316 }
317 if (job->region_count > (uint8_t)k_ra8_npu_region_count) {
318 ra8_log_error(s_tag, "npu_submit: too many regions");
320 }
321 const uint64_t qbase = (uint64_t)(uintptr_t)job->cmd_stream;
322 /* Ethos-U55 NPU TRM "QBASE" regs @ 0x10 / 0x14 -- command-stream address. */
323 *ra8_npu_reg(k_ra8_npu_off_qbase_lo) = (uint32_t)qbase;
324 *ra8_npu_reg(k_ra8_npu_off_qbase_hi) = (uint32_t)(qbase >> k_ra8_npu_addr_hi_shift);
325 /* Ethos-U55 NPU TRM "QSIZE" reg @ 0x20 -- command-stream length in bytes. */
327 for (uint8_t r = 0U; r < job->region_count; r++) {
328 internal_npu_write_region((ra8_npu_region_idx_t)r, job->region_base[r]);
329 }
330 s_npu_job_submitted = true;
331 return k_ra8_ok;
332}
333
335{
336 RA8_VALIDATE_INIT(s_npu_initialized, s_tag, "npu_run: not initialized");
337 if (!s_npu_job_submitted) {
338 ra8_log_error(s_tag, "npu_run: no job submitted");
340 }
341 /* Ethos-U55 NPU TRM "NPU_CMD" reg @ 0x08 -- transition_to_running_state. */
343 return k_ra8_ok;
344}
345
347{
348 RA8_CHECK_NULL_PTR(out, s_tag, "out must not be nullptr");
349 RA8_VALIDATE_INIT(s_npu_initialized, s_tag, "npu_read_status: not initialized");
350 /* Ethos-U55 NPU TRM "NPU_STATUS" reg @ 0x04 -- state + fault flags. */
351 const uint32_t raw = *ra8_npu_reg(k_ra8_npu_off_status);
352 out->raw = raw;
353 out->running = (raw & ((uint32_t)1U << k_ra8_npu_status_state_bit)) != 0U;
354 out->irq_raised = (raw & ((uint32_t)1U << k_ra8_npu_status_irq_raised_bit)) != 0U;
355 out->cmd_end = (raw & ((uint32_t)1U << k_ra8_npu_status_cmd_end_bit)) != 0U;
356 out->fault = (raw & (uint32_t)k_ra8_npu_status_fault_mask) != 0U;
357 return k_ra8_ok;
358}
359
360ra8_err_t ra8_npu_poll(bool* out_done)
361{
362 RA8_CHECK_NULL_PTR(out_done, s_tag, "out_done must not be nullptr");
363 RA8_VALIDATE_INIT(s_npu_initialized, s_tag, "npu_poll: not initialized");
364 /* Ethos-U55 NPU TRM "NPU_STATUS" reg @ 0x04 -- fault + cmd-end flags. */
365 const uint32_t raw = *ra8_npu_reg(k_ra8_npu_off_status);
366 if ((raw & (uint32_t)k_ra8_npu_status_fault_mask) != 0U) {
367 ra8_log_error(s_tag, "npu_poll: fault latched");
368 return k_ra8_err_hw_error;
369 }
370 *out_done = (raw & ((uint32_t)1U << k_ra8_npu_status_cmd_end_bit)) != 0U;
371 return k_ra8_ok;
372}
373
375{
376 RA8_VALIDATE_INIT(s_npu_initialized, s_tag, "npu_wait: not initialized");
377 for (uint32_t i = 0U; i < k_ra8_npu_job_poll_iters; i++) {
378 bool done = false;
379 const ra8_err_t err = ra8_npu_poll(&done);
380 RA8_RETURN_ON_ERROR(err, s_tag, "npu_wait: poll");
381 if (done) {
382 return k_ra8_ok;
383 }
384 }
386}
387
389{
390 RA8_VALIDATE_INIT(s_npu_initialized, s_tag, "npu_clear_irq: not initialized");
391 /* Ethos-U55 NPU TRM "NPU_CMD" reg @ 0x08 -- write 1 to clear_irq. */
393 return k_ra8_ok;
394}
395
397{
398 RA8_VALIDATE_INIT(s_npu_initialized, s_tag, "npu_irq_arm: not initialized");
399 if (!s_npu_job_submitted) {
400 ra8_log_error(s_tag, "npu_irq_arm: no job submitted");
402 }
403 s_npu_irq_state = k_ra8_npu_irq_armed;
404 return k_ra8_ok;
405}
406
408void ra8_npu_irq_handler(void* ctx)
409{
410 (void)ctx;
411 /* Delegate register access to the already-cited status/clear accessors so the
412 * ISR itself adds no new MMIO citation and stays a two-op hot path. */
413 ra8_npu_status_t st = {};
414 if (ra8_npu_read_status(&st) == k_ra8_ok) {
415 if (st.fault) {
416 s_npu_irq_state = k_ra8_npu_irq_fault;
417 } else if (st.cmd_end) {
418 s_npu_irq_state = k_ra8_npu_irq_done;
419 } else {
420 /* Spurious / early IRQ with neither terminal bit set: leave the latch
421 * armed and re-wait; the clear below still de-asserts the line. */
422 }
423 }
424 (void)ra8_npu_clear_irq();
425}
426
428{
429 RA8_VALIDATE_INIT(s_npu_initialized, s_tag, "npu_wait_irq: not initialized");
430 if (s_npu_irq_state == k_ra8_npu_irq_idle) {
431 ra8_log_error(s_tag, "npu_wait_irq: not armed");
433 }
434 for (uint32_t i = 0U; i < k_ra8_npu_job_poll_iters; i++) {
435 const ra8_npu_irq_state_t state = s_npu_irq_state;
436 if (state == k_ra8_npu_irq_done) {
437 return k_ra8_ok;
438 }
439 if (state == k_ra8_npu_irq_fault) {
440 ra8_log_error(s_tag, "npu_wait_irq: fault latched");
441 return k_ra8_err_hw_error;
442 }
443 internal_npu_wait_for_irq();
444 }
446}
447
448#else
449/* RA8D2 (no NPU): this translation unit is intentionally empty. */
451#endif /* RA8_HAS_NPU */
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_ISR_SAFE
The function is callable from interrupt context.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#define RA8_VALIDATE_INIT(initialized, tag, message)
Precondition: module must be initialized.
Definition ra8_check.h:334
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Compile-time device selection for the RA8 multi-chip build (RA8D2 / RA8P1).
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_err_hw_timeout
Hardware timed out waiting for a flag or handshake.
Definition ra8_err.h:304
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_hw_error
Generic hardware fault detected (error flag set, fault interrupt).
Definition ra8_err.h:310
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
Ref-counted Module Stop Control wrapper for the RA8D2.
ra8_err_t ra8_mstp_enable(ra8_mstp_t id)
Reference-counted "ungate this peripheral" request.
Definition ra8_mstp.c:343
ra8_err_t ra8_mstp_disable(ra8_mstp_t id)
Reference-counted "gate this peripheral" request.
Definition ra8_mstp.c:382
ra8_mstp_t
Packed (reg << 8) | bit module-stop identifier.
@ k_ra8_mstp_reg_a
RA8 mstp register a.
int ra8_npu_not_on_this_device_t
Definition ra8_npu.c:450
Arm Ethos-U55 NPU command/queue driver foundation (RA8P1-only).
ra8_err_t ra8_npu_clear_irq(void)
Acknowledge (clear) a raised NPU interrupt.
ra8_err_t ra8_npu_read_status(ra8_npu_status_t *out)
Read and decode the NPU_STATUS register.
ra8_err_t ra8_npu_poll(bool *out_done)
Non-blocking completion / fault poll of a running job.
ra8_err_t ra8_npu_submit(const ra8_npu_job_t *job)
Program the command queue and tensor region base pointers for a job.
ra8_err_t ra8_npu_wait_irq(void)
Block on the NPU interrupt until the armed job completes or faults.
ra8_err_t ra8_npu_irq_arm(void)
Arm the interrupt-driven completion latch for the submitted job.
void ra8_npu_irq_handler(void *ctx)
NPU interrupt service routine: latch completion / fault, ack the IRQ.
ra8_err_t ra8_npu_run(void)
Kick the currently-submitted job (transition the NPU to running).
ra8_err_t ra8_npu_reset(void)
Soft-reset an already-initialized NPU.
ra8_err_t ra8_npu_deinit(void)
Gate the NPU back into module-stop.
ra8_err_t ra8_npu_read_id(uint32_t *out_id)
Read the Ethos-U55 NPU_ID (architecture / product revision) register.
ra8_err_t ra8_npu_init(void)
Bring the NPU out of module-stop and soft-reset it.
ra8_err_t ra8_npu_wait(void)
Bounded busy-wait until the running job completes or faults.
Arm Ethos-U55 NPU register window on the Renesas RA8P1 (RA8P1-only).
static volatile uint32_t * ra8_npu_reg(uint32_t byte_off)
Compute a volatile pointer to an NPU register by byte offset.
ra8_npu_region_idx_t
Base-pointer region indices (Ethos-U55 has eight AXI region bases).
@ k_ra8_npu_region_count
Number of BASEPn region base-pointer pairs.
@ k_ra8_npu_status_cmd_parse_bit
Command-stream parse error.
@ k_ra8_npu_status_ecc_fault_bit
Internal SRAM ECC fault.
@ k_ra8_npu_status_cmd_end_bit
Command stream fully consumed.
@ k_ra8_npu_status_state_bit
1 = running, 0 = stopped.
@ k_ra8_npu_status_irq_raised_bit
IRQ asserted by the NPU.
@ k_ra8_npu_status_bus_error_bit
AXI bus error latched.
@ k_ra8_npu_status_wd_fault_bit
Weight-decoder fault.
@ k_ra8_npu_status_reset_bit
Reset in progress.
@ k_ra8_npu_off_basep0_lo
BASEP0 bits [31:0] (region 0 base).
@ k_ra8_npu_off_qsize
QSIZE (cmd-stream length in bytes).
@ k_ra8_npu_off_id
NPU_ID (Arm Ethos-U arch id/revision).
@ k_ra8_npu_off_qbase_lo
QBASE bits [31:0] (cmd-stream address).
@ k_ra8_npu_off_cmd
NPU_CMD (run / clear-irq / q-enables).
@ k_ra8_npu_off_status
NPU_STATUS (state + fault flags, RO).
@ k_ra8_npu_off_qbase_hi
QBASE bits [63:32].
@ k_ra8_npu_off_reset
NPU_RESET (software reset request).
@ k_ra8_npu_cmd_clear_irq_bit
clear_irq (write 1 to acknowledge IRQ).
@ k_ra8_npu_cmd_run_bit
transition_to_running_state (start job).
@ k_ra8_npu_basep_stride_bytes
Bytes between BASEPn pairs (lo+hi).
@ k_ra8_npu_reg_hi_offset
Low->high word gap in a 64-bit reg.
One Ethos-U55 inference job: a command stream plus its tensor arenas.
Definition ra8_npu.h:87
uint8_t region_count
Number of region_base[] entries in use.
Definition ra8_npu.h:90
uint32_t cmd_stream_bytes
Command stream length in bytes (> 0).
Definition ra8_npu.h:89
uint64_t region_base[k_ra8_npu_region_count]
AXI base of each BASEPn arena.
Definition ra8_npu.h:91
const void * cmd_stream
Vela command stream base in SRAM.
Definition ra8_npu.h:88
Decoded snapshot of the NPU_STATUS register.
Definition ra8_npu.h:106
bool fault
Any bus / parse / weight-decoder / ECC fault bit.
Definition ra8_npu.h:111
uint32_t raw
Verbatim NPU_STATUS register value.
Definition ra8_npu.h:107
bool running
STATUS.state: NPU is executing a command stream.
Definition ra8_npu.h:108
bool irq_raised
STATUS.irq_raised: an interrupt is pending.
Definition ra8_npu.h:109
bool cmd_end
STATUS.cmd_end: command stream fully consumed.
Definition ra8_npu.h:110