aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonny Svärd <jonny.svaerd@arm.com>2021-06-07 16:57:00 +0200
committerJonny Svärd <jonny.svaerd@arm.com>2021-06-08 15:44:29 +0200
commita830f17656ee3a8bcb72483886da562d69245c39 (patch)
treeb5860b6f1381ad965b0adc5ad0908343c0187eb8
parentd1ea036bd870663d737db9bfbb25e2aa04a389e0 (diff)
downloadethos-u-core-driver-a830f17656ee3a8bcb72483886da562d69245c39.tar.gz
Spring clean/refactor of NPU driver
These changes mostly focus on creating a better structure for the driver. Creating a better separation between driver and device(s). A short summary of what this commit contains: - Move driver specific defines from device to driver - Prefix device functions with ethosu_dev - Remove device specific register access' from driver - Remove device specific debug/dump functions - Add function prototypes for weak functions - Remove legacy ARM_NPU_STUB support - Rename ethosu_device.c to ethosu_device_u55.c - Remove redundant irq handler prototype - Remove (deprecated) hardcoded instance ethosu_drv - Simplify versioning API Split driver version and hardware version/information so that driver version can be queried without a driver instance. - Improve and simplify logging Make warning the new default severity level to print and reduce severity levels to: err warning info debug - Add severity prefix to log lines. Error messages print file and line number, debug messages print function by default. - Clarify some log messages - Small optimizations and bugfixes Change-Id: I2dfbfc3a40d7eca133c82f187f422325e1e6d314
-rw-r--r--CMakeLists.txt8
-rw-r--r--include/ethosu_device.h146
-rw-r--r--include/ethosu_driver.h107
-rw-r--r--src/ethosu_common.h90
-rw-r--r--src/ethosu_device.c686
-rw-r--r--src/ethosu_device_u55.c548
-rw-r--r--src/ethosu_driver.c1195
-rw-r--r--src/ethosu_pmu.c44
8 files changed, 1148 insertions, 1676 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b364716..9852ae4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2019-2020 Arm Limited. All rights reserved.
+# Copyright (c) 2019-2021 Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -28,8 +28,8 @@ option(DRIVER_PMU_AUTOINIT "Enable PMU boot auto-initialization" OFF)
set(CMSIS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../cmsis" CACHE PATH "Path to CMSIS.")
-set(LOG_NAMES emerg alert crit err warning notice info debug)
-set(ETHOSU_LOG_SEVERITY "info" CACHE STRING "Driver log severity level ${LOG_NAMES}")
+set(LOG_NAMES err warning info debug)
+set(ETHOSU_LOG_SEVERITY "warning" CACHE STRING "Driver log severity level ${LOG_NAMES}")
set_property(CACHE ETHOSU_LOG_SEVERITY PROPERTY STRINGS ${LOG_NAMES})
#
@@ -53,7 +53,7 @@ include_directories(${CMSIS_PATH}/CMSIS/Core/Include)
# Build driver library
add_library(ethosu_core_driver STATIC)
target_include_directories(ethosu_core_driver PUBLIC include)
-target_sources(ethosu_core_driver PRIVATE src/ethosu_driver.c src/ethosu_device.c src/ethosu_pmu.c)
+target_sources(ethosu_core_driver PRIVATE src/ethosu_driver.c src/ethosu_device_u55.c src/ethosu_pmu.c)
# Set the log level for the target
target_compile_definitions(ethosu_core_driver PRIVATE ETHOSU_LOG_SEVERITY=${LOG_SEVERITY})
diff --git a/include/ethosu_device.h b/include/ethosu_device.h
index 0221ad1..dad88ef 100644
--- a/include/ethosu_device.h
+++ b/include/ethosu_device.h
@@ -34,10 +34,7 @@ extern "C" {
* Defines
******************************************************************************/
-#define ETHOSU_DRIVER_VERSION_MAJOR 0 ///< Driver major version
-#define ETHOSU_DRIVER_VERSION_MINOR 16 ///< Driver minor version
-#define ETHOSU_DRIVER_VERSION_PATCH 0 ///< Driver patch version
-#define ETHOSU_DRIVER_BASEP_INDEXES 8 ///< Number of base pointer indexes
+#define ETHOSU_BASEP_INDEXES 8 ///< Number of base pointer indexes
#ifndef ETHOSU_PMU_NCOUNTERS
#define ETHOSU_PMU_NCOUNTERS 4
@@ -82,13 +79,10 @@ struct ethosu_id
struct ethosu_config
{
- struct
- {
- uint32_t macs_per_cc; ///< MACs per clock cycle
- uint32_t cmd_stream_version; ///< NPU command stream version
- uint32_t shram_size; ///< SHRAM size
- uint32_t custom_dma; ///< Custom DMA enabled
- };
+ uint32_t macs_per_cc; ///< MACs per clock cycle
+ uint32_t cmd_stream_version; ///< NPU command stream version
+ uint32_t shram_size; ///< SHRAM size
+ uint32_t custom_dma; ///< Custom DMA enabled
};
/**
@@ -156,12 +150,12 @@ enum ethosu_error_codes ethosu_dev_init(struct ethosu_device *dev,
/**
* Get device id.
*/
-enum ethosu_error_codes ethosu_get_id(struct ethosu_device *dev, struct ethosu_id *id);
+enum ethosu_error_codes ethosu_dev_get_id(struct ethosu_device *dev, struct ethosu_id *id);
/**
* Get device configuration.
*/
-enum ethosu_error_codes ethosu_get_config(struct ethosu_device *dev, struct ethosu_config *config);
+enum ethosu_error_codes ethosu_dev_get_config(struct ethosu_device *dev, struct ethosu_config *config);
/**
* Execute a given command stream on NPU.
@@ -175,11 +169,11 @@ enum ethosu_error_codes ethosu_get_config(struct ethosu_device *dev, struct etho
* \param[in] num_base_addr Number of base addresses.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_run_command_stream(struct ethosu_device *dev,
- const uint8_t *cmd_stream_ptr,
- uint32_t cms_length,
- const uint64_t *base_addr,
- int num_base_addr);
+enum ethosu_error_codes ethosu_dev_run_command_stream(struct ethosu_device *dev,
+ const uint8_t *cmd_stream_ptr,
+ uint32_t cms_length,
+ const uint64_t *base_addr,
+ int num_base_addr);
/**
* Check if IRQ is raised.
@@ -188,13 +182,13 @@ enum ethosu_error_codes ethosu_run_command_stream(struct ethosu_device *dev,
* - 1 IRQ raised
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_is_irq_raised(struct ethosu_device *dev, uint8_t *irq_status);
+enum ethosu_error_codes ethosu_dev_is_irq_raised(struct ethosu_device *dev, uint8_t *irq_status);
/**
* Clear IRQ status.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_clear_irq_status(struct ethosu_device *dev);
+enum ethosu_error_codes ethosu_dev_clear_irq_status(struct ethosu_device *dev);
/**
* Get the 16 bit status mask.
@@ -210,14 +204,21 @@ enum ethosu_error_codes ethosu_clear_irq_status(struct ethosu_device *dev);
* bit7-15: reserved
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_get_status_mask(struct ethosu_device *dev, uint16_t *status_mask);
+
+enum ethosu_error_codes ethosu_dev_get_status_mask(struct ethosu_device *dev, uint16_t *status_mask);
+
+/**
+ * Get current NPU status
+ * \return 32 bit status value
+ */
+uint32_t ethosu_dev_get_status(struct ethosu_device *dev);
/**
* Get the 16 bit IRQ history mask.
* \param[out] irq_history_mask Pointer to the IRQ history mask.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_get_irq_history_mask(struct ethosu_device *dev, uint16_t *irq_history_mask);
+enum ethosu_error_codes ethosu_dev_get_irq_history_mask(struct ethosu_device *dev, uint16_t *irq_history_mask);
/**
* Clear the given bits in the
@@ -226,19 +227,19 @@ enum ethosu_error_codes ethosu_get_irq_history_mask(struct ethosu_device *dev, u
* clear in the IRQ history mask.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_clear_irq_history_mask(struct ethosu_device *dev, uint16_t irq_history_clear_mask);
+enum ethosu_error_codes ethosu_dev_clear_irq_history_mask(struct ethosu_device *dev, uint16_t irq_history_clear_mask);
/**
* Perform a NPU soft reset.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_soft_reset(struct ethosu_device *dev);
+enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev);
/**
* Wait for reset ready.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_wait_for_reset(struct ethosu_device *dev);
+enum ethosu_error_codes ethosu_dev_wait_for_reset(struct ethosu_device *dev);
/**
* Read and return the content of a given NPU APB
@@ -250,10 +251,10 @@ enum ethosu_error_codes ethosu_wait_for_reset(struct ethosu_device *dev);
* written.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_read_apb_reg(struct ethosu_device *dev,
- uint32_t start_address,
- uint16_t num_reg,
- uint32_t *reg_p);
+enum ethosu_error_codes ethosu_dev_read_apb_reg(struct ethosu_device *dev,
+ uint32_t start_address,
+ uint16_t num_reg,
+ uint32_t *reg_p);
/**
* Set qconfig register. I.e.
@@ -262,7 +263,7 @@ enum ethosu_error_codes ethosu_read_apb_reg(struct ethosu_device *dev,
* enum ethosu_memory_type.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_set_qconfig(struct ethosu_device *dev, enum ethosu_memory_type memory_type);
+enum ethosu_error_codes ethosu_dev_set_qconfig(struct ethosu_device *dev, enum ethosu_memory_type memory_type);
/**
* Set register REGIONCFG.
@@ -272,9 +273,9 @@ enum ethosu_error_codes ethosu_set_qconfig(struct ethosu_device *dev, enum ethos
* \param[in] memory_type Memory_type to use for region: enum ethosu_memory_type.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_set_regioncfg(struct ethosu_device *dev,
- uint8_t region,
- enum ethosu_memory_type memory_type);
+enum ethosu_error_codes ethosu_dev_set_regioncfg(struct ethosu_device *dev,
+ uint8_t region,
+ enum ethosu_memory_type memory_type);
/**
* Set AXI limit parameters for port 0 counter 0.
@@ -284,11 +285,11 @@ enum ethosu_error_codes ethosu_set_regioncfg(struct ethosu_device *dev,
* \param[in] max_writes Maximum number of outstanding writes.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_set_axi_limit0(struct ethosu_device *dev,
- enum ethosu_axi_limit_beats max_beats,
- enum ethosu_axi_limit_mem_type memtype,
- uint8_t max_reads,
- uint8_t max_writes);
+enum ethosu_error_codes ethosu_dev_set_axi_limit0(struct ethosu_device *dev,
+ enum ethosu_axi_limit_beats max_beats,
+ enum ethosu_axi_limit_mem_type memtype,
+ uint8_t max_reads,
+ uint8_t max_writes);
/**
* Set AXI limit parameters for port 0 counter 1.
* \param[in] max_beats Burst split alignment, \ref ethosu_axi_limit_beats.
@@ -297,11 +298,11 @@ enum ethosu_error_codes ethosu_set_axi_limit0(struct ethosu_device *dev,
* \param[in] max_writes Maximum number of outstanding writes.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_set_axi_limit1(struct ethosu_device *dev,
- enum ethosu_axi_limit_beats max_beats,
- enum ethosu_axi_limit_mem_type memtype,
- uint8_t max_reads,
- uint8_t max_writes);
+enum ethosu_error_codes ethosu_dev_set_axi_limit1(struct ethosu_device *dev,
+ enum ethosu_axi_limit_beats max_beats,
+ enum ethosu_axi_limit_mem_type memtype,
+ uint8_t max_reads,
+ uint8_t max_writes);
/**
* Set AXI limit parameters for port 1 counter 2.
* \param[in] max_beats Burst split alignment, \ref ethosu_axi_limit_beats.
@@ -310,11 +311,11 @@ enum ethosu_error_codes ethosu_set_axi_limit1(struct ethosu_device *dev,
* \param[in] max_writes Maximum number of outstanding writes.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_set_axi_limit2(struct ethosu_device *dev,
- enum ethosu_axi_limit_beats max_beats,
- enum ethosu_axi_limit_mem_type memtype,
- uint8_t max_reads,
- uint8_t max_writes);
+enum ethosu_error_codes ethosu_dev_set_axi_limit2(struct ethosu_device *dev,
+ enum ethosu_axi_limit_beats max_beats,
+ enum ethosu_axi_limit_mem_type memtype,
+ uint8_t max_reads,
+ uint8_t max_writes);
/**
* Set AXI limit parameters for port 1 counter 3.
* \param[in] max_beats Burst split alignment, \ref ethosu_axi_limit_beats.
@@ -323,25 +324,24 @@ enum ethosu_error_codes ethosu_set_axi_limit2(struct ethosu_device *dev,
* \param[in] max_writes Maximum number of outstanding writes.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_set_axi_limit3(struct ethosu_device *dev,
- enum ethosu_axi_limit_beats max_beats,
- enum ethosu_axi_limit_mem_type memtype,
- uint8_t max_reads,
- uint8_t max_writes);
+enum ethosu_error_codes ethosu_dev_set_axi_limit3(struct ethosu_device *dev,
+ enum ethosu_axi_limit_beats max_beats,
+ enum ethosu_axi_limit_mem_type memtype,
+ uint8_t max_reads,
+ uint8_t max_writes);
/**
* Get current command stream queue read position.
- * \param[out] qread Pointer to queue read.
- * \return \ref ethosu_error_codes
+ * \return qread position
*/
-enum ethosu_error_codes ethosu_get_qread(struct ethosu_device *dev, uint32_t *qread);
+uint32_t ethosu_dev_get_qread(struct ethosu_device *dev);
/**
* Get revision of NPU
* \param[out] revision Pointer to revision read.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_get_revision(struct ethosu_device *dev, uint32_t *revision);
+enum ethosu_error_codes ethosu_dev_get_revision(struct ethosu_device *dev, uint32_t *revision);
/**
* Issue run command for the currently programmed
@@ -349,7 +349,7 @@ enum ethosu_error_codes ethosu_get_revision(struct ethosu_device *dev, uint32_t
* position.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_set_command_run(struct ethosu_device *dev);
+enum ethosu_error_codes ethosu_dev_set_command_run(struct ethosu_device *dev);
/**
* Dump a 1KB section of SHRAM.
@@ -359,7 +359,7 @@ enum ethosu_error_codes ethosu_set_command_run(struct ethosu_device *dev);
* written.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_get_shram_data(struct ethosu_device *dev, int section, uint32_t *shram_p);
+enum ethosu_error_codes ethosu_dev_get_shram_data(struct ethosu_device *dev, int section, uint32_t *shram_p);
/**
* Set clock and power q request enable bits.
@@ -367,30 +367,30 @@ enum ethosu_error_codes ethosu_get_shram_data(struct ethosu_device *dev, int sec
* \param[in] power_q Power q ENABLE/DISABLE \ref power_q_request.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_set_clock_and_power(struct ethosu_device *dev,
- enum ethosu_clock_q_request clock_q,
- enum ethosu_power_q_request power_q);
+enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev,
+ enum ethosu_clock_q_request clock_q,
+ enum ethosu_power_q_request power_q);
/**
* Read register.
* \param[in] address Address to read.
* \return Register value.
*/
-uint32_t ethosu_read_reg(struct ethosu_device *dev, uint32_t address);
+uint32_t ethosu_dev_read_reg(struct ethosu_device *dev, uint32_t address);
/**
* Write register.
* \param[in] address Address to read.
* \param[in] value Value to be written.
*/
-void ethosu_write_reg(struct ethosu_device *dev, uint32_t address, uint32_t value);
+void ethosu_dev_write_reg(struct ethosu_device *dev, uint32_t address, uint32_t value);
/**
* Write register with shadow variable.
* \param[in] address Address to read.
* \param[in] value Value to be written.
*/
-void ethosu_write_reg_shadow(struct ethosu_device *dev, uint32_t address, uint32_t value, uint32_t *shadow);
+void ethosu_dev_write_reg_shadow(struct ethosu_device *dev, uint32_t address, uint32_t value, uint32_t *shadow);
/**
* Save the PMU configuration to ethosu_device struct.
@@ -398,7 +398,7 @@ void ethosu_write_reg_shadow(struct ethosu_device *dev, uint32_t address, uint32
* saved.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_save_pmu_config(struct ethosu_device *dev);
+enum ethosu_error_codes ethosu_dev_save_pmu_config(struct ethosu_device *dev);
/**
* Restore the PMU configuration from a ethosu_device struct.
@@ -406,7 +406,7 @@ enum ethosu_error_codes ethosu_save_pmu_config(struct ethosu_device *dev);
* stored.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_restore_pmu_config(struct ethosu_device *dev);
+enum ethosu_error_codes ethosu_dev_restore_pmu_config(struct ethosu_device *dev);
/**
* Save PMU counters to shadow variables in memory.
@@ -414,7 +414,15 @@ enum ethosu_error_codes ethosu_restore_pmu_config(struct ethosu_device *dev);
* stored.
* \return \ref ethosu_error_codes
*/
-enum ethosu_error_codes ethosu_save_pmu_counters(struct ethosu_device *dev);
+enum ethosu_error_codes ethosu_dev_save_pmu_counters(struct ethosu_device *dev);
+
+/**
+ * Check if the PROT register value has changed compared to cached value.
+ * \param[in] dev Ethos-U device to check.
+ * \return true if register value differs from cached value,
+ * false otherwise.
+ */
+bool ethosu_dev_prot_has_changed(struct ethosu_device *dev);
/**
* Check if the STATUS register has any error bits set or not.
@@ -422,7 +430,7 @@ enum ethosu_error_codes ethosu_save_pmu_counters(struct ethosu_device *dev);
* \return true if any error bits set,
* false otherwise.
*/
-bool ethosu_status_has_error(struct ethosu_device *dev);
+bool ethosu_dev_status_has_error(struct ethosu_device *dev);
#ifdef __cplusplus
}
diff --git a/include/ethosu_driver.h b/include/ethosu_driver.h
index e492f91..30d707f 100644
--- a/include/ethosu_driver.h
+++ b/include/ethosu_driver.h
@@ -34,54 +34,44 @@ extern "C" {
#endif
/******************************************************************************
+ * Defines
+ ******************************************************************************/
+
+#define ETHOSU_DRIVER_VERSION_MAJOR 0 ///< Driver major version
+#define ETHOSU_DRIVER_VERSION_MINOR 16 ///< Driver minor version
+#define ETHOSU_DRIVER_VERSION_PATCH 0 ///< Driver patch version
+
+/******************************************************************************
* Types
******************************************************************************/
struct ethosu_driver
{
struct ethosu_device dev;
- bool abort_inference;
+ struct ethosu_driver *next;
+ void *semaphore;
uint64_t fast_memory;
size_t fast_memory_size;
bool status_error;
+ bool abort_inference;
bool dev_power_always_on;
- struct ethosu_driver *next;
bool reserved;
volatile bool irq_triggered;
- void *semaphore;
uint8_t clock_request;
uint8_t power_request;
};
-struct ethosu_version_id
+struct ethosu_driver_version
{
- // Ethos-U id
- uint8_t version_status;
- uint8_t version_minor;
- uint8_t version_major;
- uint8_t product_major;
- uint8_t arch_patch_rev;
- uint8_t arch_minor_rev;
- uint8_t arch_major_rev;
-
- // Driver Version
- uint8_t driver_patch_rev;
- uint8_t driver_minor_rev;
- uint8_t driver_major_rev;
+ uint8_t major;
+ uint8_t minor;
+ uint8_t patch;
};
-struct ethosu_version_config
+struct ethosu_hw_info
{
- uint8_t macs_per_cc;
- uint8_t cmd_stream_version;
- uint8_t shram_size;
- uint8_t custom_dma;
-};
-
-struct ethosu_version
-{
- struct ethosu_version_id id;
- struct ethosu_version_config cfg;
+ struct ethosu_id version;
+ struct ethosu_config cfg;
};
enum ethosu_request_clients
@@ -91,10 +81,43 @@ enum ethosu_request_clients
};
/******************************************************************************
- * Variables
+ * Prototypes (weak functions in driver)
******************************************************************************/
-extern struct ethosu_driver ethosu_drv;
+/**
+ * Interrupt handler to be called on IRQ from Ethos-U
+ */
+void ethosu_irq_handler(struct ethosu_driver *drv);
+
+/*
+ * Flush/clean the data cache by address and size. Passing NULL as p argument
+ * expects the whole cache to be flushed.
+ */
+
+void ethosu_flush_dcache(uint32_t *p, size_t bytes);
+/*
+ * Invalidate the data cache by address and size. Passing NULL as p argument
+ * expects the whole cache to be invalidated.
+ */
+void ethosu_invalidate_dcache(uint32_t *p, size_t bytes);
+
+/*
+ * Minimal sempahore and mutex implementation for baremetal applications. See
+ * ethosu_driver.c.
+ */
+void *ethosu_mutex_create(void);
+void ethosu_mutex_lock(void *mutex);
+void ethosu_mutex_unlock(void *mutex);
+void *ethosu_semaphore_create(void);
+void ethosu_semaphore_take(void *sem);
+void ethosu_semaphore_give(void *sem);
+
+/*
+ * Callbacks for begin/end of inference. inference_data pointer is set in the
+ * ethosu_invoke() call, referenced as custom_data_ptr.
+ */
+void ethosu_inference_begin(struct ethosu_driver *drv, const void *inference_data);
+void ethosu_inference_end(struct ethosu_driver *drv, const void *inference_data);
/******************************************************************************
* Prototypes
@@ -111,9 +134,14 @@ int ethosu_init(struct ethosu_driver *drv,
uint32_t privilege_enable);
/**
- * Get Ethos-U version.
+ * Get Ethos-U driver version.
+ */
+void ethosu_get_driver_version(struct ethosu_driver_version *ver);
+
+/**
+ * Get Ethos-U hardware information.
*/
-int ethosu_get_version(struct ethosu_driver *drv, struct ethosu_version *version);
+void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw);
/**
* Invoke Vela command stream.
@@ -131,26 +159,11 @@ int ethosu_invoke(struct ethosu_driver *drv,
void ethosu_abort(struct ethosu_driver *drv);
/**
- * Interrupt handler do be called on IRQ from Ethos-U
- */
-void ethosu_irq_handler(struct ethosu_driver *drv);
-
-/**
* Set Ethos-U power mode.
*/
void ethosu_set_power_mode(struct ethosu_driver *drv, bool always_on);
/**
- * Register a driver for multiNPU usage
- */
-int ethosu_register_driver(struct ethosu_driver *drv);
-
-/**
- * Deregister a driver from multiNPU usage
- */
-int ethosu_deregister_driver(struct ethosu_driver *drv);
-
-/**
* Reserves a driver to execute inference with
*/
struct ethosu_driver *ethosu_reserve_driver(void);
diff --git a/src/ethosu_common.h b/src/ethosu_common.h
index bf3aff0..6342df2 100644
--- a/src/ethosu_common.h
+++ b/src/ethosu_common.h
@@ -23,104 +23,52 @@
* Includes
******************************************************************************/
-#include "ethosu55_interface.h"
-
#include <stdio.h>
+#include <string.h>
/******************************************************************************
* Defines
******************************************************************************/
+#define UNUSED(x) ((void)x)
+
+#define MASK_0_31_BITS (0xFFFFFFFF)
+#define MASK_32_47_BITS (0xFFFF00000000)
+
// Log severity levels
-#define ETHOSU_LOG_EMERG 0
-#define ETHOSU_LOG_ALERT 1
-#define ETHOSU_LOG_CRIT 2
-#define ETHOSU_LOG_ERR 3
-#define ETHOSU_LOG_WARN 4
-#define ETHOSU_LOG_NOTICE 5
-#define ETHOSU_LOG_INFO 6
-#define ETHOSU_LOG_DEBUG 7
+#define ETHOSU_LOG_ERR 0
+#define ETHOSU_LOG_WARN 1
+#define ETHOSU_LOG_INFO 2
+#define ETHOSU_LOG_DEBUG 3
// Define default log severity
#ifndef ETHOSU_LOG_SEVERITY
#define ETHOSU_LOG_SEVERITY ETHOSU_LOG_WARN
#endif
-#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_EMERG
-#define LOG_EMERG(format, ...) \
- fprintf(stderr, format, ##__VA_ARGS__); \
- fflush(stderr); \
- exit(-1)
-#else
-#define LOG_EMERG(format, ...)
-#endif
-
-#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_ALERT
-#define LOG_ALERT(format, ...) \
- fprintf(stderr, format, ##__VA_ARGS__); \
- fflush(stderr); \
- exit(-1)
-#else
-#define LOG_ALERT(format, ...)
-#endif
-
-#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_CRIT
-#define LOG_CRIT(format, ...) \
- fprintf(stderr, format, ##__VA_ARGS__); \
- fflush(stderr); \
- exit(-1)
-#else
-#define LOG_CRIT(format, ...)
-#endif
-
+// Log formatting
#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_ERR
-#define LOG_ERR(format, ...) \
- fprintf(stderr, format, ##__VA_ARGS__); \
- fflush(stderr)
+#define LOG_ERR(f, ...) fprintf(stderr, "E: " f " (%s:%d)\n", ##__VA_ARGS__, strrchr("/" __FILE__, '/') + 1, __LINE__)
#else
-#define LOG_ERR(format, ...)
+#define LOG_ERR(f, ...)
#endif
#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_WARN
-#define LOG_WARN(format, ...) fprintf(stdout, format, ##__VA_ARGS__)
+#define LOG_WARN(f, ...) fprintf(stdout, "W: " f "\n", ##__VA_ARGS__)
#else
-#define LOG_WARN(format, ...)
-#endif
-
-#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_NOTICE
-#define LOG_NOTICE(format, ...) fprintf(stdout, format, ##__VA_ARGS__)
-#else
-#define LOG_NOTICE(format, ...)
+#define LOG_WARN(f, ...)
#endif
#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_INFO
-#define LOG_INFO(format, ...) fprintf(stdout, format, ##__VA_ARGS__)
+#define LOG_INFO(f, ...) fprintf(stdout, "I: " f "\n", ##__VA_ARGS__)
#else
-#define LOG_INFO(format, ...)
+#define LOG_INFO(f, ...)
#endif
#if ETHOSU_LOG_SEVERITY >= ETHOSU_LOG_DEBUG
-#define LOG_DEBUG(format, ...) fprintf(stdout, format, ##__VA_ARGS__)
+#define LOG_DEBUG(f, ...) fprintf(stdout, "D: %s(): " f "\n", __FUNCTION__, ##__VA_ARGS__)
#else
-#define LOG_DEBUG(format, ...)
+#define LOG_DEBUG(f, ...)
#endif
-#define UNUSED(x) ((void)x)
-
-#define VER_STR(X) VNUM_STR(X)
-#define VNUM_STR(X) #X
-
-#define MASK_0_31_BITS (0xFFFFFFFF)
-#define MASK_32_47_BITS (0xFFFF00000000)
-
-/******************************************************************************
- * Inline functions
- ******************************************************************************/
-
-static const __attribute__((section("npu_driver_version"))) char driver_version_str[] = VER_STR(
- ETHOSU_DRIVER_VERSION_MAJOR) "." VER_STR(ETHOSU_DRIVER_VERSION_MINOR) "." VER_STR(ETHOSU_DRIVER_VERSION_PATCH);
-
-static const __attribute__((section("npu_driver_arch_version"))) char driver_arch_version_str[] =
- VER_STR(NNX_ARCH_VERSION_MAJOR) "." VER_STR(NNX_ARCH_VERSION_MINOR) "." VER_STR(NNX_ARCH_VERSION_PATCH);
-
#endif // ETHOSU_COMMON_H
diff --git a/src/ethosu_device.c b/src/ethosu_device.c
deleted file mode 100644
index e8d067f..0000000
--- a/src/ethosu_device.c
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the License); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "ethosu_device.h"
-#include "ethosu_common.h"
-#include "ethosu_config.h"
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdio.h>
-
-#define BASEP_OFFSET 4
-#define REG_OFFSET 4
-#define BYTES_1KB 1024
-
-#define ADDRESS_BITS 48
-#define ADDRESS_MASK ((1ull << ADDRESS_BITS) - 1)
-
-#if defined(ARM_NPU_STUB)
-static uint32_t stream_length = 0;
-#endif
-
-enum ethosu_error_codes ethosu_dev_init(struct ethosu_device *dev,
- const void *base_address,
- uint32_t secure_enable,
- uint32_t privilege_enable)
-{
-#if !defined(ARM_NPU_STUB)
- dev->base_address = (volatile uintptr_t)base_address;
- dev->secure = secure_enable;
- dev->privileged = privilege_enable;
-
- ethosu_save_pmu_config(dev);
-#else
- UNUSED(dev);
- UNUSED(base_address);
-#endif
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_get_id(struct ethosu_device *dev, struct ethosu_id *id)
-{
- struct id_r _id;
-
-#if !defined(ARM_NPU_STUB)
- _id.word = ethosu_read_reg(dev, NPU_REG_ID);
-#else
- UNUSED(dev);
-
- _id.word = 0;
- _id.arch_patch_rev = NNX_ARCH_VERSION_PATCH;
- _id.arch_minor_rev = NNX_ARCH_VERSION_MINOR;
- _id.arch_major_rev = NNX_ARCH_VERSION_MAJOR;
-#endif
-
- id->version_status = _id.version_status;
- id->version_minor = _id.version_minor;
- id->version_major = _id.version_major;
- id->product_major = _id.product_major;
- id->arch_patch_rev = _id.arch_patch_rev;
- id->arch_minor_rev = _id.arch_minor_rev;
- id->arch_major_rev = _id.arch_major_rev;
-
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_get_config(struct ethosu_device *dev, struct ethosu_config *config)
-{
- struct config_r cfg = {.word = 0};
-
-#if !defined(ARM_NPU_STUB)
- cfg.word = ethosu_read_reg(dev, NPU_REG_CONFIG);
-#else
- UNUSED(dev);
-#endif
-
- config->macs_per_cc = cfg.macs_per_cc;
- config->cmd_stream_version = cfg.cmd_stream_version;
- config->shram_size = cfg.shram_size;
- config->custom_dma = cfg.custom_dma;
-
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_run_command_stream(struct ethosu_device *dev,
- const uint8_t *cmd_stream_ptr,
- uint32_t cms_length,
- const uint64_t *base_addr,
- int num_base_addr)
-{
- enum ethosu_error_codes ret_code = ETHOSU_SUCCESS;
-
-#if !defined(ARM_NPU_STUB)
- assert(num_base_addr <= ETHOSU_DRIVER_BASEP_INDEXES);
-
- uint64_t qbase = (uintptr_t)cmd_stream_ptr + BASE_POINTER_OFFSET;
- assert(qbase <= ADDRESS_MASK);
- LOG_DEBUG("QBASE=0x%016llx, QSIZE=%u, base_pointer_offset=0x%08x\n", qbase, cms_length, BASE_POINTER_OFFSET);
- ethosu_write_reg(dev, NPU_REG_QBASE0, qbase & 0xffffffff);
- ethosu_write_reg(dev, NPU_REG_QBASE1, qbase >> 32);
- ethosu_write_reg(dev, NPU_REG_QSIZE, cms_length);
-
- for (int i = 0; i < num_base_addr; i++)
- {
- uint64_t addr = base_addr[i] + BASE_POINTER_OFFSET;
- assert(addr <= ADDRESS_MASK);
- LOG_DEBUG("BASEP%d=0x%016llx\n", i, addr);
- ethosu_write_reg(dev, NPU_REG_BASEP0 + (2 * i) * BASEP_OFFSET, addr & 0xffffffff);
- ethosu_write_reg(dev, NPU_REG_BASEP0 + (2 * i + 1) * BASEP_OFFSET, addr >> 32);
- }
-
- ret_code = ethosu_set_command_run(dev);
-#else
- // NPU stubbed
- UNUSED(dev);
- stream_length = cms_length;
- UNUSED(cmd_stream_ptr);
- UNUSED(base_addr);
- assert(num_base_addr < ETHOSU_DRIVER_BASEP_INDEXES);
-#if defined(NDEBUG)
- UNUSED(num_base_addr);
-#endif
-#endif
-
- return ret_code;
-}
-
-enum ethosu_error_codes ethosu_is_irq_raised(struct ethosu_device *dev, uint8_t *irq_raised)
-{
-#if !defined(ARM_NPU_STUB)
- struct status_r status;
- status.word = ethosu_read_reg(dev, NPU_REG_STATUS);
- if (status.irq_raised == 1)
- {
- *irq_raised = 1;
- }
- else
- {
- *irq_raised = 0;
- }
-#else
- UNUSED(dev);
- *irq_raised = 1;
-#endif
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_clear_irq_status(struct ethosu_device *dev)
-{
-#if !defined(ARM_NPU_STUB)
- struct cmd_r oldcmd;
- oldcmd.word = ethosu_read_reg(dev, NPU_REG_CMD);
- struct cmd_r cmd;
-
- cmd.word = 0;
- cmd.clear_irq = 1;
- cmd.clock_q_enable = oldcmd.clock_q_enable;
- cmd.power_q_enable = oldcmd.power_q_enable;
- ethosu_write_reg(dev, NPU_REG_CMD, cmd.word);
- LOG_DEBUG("CMD=0x%08x\n", cmd.word);
-#else
- UNUSED(dev);
-#endif
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_soft_reset(struct ethosu_device *dev)
-{
- enum ethosu_error_codes return_code = ETHOSU_SUCCESS;
-#if !defined(ARM_NPU_STUB)
- struct reset_r reset;
- struct prot_r prot;
-
- reset.word = 0;
- reset.pending_CPL = dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER;
- reset.pending_CSL = dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE;
-
- // Reset and set security level
- LOG_INFO("Soft reset NPU\n");
- ethosu_write_reg(dev, NPU_REG_RESET, reset.word);
-
- // Wait for reset to complete
- return_code = ethosu_wait_for_reset(dev);
- if (return_code != ETHOSU_SUCCESS)
- {
- LOG_ERR("Soft reset timed out\n");
- return return_code;
- }
-
- // Verify that NPU has switched security state and privilege level
- prot.word = ethosu_read_reg(dev, NPU_REG_PROT);
- if (prot.active_CPL != reset.pending_CPL || prot.active_CSL != reset.pending_CSL)
- {
- LOG_ERR("Failed to switch security state and privilege level\n");
- // Register access not permitted
- return ETHOSU_GENERIC_FAILURE;
- }
-
- // Save the prot register
- dev->proto = ethosu_read_reg(dev, NPU_REG_PROT);
-
- // Soft reset will clear the PMU configuration and counters. The shadow PMU counters
- // are cleared by saving the PMU counters to ram, which will read back zeros.
- // The PMU configuration will be restored in the invoke function after power save
- // has been disabled.
- ethosu_save_pmu_counters(dev);
-#else
- UNUSED(dev);
-#endif
-
- return return_code;
-}
-
-enum ethosu_error_codes ethosu_wait_for_reset(struct ethosu_device *dev)
-{
-#if !defined(ARM_NPU_STUB)
- struct status_r status;
-
- // Wait until reset status indicates that reset has been completed
- for (int i = 0; i < 100000; i++)
- {
- status.word = ethosu_read_reg(dev, NPU_REG_STATUS);
- if (0 == status.reset_status)
- {
- break;
- }
- }
-
- if (1 == status.reset_status)
- {
- return ETHOSU_GENERIC_FAILURE;
- }
-#else
- UNUSED(dev);
-#endif
-
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_read_apb_reg(struct ethosu_device *dev,
- uint32_t start_address,
- uint16_t num_reg,
- uint32_t *reg)
-{
-#if !defined(ARM_NPU_STUB)
- uint32_t address = start_address;
-
- assert((start_address + num_reg) < ID_REGISTERS_SIZE);
-
- for (int i = 0; i < num_reg; i++)
- {
- reg[i] = ethosu_read_reg(dev, address);
- address += REG_OFFSET;
- }
-#else
- // NPU stubbed
- UNUSED(dev);
- UNUSED(start_address);
- UNUSED(num_reg);
- UNUSED(reg);
-#endif
-
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_set_qconfig(struct ethosu_device *dev, enum ethosu_memory_type memory_type)
-{
- if (memory_type > ETHOSU_AXI1_OUTSTANDING_COUNTER3)
- {
- return ETHOSU_INVALID_PARAM;
- }
-#if !defined(ARM_NPU_STUB)
- ethosu_write_reg(dev, NPU_REG_QCONFIG, memory_type);
- LOG_DEBUG("QCONFIG=0x%08x\n", memory_type);
-#else
- // NPU stubbed
- UNUSED(dev);
- UNUSED(memory_type);
-#endif
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_set_regioncfg(struct ethosu_device *dev,
- uint8_t region,
- enum ethosu_memory_type memory_type)
-{
- if (region > 7)
- {
- return ETHOSU_INVALID_PARAM;
- }
-#if !defined(ARM_NPU_STUB)
- struct regioncfg_r regioncfg;
- regioncfg.word = ethosu_read_reg(dev, NPU_REG_REGIONCFG);
- regioncfg.word &= ~(0x3 << (2 * region));
- regioncfg.word |= (memory_type & 0x3) << (2 * region);
- ethosu_write_reg(dev, NPU_REG_REGIONCFG, regioncfg.word);
- LOG_DEBUG("REGIONCFG%u=0x%08x\n", region, regioncfg.word);
-#else
- // NPU stubbed
- UNUSED(dev);
- UNUSED(region);
- UNUSED(memory_type);
-#endif
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_set_axi_limit0(struct ethosu_device *dev,
- enum ethosu_axi_limit_beats max_beats,
- enum ethosu_axi_limit_mem_type memtype,
- uint8_t max_reads,
- uint8_t max_writes)
-{
-#if !defined(ARM_NPU_STUB)
- struct axi_limit0_r axi_limit0;
- axi_limit0.word = 0;
- axi_limit0.max_beats = max_beats;
- axi_limit0.memtype = memtype;
- axi_limit0.max_outstanding_read_m1 = max_reads - 1;
- axi_limit0.max_outstanding_write_m1 = max_writes - 1;
-
- ethosu_write_reg(dev, NPU_REG_AXI_LIMIT0, axi_limit0.word);
- LOG_DEBUG("AXI_LIMIT0=0x%08x\n", axi_limit0.word);
-#else
- // NPU stubbed
- UNUSED(dev);
- UNUSED(max_beats);
- UNUSED(memtype);
- UNUSED(max_reads);
- UNUSED(max_writes);
-#endif
-
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_set_axi_limit1(struct ethosu_device *dev,
- enum ethosu_axi_limit_beats max_beats,
- enum ethosu_axi_limit_mem_type memtype,
- uint8_t max_reads,
- uint8_t max_writes)
-{
-#if !defined(ARM_NPU_STUB)
- struct axi_limit1_r axi_limit1;
- axi_limit1.word = 0;
- axi_limit1.max_beats = max_beats;
- axi_limit1.memtype = memtype;
- axi_limit1.max_outstanding_read_m1 = max_reads - 1;
- axi_limit1.max_outstanding_write_m1 = max_writes - 1;
-
- ethosu_write_reg(dev, NPU_REG_AXI_LIMIT1, axi_limit1.word);
- LOG_DEBUG("AXI_LIMIT1=0x%08x\n", axi_limit1.word);
-#else
- // NPU stubbed
- UNUSED(dev);
- UNUSED(max_beats);
- UNUSED(memtype);
- UNUSED(max_reads);
- UNUSED(max_writes);
-#endif
-
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_set_axi_limit2(struct ethosu_device *dev,
- enum ethosu_axi_limit_beats max_beats,
- enum ethosu_axi_limit_mem_type memtype,
- uint8_t max_reads,
- uint8_t max_writes)
-{
-#if !defined(ARM_NPU_STUB)
- struct axi_limit2_r axi_limit2;
- axi_limit2.word = 0;
- axi_limit2.max_beats = max_beats;
- axi_limit2.memtype = memtype;
- axi_limit2.max_outstanding_read_m1 = max_reads - 1;
- axi_limit2.max_outstanding_write_m1 = max_writes - 1;
-
- ethosu_write_reg(dev, NPU_REG_AXI_LIMIT2, axi_limit2.word);
- LOG_DEBUG("AXI_LIMIT2=0x%08x\n", axi_limit2.word);
-#else
- // NPU stubbed
- UNUSED(dev);
- UNUSED(max_beats);
- UNUSED(memtype);
- UNUSED(max_reads);
- UNUSED(max_writes);
-#endif
-
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_set_axi_limit3(struct ethosu_device *dev,
- enum ethosu_axi_limit_beats max_beats,
- enum ethosu_axi_limit_mem_type memtype,
- uint8_t max_reads,
- uint8_t max_writes)
-{
-#if !defined(ARM_NPU_STUB)
- struct axi_limit3_r axi_limit3;
- axi_limit3.word = 0;
- axi_limit3.max_beats = max_beats;
- axi_limit3.memtype = memtype;
- axi_limit3.max_outstanding_read_m1 = max_reads - 1;
- axi_limit3.max_outstanding_write_m1 = max_writes - 1;
-
- ethosu_write_reg(dev, NPU_REG_AXI_LIMIT3, axi_limit3.word);
- LOG_DEBUG("AXI_LIMIT3=0x%08x\n", axi_limit3.word);
-#else
- // NPU stubbed
- UNUSED(dev);
- UNUSED(max_beats);
- UNUSED(memtype);
- UNUSED(max_reads);
- UNUSED(max_writes);
-#endif
-
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_get_revision(struct ethosu_device *dev, uint32_t *revision)
-{
-#if !defined(ARM_NPU_STUB)
- *revision = ethosu_read_reg(dev, NPU_REG_REVISION);
-#else
- UNUSED(dev);
- *revision = 0xDEADC0DE;
-#endif
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_get_qread(struct ethosu_device *dev, uint32_t *qread)
-{
-#if !defined(ARM_NPU_STUB)
- *qread = ethosu_read_reg(dev, NPU_REG_QREAD);
-#else
- UNUSED(dev);
- *qread = stream_length;
-#endif
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_get_status_mask(struct ethosu_device *dev, uint16_t *status_mask)
-{
-#if !defined(ARM_NPU_STUB)
- struct status_r status;
-
- status.word = ethosu_read_reg(dev, NPU_REG_STATUS);
- *status_mask = status.word & 0xFFFF;
-#else
- UNUSED(dev);
- *status_mask = 0x0000;
-#endif
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_get_irq_history_mask(struct ethosu_device *dev, uint16_t *irq_history_mask)
-{
-#if !defined(ARM_NPU_STUB)
- struct status_r status;
-
- status.word = ethosu_read_reg(dev, NPU_REG_STATUS);
- *irq_history_mask = status.irq_history_mask;
-#else
- UNUSED(dev);
- *irq_history_mask = 0xffff;
-#endif
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_clear_irq_history_mask(struct ethosu_device *dev, uint16_t irq_history_clear_mask)
-{
-#if !defined(ARM_NPU_STUB)
- struct cmd_r oldcmd;
- oldcmd.word = ethosu_read_reg(dev, NPU_REG_CMD);
-
- struct cmd_r cmd;
- cmd.word = 0;
- cmd.clock_q_enable = oldcmd.clock_q_enable;
- cmd.power_q_enable = oldcmd.power_q_enable;
- cmd.clear_irq_history = irq_history_clear_mask;
- ethosu_write_reg(dev, NPU_REG_CMD, cmd.word);
- LOG_DEBUG("CMD=0x%08x\n", cmd.word);
-#else
- UNUSED(dev);
- UNUSED(irq_history_clear_mask);
-#endif
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_set_command_run(struct ethosu_device *dev)
-{
-#if !defined(ARM_NPU_STUB)
- struct cmd_r oldcmd;
- oldcmd.word = ethosu_read_reg(dev, NPU_REG_CMD);
-
- struct cmd_r cmd;
- cmd.word = 0;
- cmd.transition_to_running_state = 1;
- cmd.clock_q_enable = oldcmd.clock_q_enable;
- cmd.power_q_enable = oldcmd.power_q_enable;
- ethosu_write_reg(dev, NPU_REG_CMD, cmd.word);
- LOG_DEBUG("CMD=0x%08x\n", cmd.word);
-#else
- UNUSED(dev);
-#endif
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_get_shram_data(struct ethosu_device *dev, int section, uint32_t *shram_p)
-{
-#if !defined(ARM_NPU_STUB)
- int i = 0;
- uint32_t address = NPU_REG_SHARED_BUFFER0;
- ethosu_write_reg(dev, NPU_REG_DEBUG_ADDRESS, section * BYTES_1KB);
-
- while (address <= NPU_REG_SHARED_BUFFER255)
- {
- shram_p[i] = ethosu_read_reg(dev, address);
- address += REG_OFFSET;
- i++;
- }
-#else
- // NPU stubbed
- UNUSED(dev);
- UNUSED(section);
- UNUSED(shram_p);
-#endif
-
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_set_clock_and_power(struct ethosu_device *dev,
- enum ethosu_clock_q_request clock_q,
- enum ethosu_power_q_request power_q)
-{
-#if !defined(ARM_NPU_STUB)
- struct cmd_r cmd;
- cmd.word = 0;
- cmd.clock_q_enable = clock_q;
- cmd.power_q_enable = power_q;
- ethosu_write_reg(dev, NPU_REG_CMD, cmd.word);
- LOG_DEBUG("CMD=0x%08x\n", cmd.word);
-#else
- UNUSED(dev);
- UNUSED(clock_q);
- UNUSED(power_q);
-#endif
- return ETHOSU_SUCCESS;
-}
-
-uint32_t ethosu_read_reg(struct ethosu_device *dev, uint32_t address)
-{
-#if !defined(ARM_NPU_STUB)
- assert(dev->base_address != 0);
- assert(address % 4 == 0);
-
- volatile uint32_t *reg = (volatile uint32_t *)(dev->base_address + address);
- return *reg;
-#else
- UNUSED(dev);
- UNUSED(address);
-
- return 0;
-#endif
-}
-
-void ethosu_write_reg(struct ethosu_device *dev, uint32_t address, uint32_t value)
-{
-#if !defined(ARM_NPU_STUB)
- assert(dev->base_address != 0);
- assert(address % 4 == 0);
-
- volatile uint32_t *reg = (volatile uint32_t *)(dev->base_address + address);
- *reg = value;
-#else
- UNUSED(dev);
- UNUSED(address);
- UNUSED(value);
-#endif
-}
-
-void ethosu_write_reg_shadow(struct ethosu_device *dev, uint32_t address, uint32_t value, uint32_t *shadow)
-{
- ethosu_write_reg(dev, address, value);
- *shadow = ethosu_read_reg(dev, address);
-}
-
-enum ethosu_error_codes ethosu_save_pmu_config(struct ethosu_device *dev)
-{
-#if !defined(ARM_NPU_STUB)
- // Save the PMU control register
- dev->pmcr = ethosu_read_reg(dev, NPU_REG_PMCR);
-
- // Save IRQ control
- dev->pmint = ethosu_read_reg(dev, NPU_REG_PMINTSET);
-
- // Save the enabled events mask
- dev->pmcnten = ethosu_read_reg(dev, NPU_REG_PMCNTENSET);
-
- // Save start and stop event
- dev->pmccntr_cfg = ethosu_read_reg(dev, NPU_REG_PMCCNTR_CFG);
-
- // Save the event settings and counters
- for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
- {
- dev->pmu_evtypr[i] = ethosu_read_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t));
- }
-#else
- UNUSED(dev);
-#endif
-
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_restore_pmu_config(struct ethosu_device *dev)
-{
-#if !defined(ARM_NPU_STUB)
- // Restore PMU control register
- ethosu_write_reg(dev, NPU_REG_PMCR, dev->pmcr);
-
- // Restore IRQ control
- ethosu_write_reg(dev, NPU_REG_PMINTSET, dev->pmint);
-
- // Restore enabled event mask
- ethosu_write_reg(dev, NPU_REG_PMCNTENSET, dev->pmcnten);
-
- // Restore start and stop event
- ethosu_write_reg(dev, NPU_REG_PMCCNTR_CFG, dev->pmccntr_cfg);
-
- // Save the event settings and counters
- for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
- {
- ethosu_write_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t), dev->pmu_evtypr[i]);
- }
-#else
- UNUSED(dev);
-#endif
-
- return ETHOSU_SUCCESS;
-}
-
-enum ethosu_error_codes ethosu_save_pmu_counters(struct ethosu_device *dev)
-{
-#if !defined(ARM_NPU_STUB)
- // Save the cycle counter
- dev->pmccntr[0] = ethosu_read_reg(dev, NPU_REG_PMCCNTR_LO);
- dev->pmccntr[1] = ethosu_read_reg(dev, NPU_REG_PMCCNTR_HI);
-
- // Save the event settings and counters
- for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
- {
- dev->pmu_evcntr[i] = ethosu_read_reg(dev, NPU_REG_PMEVCNTR0 + i * sizeof(uint32_t));
- }
-#else
- UNUSED(dev);
-#endif
-
- return ETHOSU_SUCCESS;
-}
-
-bool ethosu_status_has_error(struct ethosu_device *dev)
-{
- bool status_error = false;
-#if !defined(ARM_NPU_STUB)
- struct status_r status;
- status.word = ethosu_read_reg(dev, NPU_REG_STATUS);
- status_error = ((1 == status.bus_status) || (1 == status.cmd_parse_error) || (1 == status.wd_fault) ||
- (1 == status.ecc_fault));
-#else
- UNUSED(dev);
-#endif
- return status_error;
-}
diff --git a/src/ethosu_device_u55.c b/src/ethosu_device_u55.c
new file mode 100644
index 0000000..24d0680
--- /dev/null
+++ b/src/ethosu_device_u55.c
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ethosu55_interface.h"
+
+#include "ethosu_common.h"
+#include "ethosu_config.h"
+#include "ethosu_device.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#define BASEP_OFFSET 4
+#define REG_OFFSET 4
+#define BYTES_1KB 1024
+
+#define ADDRESS_BITS 48
+#define ADDRESS_MASK ((1ull << ADDRESS_BITS) - 1)
+
+enum ethosu_error_codes ethosu_dev_init(struct ethosu_device *dev,
+ const void *base_address,
+ uint32_t secure_enable,
+ uint32_t privilege_enable)
+{
+ dev->base_address = (volatile uintptr_t)base_address;
+ dev->secure = secure_enable;
+ dev->privileged = privilege_enable;
+
+ ethosu_dev_save_pmu_config(dev);
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_get_id(struct ethosu_device *dev, struct ethosu_id *id)
+{
+ struct id_r _id;
+
+ _id.word = ethosu_dev_read_reg(dev, NPU_REG_ID);
+
+ id->version_status = _id.version_status;
+ id->version_minor = _id.version_minor;
+ id->version_major = _id.version_major;
+ id->product_major = _id.product_major;
+ id->arch_patch_rev = _id.arch_patch_rev;
+ id->arch_minor_rev = _id.arch_minor_rev;
+ id->arch_major_rev = _id.arch_major_rev;
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_get_config(struct ethosu_device *dev, struct ethosu_config *config)
+{
+ struct config_r cfg = {.word = 0};
+
+ cfg.word = ethosu_dev_read_reg(dev, NPU_REG_CONFIG);
+
+ config->macs_per_cc = cfg.macs_per_cc;
+ config->cmd_stream_version = cfg.cmd_stream_version;
+ config->shram_size = cfg.shram_size;
+ config->custom_dma = cfg.custom_dma;
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_run_command_stream(struct ethosu_device *dev,
+ const uint8_t *cmd_stream_ptr,
+ uint32_t cms_length,
+ const uint64_t *base_addr,
+ int num_base_addr)
+{
+ assert(num_base_addr <= ETHOSU_BASEP_INDEXES);
+
+ uint64_t qbase = (uintptr_t)cmd_stream_ptr + BASE_POINTER_OFFSET;
+ assert(qbase <= ADDRESS_MASK);
+ LOG_DEBUG("QBASE=0x%016llx, QSIZE=%u, base_pointer_offset=0x%08x\n", qbase, cms_length, BASE_POINTER_OFFSET);
+
+ ethosu_dev_write_reg(dev, NPU_REG_QBASE0, qbase & 0xffffffff);
+ ethosu_dev_write_reg(dev, NPU_REG_QBASE1, qbase >> 32);
+ ethosu_dev_write_reg(dev, NPU_REG_QSIZE, cms_length);
+
+ for (int i = 0; i < num_base_addr; i++)
+ {
+ uint64_t addr = base_addr[i] + BASE_POINTER_OFFSET;
+ assert(addr <= ADDRESS_MASK);
+ LOG_DEBUG("BASEP%d=0x%016llx\n", i, addr);
+ ethosu_dev_write_reg(dev, NPU_REG_BASEP0 + (2 * i) * BASEP_OFFSET, addr & 0xffffffff);
+ ethosu_dev_write_reg(dev, NPU_REG_BASEP0 + (2 * i + 1) * BASEP_OFFSET, addr >> 32);
+ }
+
+ return ethosu_dev_set_command_run(dev);
+}
+
+enum ethosu_error_codes ethosu_dev_is_irq_raised(struct ethosu_device *dev, uint8_t *irq_raised)
+{
+ struct status_r status;
+
+ status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
+
+ if (status.irq_raised == 1)
+ {
+ *irq_raised = 1;
+ }
+ else
+ {
+ *irq_raised = 0;
+ }
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_clear_irq_status(struct ethosu_device *dev)
+{
+ struct cmd_r oldcmd;
+ struct cmd_r cmd;
+
+ oldcmd.word = ethosu_dev_read_reg(dev, NPU_REG_CMD);
+
+ cmd.word = 0;
+ cmd.clear_irq = 1;
+ cmd.clock_q_enable = oldcmd.clock_q_enable;
+ cmd.power_q_enable = oldcmd.power_q_enable;
+ ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
+ LOG_DEBUG("CMD=0x%08x\n", cmd.word);
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev)
+{
+ enum ethosu_error_codes return_code = ETHOSU_SUCCESS;
+ struct reset_r reset;
+ struct prot_r prot;
+
+ reset.word = 0;
+ reset.pending_CPL = dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER;
+ reset.pending_CSL = dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE;
+
+ // Reset and set security level
+ LOG_INFO("Soft reset NPU\n");
+ ethosu_dev_write_reg(dev, NPU_REG_RESET, reset.word);
+
+ // Wait for reset to complete
+ return_code = ethosu_dev_wait_for_reset(dev);
+ if (return_code != ETHOSU_SUCCESS)
+ {
+ LOG_ERR("Soft reset timed out\n");
+ return return_code;
+ }
+
+ // Verify that NPU has switched security state and privilege level
+ prot.word = ethosu_dev_read_reg(dev, NPU_REG_PROT);
+ if (prot.active_CPL != reset.pending_CPL || prot.active_CSL != reset.pending_CSL)
+ {
+ LOG_ERR("Failed to switch security state and privilege level\n");
+ // Register access not permitted
+ return ETHOSU_GENERIC_FAILURE;
+ }
+
+ // Save the prot register
+ dev->proto = prot.word;
+
+ // Soft reset will clear the PMU configuration and counters. The shadow PMU counters
+ // are cleared by saving the PMU counters to ram, which will read back zeros.
+ // The PMU configuration will be restored in the invoke function after power save
+ // has been disabled.
+ ethosu_dev_save_pmu_counters(dev);
+
+ return return_code;
+}
+
+enum ethosu_error_codes ethosu_dev_wait_for_reset(struct ethosu_device *dev)
+{
+ struct status_r status;
+
+ // Wait until reset status indicates that reset has been completed
+ for (int i = 0; i < 100000; i++)
+ {
+ status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
+ if (0 == status.reset_status)
+ {
+ break;
+ }
+ }
+
+ if (1 == status.reset_status)
+ {
+ return ETHOSU_GENERIC_FAILURE;
+ }
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_read_apb_reg(struct ethosu_device *dev,
+ uint32_t start_address,
+ uint16_t num_reg,
+ uint32_t *reg)
+{
+ uint32_t address = start_address;
+
+ assert((start_address + num_reg) < ID_REGISTERS_SIZE);
+
+ for (int i = 0; i < num_reg; i++)
+ {
+ reg[i] = ethosu_dev_read_reg(dev, address);
+ address += REG_OFFSET;
+ }
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_set_qconfig(struct ethosu_device *dev, enum ethosu_memory_type memory_type)
+{
+ if (memory_type > ETHOSU_AXI1_OUTSTANDING_COUNTER3)
+ {
+ return ETHOSU_INVALID_PARAM;
+ }
+ ethosu_dev_write_reg(dev, NPU_REG_QCONFIG, memory_type);
+ LOG_DEBUG("QCONFIG=0x%08x\n", memory_type);
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_set_regioncfg(struct ethosu_device *dev,
+ uint8_t region,
+ enum ethosu_memory_type memory_type)
+{
+ struct regioncfg_r regioncfg;
+
+ if (region > 7)
+ {
+ return ETHOSU_INVALID_PARAM;
+ }
+
+ regioncfg.word = ethosu_dev_read_reg(dev, NPU_REG_REGIONCFG);
+ regioncfg.word &= ~(0x3 << (2 * region));
+ regioncfg.word |= (memory_type & 0x3) << (2 * region);
+ ethosu_dev_write_reg(dev, NPU_REG_REGIONCFG, regioncfg.word);
+ LOG_DEBUG("REGIONCFG%u=0x%08x\n", region, regioncfg.word);
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_set_axi_limit0(struct ethosu_device *dev,
+ enum ethosu_axi_limit_beats max_beats,
+ enum ethosu_axi_limit_mem_type memtype,
+ uint8_t max_reads,
+ uint8_t max_writes)
+{
+ struct axi_limit0_r axi_limit0;
+
+ axi_limit0.word = 0;
+ axi_limit0.max_beats = max_beats;
+ axi_limit0.memtype = memtype;
+ axi_limit0.max_outstanding_read_m1 = max_reads - 1;
+ axi_limit0.max_outstanding_write_m1 = max_writes - 1;
+
+ ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT0, axi_limit0.word);
+ LOG_DEBUG("AXI_LIMIT0=0x%08x\n", axi_limit0.word);
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_set_axi_limit1(struct ethosu_device *dev,
+ enum ethosu_axi_limit_beats max_beats,
+ enum ethosu_axi_limit_mem_type memtype,
+ uint8_t max_reads,
+ uint8_t max_writes)
+{
+ struct axi_limit1_r axi_limit1;
+
+ axi_limit1.word = 0;
+ axi_limit1.max_beats = max_beats;
+ axi_limit1.memtype = memtype;
+ axi_limit1.max_outstanding_read_m1 = max_reads - 1;
+ axi_limit1.max_outstanding_write_m1 = max_writes - 1;
+
+ ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT1, axi_limit1.word);
+ LOG_DEBUG("AXI_LIMIT1=0x%08x\n", axi_limit1.word);
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_set_axi_limit2(struct ethosu_device *dev,
+ enum ethosu_axi_limit_beats max_beats,
+ enum ethosu_axi_limit_mem_type memtype,
+ uint8_t max_reads,
+ uint8_t max_writes)
+{
+ struct axi_limit2_r axi_limit2;
+
+ axi_limit2.word = 0;
+ axi_limit2.max_beats = max_beats;
+ axi_limit2.memtype = memtype;
+ axi_limit2.max_outstanding_read_m1 = max_reads - 1;
+ axi_limit2.max_outstanding_write_m1 = max_writes - 1;
+
+ ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT2, axi_limit2.word);
+ LOG_DEBUG("AXI_LIMIT2=0x%08x\n", axi_limit2.word);
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_set_axi_limit3(struct ethosu_device *dev,
+ enum ethosu_axi_limit_beats max_beats,
+ enum ethosu_axi_limit_mem_type memtype,
+ uint8_t max_reads,
+ uint8_t max_writes)
+{
+ struct axi_limit3_r axi_limit3;
+
+ axi_limit3.word = 0;
+ axi_limit3.max_beats = max_beats;
+ axi_limit3.memtype = memtype;
+ axi_limit3.max_outstanding_read_m1 = max_reads - 1;
+ axi_limit3.max_outstanding_write_m1 = max_writes - 1;
+
+ ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT3, axi_limit3.word);
+ LOG_DEBUG("AXI_LIMIT3=0x%08x\n", axi_limit3.word);
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_get_revision(struct ethosu_device *dev, uint32_t *revision)
+{
+ *revision = ethosu_dev_read_reg(dev, NPU_REG_REVISION);
+
+ return ETHOSU_SUCCESS;
+}
+
+uint32_t ethosu_dev_get_qread(struct ethosu_device *dev)
+{
+ return ethosu_dev_read_reg(dev, NPU_REG_QREAD);
+}
+
+uint32_t ethosu_dev_get_status(struct ethosu_device *dev)
+{
+ return ethosu_dev_read_reg(dev, NPU_REG_STATUS);
+}
+
+enum ethosu_error_codes ethosu_dev_get_status_mask(struct ethosu_device *dev, uint16_t *status_mask)
+{
+ struct status_r status;
+
+ status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
+ *status_mask = status.word & 0xFFFF;
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_get_irq_history_mask(struct ethosu_device *dev, uint16_t *irq_history_mask)
+{
+ struct status_r status;
+
+ status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
+ *irq_history_mask = status.irq_history_mask;
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_clear_irq_history_mask(struct ethosu_device *dev, uint16_t irq_history_clear_mask)
+{
+ struct cmd_r oldcmd;
+ struct cmd_r cmd;
+
+ oldcmd.word = ethosu_dev_read_reg(dev, NPU_REG_CMD);
+
+ cmd.word = 0;
+ cmd.clock_q_enable = oldcmd.clock_q_enable;
+ cmd.power_q_enable = oldcmd.power_q_enable;
+ cmd.clear_irq_history = irq_history_clear_mask;
+
+ ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
+ LOG_DEBUG("CMD=0x%08x\n", cmd.word);
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_set_command_run(struct ethosu_device *dev)
+{
+ struct cmd_r oldcmd;
+ struct cmd_r cmd;
+
+ oldcmd.word = ethosu_dev_read_reg(dev, NPU_REG_CMD);
+
+ cmd.word = 0;
+ cmd.transition_to_running_state = 1;
+ cmd.clock_q_enable = oldcmd.clock_q_enable;
+ cmd.power_q_enable = oldcmd.power_q_enable;
+
+ ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
+ LOG_DEBUG("CMD=0x%08x\n", cmd.word);
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_get_shram_data(struct ethosu_device *dev, int section, uint32_t *shram_p)
+{
+ int i = 0;
+ uint32_t address = NPU_REG_SHARED_BUFFER0;
+
+ ethosu_dev_write_reg(dev, NPU_REG_DEBUG_ADDRESS, section * BYTES_1KB);
+
+ while (address <= NPU_REG_SHARED_BUFFER255)
+ {
+ shram_p[i] = ethosu_dev_read_reg(dev, address);
+ address += REG_OFFSET;
+ i++;
+ }
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev,
+ enum ethosu_clock_q_request clock_q,
+ enum ethosu_power_q_request power_q)
+{
+ struct cmd_r cmd;
+
+ cmd.word = 0;
+ cmd.clock_q_enable = clock_q;
+ cmd.power_q_enable = power_q;
+ ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
+ LOG_DEBUG("CMD=0x%08x\n", cmd.word);
+
+ return ETHOSU_SUCCESS;
+}
+
+uint32_t ethosu_dev_read_reg(struct ethosu_device *dev, uint32_t address)
+{
+ assert(dev->base_address != 0);
+ assert(address % 4 == 0);
+
+ volatile uint32_t *reg = (volatile uint32_t *)(dev->base_address + address);
+ return *reg;
+}
+
+void ethosu_dev_write_reg(struct ethosu_device *dev, uint32_t address, uint32_t value)
+{
+ assert(dev->base_address != 0);
+ assert(address % 4 == 0);
+
+ volatile uint32_t *reg = (volatile uint32_t *)(dev->base_address + address);
+ *reg = value;
+}
+
+void ethosu_dev_write_reg_shadow(struct ethosu_device *dev, uint32_t address, uint32_t value, uint32_t *shadow)
+{
+ ethosu_dev_write_reg(dev, address, value);
+ *shadow = ethosu_dev_read_reg(dev, address);
+}
+
+enum ethosu_error_codes ethosu_dev_save_pmu_config(struct ethosu_device *dev)
+{
+ // Save the PMU control register
+ dev->pmcr = ethosu_dev_read_reg(dev, NPU_REG_PMCR);
+
+ // Save IRQ control
+ dev->pmint = ethosu_dev_read_reg(dev, NPU_REG_PMINTSET);
+
+ // Save the enabled events mask
+ dev->pmcnten = ethosu_dev_read_reg(dev, NPU_REG_PMCNTENSET);
+
+ // Save start and stop event
+ dev->pmccntr_cfg = ethosu_dev_read_reg(dev, NPU_REG_PMCCNTR_CFG);
+
+ // Save the event settings and counters
+ for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
+ {
+ dev->pmu_evtypr[i] = ethosu_dev_read_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t));
+ }
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_restore_pmu_config(struct ethosu_device *dev)
+{
+ // Restore PMU control register
+ ethosu_dev_write_reg(dev, NPU_REG_PMCR, dev->pmcr);
+
+ // Restore IRQ control
+ ethosu_dev_write_reg(dev, NPU_REG_PMINTSET, dev->pmint);
+
+ // Restore enabled event mask
+ ethosu_dev_write_reg(dev, NPU_REG_PMCNTENSET, dev->pmcnten);
+
+ // Restore start and stop event
+ ethosu_dev_write_reg(dev, NPU_REG_PMCCNTR_CFG, dev->pmccntr_cfg);
+
+ // Save the event settings and counters
+ for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
+ {
+ ethosu_dev_write_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t), dev->pmu_evtypr[i]);
+ }
+
+ return ETHOSU_SUCCESS;
+}
+
+enum ethosu_error_codes ethosu_dev_save_pmu_counters(struct ethosu_device *dev)
+{
+ // Save the cycle counter
+ dev->pmccntr[0] = ethosu_dev_read_reg(dev, NPU_REG_PMCCNTR_LO);
+ dev->pmccntr[1] = ethosu_dev_read_reg(dev, NPU_REG_PMCCNTR_HI);
+
+ // Save the event settings and counters
+ for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
+ {
+ dev->pmu_evcntr[i] = ethosu_dev_read_reg(dev, NPU_REG_PMEVCNTR0 + i * sizeof(uint32_t));
+ }
+
+ return ETHOSU_SUCCESS;
+}
+
+bool ethosu_dev_prot_has_changed(struct ethosu_device *dev)
+{
+ if (dev->proto != ethosu_dev_read_reg(dev, NPU_REG_PROT))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool ethosu_dev_status_has_error(struct ethosu_device *dev)
+{
+ bool status_error = false;
+ struct status_r status;
+
+ status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
+ status_error = ((1 == status.bus_status) || (1 == status.cmd_parse_error) || (1 == status.wd_fault) ||
+ (1 == status.ecc_fault));
+
+ return status_error;
+}
diff --git a/src/ethosu_driver.c b/src/ethosu_driver.c
index 4c1b100..84488e5 100644
--- a/src/ethosu_driver.c
+++ b/src/ethosu_driver.c
@@ -147,30 +147,51 @@ struct opt_cfg_s
};
/******************************************************************************
- * Functions
+ * Variables
******************************************************************************/
-struct ethosu_driver ethosu_drv = {
- .dev = {.base_address = NULL, .proto = 0, .pmccntr = {0}, .pmu_evcntr = {0, 0, 0, 0}, .pmu_evtypr = {0, 0, 0, 0}},
- .abort_inference = false,
- .status_error = false,
- .dev_power_always_on = false};
-
// Registered drivers linked list HEAD
static struct ethosu_driver *registered_drivers = NULL;
+/******************************************************************************
+ * Weak functions - Cache
+ *
+ * Default NOP operations. Override if available on the targeted device.
+ ******************************************************************************/
+
+/*
+ * Flush/clean the data cache by address and size. Passing NULL as p argument
+ * expects the whole cache to be flushed.
+ */
+void __attribute__((weak)) ethosu_flush_dcache(uint32_t *p, size_t bytes)
+{
+ UNUSED(p);
+ UNUSED(bytes);
+}
+
/*
- * Following section handles the minimal sempahore and mutex implementation in case of baremetal applications.
- * Weak symbols will be overwritten by RTOS definitions and implement true thread-safety. (Done in application layer)
+ * Invalidate the data cache by address and size. Passing NULL as p argument
+ * expects the whole cache to be invalidated.
*/
+void __attribute__((weak)) ethosu_invalidate_dcache(uint32_t *p, size_t bytes)
+{
+ UNUSED(p);
+ UNUSED(bytes);
+}
+
+/******************************************************************************
+ * Weak functions - Semaphore/Mutex for multi NPU
+ *
+ * Following section handles the minimal sempahore and mutex implementation in
+ * case of baremetal applications. Weak symbols will be overridden by RTOS
+ * definitions and implement true thread-safety (in application layer).
+ ******************************************************************************/
-// Baremetal sempahore implementation
struct ethosu_semaphore_t
{
int count;
};
-// Minimal needed declaration to allow baremetal functionality.
static void *ethosu_mutex;
static void *ethosu_semaphore;
@@ -215,351 +236,85 @@ void __attribute__((weak)) ethosu_semaphore_give(void *sem)
s->count++;
__SEV();
}
-// <--- End of semaphore and mutex implementations
-static int ethosu_soft_reset_and_restore(struct ethosu_driver *drv);
-
-void __attribute__((weak)) ethosu_irq_handler(struct ethosu_driver *drv)
-{
- uint8_t irq_raised = 0;
-
- LOG_DEBUG("Interrupt. status=0x%08x, qread=%d\n",
- ethosu_read_reg(&drv->dev, NPU_REG_STATUS),
- ethosu_read_reg(&drv->dev, NPU_REG_QREAD));
-
- // Verify that interrupt has been raised
- (void)ethosu_is_irq_raised(&drv->dev, &irq_raised);
- assert(irq_raised == 1);
- drv->irq_triggered = true;
-
- // Clear interrupt
- (void)ethosu_clear_irq_status(&drv->dev);
-
- // Verify that interrupt has been successfully cleared
- (void)ethosu_is_irq_raised(&drv->dev, &irq_raised);
- assert(irq_raised == 0);
-
- if (ethosu_status_has_error(&drv->dev))
- {
- ethosu_soft_reset_and_restore(drv);
- drv->status_error = true;
- }
-
- ethosu_semaphore_give(drv->semaphore);
-}
-
-static inline void wait_for_irq(struct ethosu_driver *drv)
-{
- while (1)
- {
- if (drv->irq_triggered || drv->abort_inference)
- {
- drv->irq_triggered = false;
- break;
- }
-
- ethosu_semaphore_take(drv->semaphore);
- }
-}
+/******************************************************************************
+ * Weak functions - Inference begin/end callbacks
+ ******************************************************************************/
void __attribute__((weak)) ethosu_inference_begin(struct ethosu_driver *drv, const void *inference_data)
{
- (void)inference_data;
- (void)drv;
+ UNUSED(inference_data);
+ UNUSED(drv);
}
void __attribute__((weak)) ethosu_inference_end(struct ethosu_driver *drv, const void *inference_data)
{
- (void)inference_data;
- (void)drv;
-}
-
-static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s *opt_cfg_p);
-static int handle_command_stream(struct ethosu_driver *drv,
- const uint8_t *cmd_stream,
- const int cms_length,
- const uint64_t *base_addr,
- const size_t *base_addr_size,
- const int num_base_addr);
-static int read_apb_reg(struct ethosu_driver *drv, uint16_t);
-static int dump_shram(struct ethosu_driver *drv);
-static void dump_npu_register(struct ethosu_driver *drv, int npu_reg, int npu_reg_end);
-static void dump_command_stream(const uint32_t *cmd_stream, const int cms_length, int qread);
-static void npu_axi_init(struct ethosu_driver *drv);
-static struct ethosu_driver *ethosu_find_and_reserve_driver(void);
-
-int ethosu_init(struct ethosu_driver *drv,
- const void *base_address,
- const void *fast_memory,
- const size_t fast_memory_size,
- uint32_t secure_enable,
- uint32_t privilege_enable)
-{
- int return_code = 0;
-
- LOG_INFO("%s. base_address=%p, fast_memory=%p, fast_memory_size=%zu, secure=%" PRIu32 ", privileged=%" PRIu32 "\n",
- __FUNCTION__,
- base_address,
- fast_memory,
- fast_memory_size,
- secure_enable,
- privilege_enable);
-
- if (!ethosu_mutex)
- {
- ethosu_mutex = ethosu_mutex_create();
- }
-
- if (!ethosu_semaphore)
- {
- ethosu_semaphore = ethosu_semaphore_create();
- }
-
- ethosu_register_driver(drv);
-
- drv->fast_memory = (uint32_t)fast_memory;
- drv->fast_memory_size = fast_memory_size;
- drv->irq_triggered = false;
- drv->semaphore = ethosu_semaphore_create();
-
- if (ETHOSU_SUCCESS != ethosu_dev_init(&drv->dev, base_address, secure_enable, privilege_enable))
- {
- LOG_ERR("Failed in ethosu_dev_init");
- return -1;
- }
-
- if (ETHOSU_SUCCESS !=
- set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_DISABLE, ETHOSU_POWER_Q_DISABLE))
- {
- LOG_ERR("Failed to disable clock-q & power-q for Ethos-U\n");
- return -1;
- }
-
- if (ETHOSU_SUCCESS != ethosu_soft_reset(&drv->dev))
- {
- return -1;
- }
-
- if (ETHOSU_SUCCESS != ethosu_wait_for_reset(&drv->dev))
- {
- LOG_ERR("Failed reset of Ethos-U\n");
- return -1;
- }
-
- drv->status_error = false;
-
- return return_code;
-}
-
-int ethosu_get_version(struct ethosu_driver *drv, struct ethosu_version *version)
-{
- int return_code = 0;
-
- if (NULL != version)
- {
- struct ethosu_id id;
- struct ethosu_config cfg;
- (void)ethosu_get_id(&drv->dev, &id);
- (void)ethosu_get_config(&drv->dev, &cfg);
-
- version->id.version_status = id.version_status;
- version->id.version_minor = id.version_minor;
- version->id.version_major = id.version_major;
- version->id.product_major = id.product_major;
- version->id.arch_patch_rev = id.arch_patch_rev;
- version->id.arch_minor_rev = id.arch_minor_rev;
- version->id.arch_major_rev = id.arch_major_rev;
- version->id.driver_patch_rev = ETHOSU_DRIVER_VERSION_PATCH;
- version->id.driver_minor_rev = ETHOSU_DRIVER_VERSION_MINOR;
- version->id.driver_major_rev = ETHOSU_DRIVER_VERSION_MAJOR;
- version->cfg.macs_per_cc = cfg.macs_per_cc;
- version->cfg.cmd_stream_version = cfg.cmd_stream_version;
- version->cfg.shram_size = cfg.shram_size;
- version->cfg.custom_dma = cfg.custom_dma;
- }
- else
- {
- return_code = -1;
- }
-
- return return_code;
+ UNUSED(inference_data);
+ UNUSED(drv);
}
-int ethosu_invoke(struct ethosu_driver *drv,
- const void *custom_data_ptr,
- const int custom_data_size,
- const uint64_t *base_addr,
- const size_t *base_addr_size,
- const int num_base_addr)
+/******************************************************************************
+ * Static functions
+ ******************************************************************************/
+static inline void wait_for_irq(struct ethosu_driver *drv)
{
- const struct custom_data_s *data_ptr = custom_data_ptr;
- const struct custom_data_s *data_end = custom_data_ptr + custom_data_size;
- int return_code = 0;
-
- LOG_INFO("%s\n", __FUNCTION__);
-
- // First word in custom_data_ptr should contain "Custom Operator Payload 1"
- if (data_ptr->word != ETHOSU_FOURCC)
- {
- LOG_ERR("Custom Operator Payload: %" PRIu32 " is not correct, expected %x\n", data_ptr->word, ETHOSU_FOURCC);
- return -1;
- }
-
- // Custom data length must be a multiple of 32 bits
- if ((custom_data_size % BYTES_IN_32_BITS) != 0)
- {
- LOG_ERR("ethosu_invoke ERROR custom_data_size=0x%x not a multiple of 4\n", custom_data_size);
- return -1;
- }
-
- ++data_ptr;
-
- // Adjust base address to fast memory area
- if (drv->fast_memory != 0 && num_base_addr >= FAST_MEMORY_BASE_ADDR_INDEX)
- {
- uint64_t *fast_memory = (uint64_t *)&base_addr[FAST_MEMORY_BASE_ADDR_INDEX];
-
- if (base_addr_size != NULL && base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > drv->fast_memory_size)
- {
- LOG_ERR("Fast memory area too small. fast_memory_size=%u, base_addr_size=%u\n",
- drv->fast_memory_size,
- base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX]);
- return -1;
- }
-
- *fast_memory = drv->fast_memory;
- }
-
- if (!drv->dev_power_always_on)
- {
- // Only soft reset if securty state or privilege level needs changing
- if (drv->dev.proto != ethosu_read_reg(&drv->dev, NPU_REG_PROT))
- {
- if (ETHOSU_SUCCESS != ethosu_soft_reset(&drv->dev))
- {
- return -1;
- }
- }
-
- drv->status_error = false;
- set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE);
- ethosu_restore_pmu_config(&drv->dev);
- npu_axi_init(drv);
- }
-
- drv->status_error = false;
-
- ethosu_inference_begin(drv, custom_data_ptr);
- while (data_ptr < data_end)
+ while (1)
{
- int ret = 0;
- switch (data_ptr->driver_action_command)
+ if (drv->irq_triggered || drv->abort_inference)
{
- case OPTIMIZER_CONFIG:
- LOG_INFO("ethosu_invoke OPTIMIZER_CONFIG\n");
- struct opt_cfg_s *opt_cfg_p = (struct opt_cfg_s *)data_ptr;
-
- ret = handle_optimizer_config(drv, opt_cfg_p);
- data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD;
- break;
- case COMMAND_STREAM:
- LOG_INFO("ethosu_invoke COMMAND_STREAM\n");
- void *command_stream = (uint8_t *)(data_ptr) + sizeof(struct custom_data_s);
- int cms_length = (data_ptr->reserved << 16) | data_ptr->length;
-
- drv->abort_inference = false;
- // It is safe to clear this flag without atomic, because npu is not running.
drv->irq_triggered = false;
-
- ret = handle_command_stream(drv, command_stream, cms_length, base_addr, base_addr_size, num_base_addr);
-
- if (return_code == -1 && drv->abort_inference)
- {
- uint32_t qread = 0;
- ethosu_get_qread(&drv->dev, &qread);
- LOG_ERR("NPU timeout\n");
- dump_command_stream(command_stream, cms_length, qread);
- dump_npu_register(drv, 0x200, 0x2BF);
- dump_npu_register(drv, 0x800, 0xB3F);
- dump_shram(drv);
- }
-
- data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + cms_length;
- break;
- case READ_APB_REG:
- LOG_INFO("ethosu_invoke READ_APB_REG\n");
- ret = read_apb_reg(drv, data_ptr->driver_action_data);
- data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
- break;
- case DUMP_SHRAM:
- LOG_INFO("ethosu_invoke DUMP_SHRAM\n");
- ret = dump_shram(drv);
- data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
- break;
- case NOP:
- LOG_INFO("ethosu_invoke NOP\n");
- data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
- break;
- default:
- LOG_ERR("ethosu_invoke UNSUPPORTED driver_action_command %d \n", data_ptr->driver_action_command);
- ret = -1;
break;
}
- if (ret != 0)
- {
- return_code = -1;
- break;
- }
- }
- ethosu_inference_end(drv, custom_data_ptr);
-
- if (!drv->status_error && !drv->dev_power_always_on)
- {
- ethosu_save_pmu_counters(&drv->dev);
- set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
- }
-
- return return_code;
-}
-
-void ethosu_abort(struct ethosu_driver *drv)
-{
- drv->abort_inference = true;
-}
-void ethosu_set_power_mode(struct ethosu_driver *drv, bool always_on)
-{
- drv->dev_power_always_on = always_on;
-
- if (always_on)
- {
- npu_axi_init(drv);
+ ethosu_semaphore_take(drv->semaphore);
}
}
-int ethosu_register_driver(struct ethosu_driver *drv)
+static void npu_axi_init(struct ethosu_driver *drv)
{
- // Safeguard check for if driver is already registered
- struct ethosu_driver *cur = registered_drivers;
- while (cur != NULL)
- {
- if (cur == drv)
- {
- LOG_ERR("%s: NPU driver at address %p is already registered.\n", __FUNCTION__, drv);
- return -1;
- }
- cur = cur->next;
- }
-
- drv->next = registered_drivers;
- // Designate new registered driver HEAD
+ ethosu_dev_set_qconfig(&drv->dev, NPU_QCONFIG);
+
+ ethosu_dev_set_regioncfg(&drv->dev, 0, NPU_REGIONCFG_0);
+ ethosu_dev_set_regioncfg(&drv->dev, 1, NPU_REGIONCFG_1);
+ ethosu_dev_set_regioncfg(&drv->dev, 2, NPU_REGIONCFG_2);
+ ethosu_dev_set_regioncfg(&drv->dev, 3, NPU_REGIONCFG_3);
+ ethosu_dev_set_regioncfg(&drv->dev, 4, NPU_REGIONCFG_4);
+ ethosu_dev_set_regioncfg(&drv->dev, 5, NPU_REGIONCFG_5);
+ ethosu_dev_set_regioncfg(&drv->dev, 6, NPU_REGIONCFG_6);
+ ethosu_dev_set_regioncfg(&drv->dev, 7, NPU_REGIONCFG_7);
+
+ (void)ethosu_dev_set_axi_limit0(&drv->dev,
+ AXI_LIMIT0_MAX_BEATS_BYTES,
+ AXI_LIMIT0_MEM_TYPE,
+ AXI_LIMIT0_MAX_OUTSTANDING_READS,
+ AXI_LIMIT0_MAX_OUTSTANDING_WRITES);
+ (void)ethosu_dev_set_axi_limit1(&drv->dev,
+ AXI_LIMIT1_MAX_BEATS_BYTES,
+ AXI_LIMIT1_MEM_TYPE,
+ AXI_LIMIT1_MAX_OUTSTANDING_READS,
+ AXI_LIMIT1_MAX_OUTSTANDING_WRITES);
+ (void)ethosu_dev_set_axi_limit2(&drv->dev,
+ AXI_LIMIT2_MAX_BEATS_BYTES,
+ AXI_LIMIT2_MEM_TYPE,
+ AXI_LIMIT2_MAX_OUTSTANDING_READS,
+ AXI_LIMIT2_MAX_OUTSTANDING_WRITES);
+ (void)ethosu_dev_set_axi_limit3(&drv->dev,
+ AXI_LIMIT3_MAX_BEATS_BYTES,
+ AXI_LIMIT3_MEM_TYPE,
+ AXI_LIMIT3_MAX_OUTSTANDING_READS,
+ AXI_LIMIT3_MAX_OUTSTANDING_WRITES);
+}
+
+static void ethosu_register_driver(struct ethosu_driver *drv)
+{
+ // Register driver as new HEAD of list
+ drv->next = registered_drivers;
registered_drivers = drv;
- LOG_INFO("%s: New NPU driver at address %p is registered.\n", __FUNCTION__, drv);
- return 0;
+ LOG_INFO("New NPU driver registered (handle: 0x%p, NPU: 0x%x)", drv, drv->dev.base_address);
}
-int ethosu_deregister_driver(struct ethosu_driver *drv)
+static int ethosu_deregister_driver(struct ethosu_driver *drv)
{
struct ethosu_driver *cur = registered_drivers;
struct ethosu_driver **prev = &registered_drivers;
@@ -569,7 +324,7 @@ int ethosu_deregister_driver(struct ethosu_driver *drv)
if (cur == drv)
{
*prev = cur->next;
- LOG_INFO("%s: NPU driver at address %p is deregistered.\n", __FUNCTION__, drv);
+ LOG_INFO("NPU driver handle %p deregistered.", drv);
return 0;
}
@@ -577,36 +332,11 @@ int ethosu_deregister_driver(struct ethosu_driver *drv)
cur = cur->next;
}
- LOG_ERR("%s: NPU driver at address %p does not match a registered driver and therefore may not be deregistered.\n",
- __FUNCTION__,
- drv);
+ LOG_ERR("No NPU driver handle registered at address %p.", drv);
return -1;
}
-struct ethosu_driver *ethosu_reserve_driver(void)
-{
- struct ethosu_driver *drv = NULL;
-
- do
- {
- ethosu_mutex_lock(ethosu_mutex);
- drv = ethosu_find_and_reserve_driver();
- ethosu_mutex_unlock(ethosu_mutex);
-
- if (drv != NULL)
- {
- break;
- }
-
- LOG_INFO("%s - Waiting for driver \n", __FUNCTION__);
- ethosu_semaphore_take(ethosu_semaphore);
-
- } while (1);
-
- return drv;
-}
-
static struct ethosu_driver *ethosu_find_and_reserve_driver(void)
{
struct ethosu_driver *drv = registered_drivers;
@@ -616,33 +346,21 @@ static struct ethosu_driver *ethosu_find_and_reserve_driver(void)
if (!drv->reserved)
{
drv->reserved = true;
- LOG_INFO("%s - Driver %p reserved.\n", __FUNCTION__, drv);
+ LOG_DEBUG("NPU driver handle %p reserved.", drv);
return drv;
}
drv = drv->next;
}
- LOG_INFO("%s: No available drivers.\n", __FUNCTION__, drv);
+ LOG_DEBUG("No NPU driver handle available.", drv);
return NULL;
}
-void ethosu_release_driver(struct ethosu_driver *drv)
-{
- ethosu_mutex_lock(ethosu_mutex);
- if (drv != NULL && drv->reserved)
- {
- drv->reserved = false;
- LOG_INFO("%s - Driver %p released\n", __FUNCTION__, drv);
- ethosu_semaphore_give(ethosu_semaphore);
- }
- ethosu_mutex_unlock(ethosu_mutex);
-}
-
static int ethosu_soft_reset_and_restore(struct ethosu_driver *drv)
{
- if (ETHOSU_SUCCESS != ethosu_soft_reset(&drv->dev))
+ if (ETHOSU_SUCCESS != ethosu_dev_soft_reset(&drv->dev))
{
return -1;
}
@@ -650,73 +368,37 @@ static int ethosu_soft_reset_and_restore(struct ethosu_driver *drv)
set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE);
npu_axi_init(drv);
- ethosu_restore_pmu_config(&drv->dev);
+ ethosu_dev_restore_pmu_config(&drv->dev);
return 0;
}
-enum ethosu_error_codes set_clock_and_power_request(struct ethosu_driver *drv,
- enum ethosu_request_clients client,
- enum ethosu_clock_q_request clock_request,
- enum ethosu_power_q_request power_request)
-{
- // Set clock request bit for client
- if (clock_request == ETHOSU_CLOCK_Q_DISABLE)
- {
- drv->clock_request |= (1 << client);
- }
- else
- {
- drv->clock_request &= ~(1 << client);
- }
- // Get current clock request (ENABLE if both PMU and INFERENCE asks for clock request, else DISABLE)
- clock_request = drv->clock_request == 0 ? ETHOSU_CLOCK_Q_ENABLE : ETHOSU_CLOCK_Q_DISABLE;
-
- // Set power request bit for client
- if (power_request == ETHOSU_POWER_Q_DISABLE)
- {
- drv->power_request |= (1 << client);
- }
- else
- {
- drv->power_request &= ~(1 << client);
- }
- // Get current power request (ENABLE if both PMU and INFERENCE asks for power request, else DISABLE)
- power_request = drv->power_request == 0 ? ETHOSU_POWER_Q_ENABLE : ETHOSU_POWER_Q_DISABLE;
-
- // Set clock and power
- enum ethosu_error_codes ret = ethosu_set_clock_and_power(&drv->dev, clock_request, power_request);
-
- return ret;
-}
-
static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s *opt_cfg_p)
{
struct ethosu_config cfg;
struct ethosu_id id;
int return_code = 0;
- LOG_INFO("handle_optimizer_config:\n");
- LOG_INFO("Optimizer release nbr: %d patch: %d\n", opt_cfg_p->da_data.rel_nbr, opt_cfg_p->da_data.patch_nbr);
- LOG_INFO("Optimizer config cmd_stream_version: %d macs_per_cc: %d shram_size: %d custom_dma: %d\n",
+ LOG_INFO("Optimizer release nbr: %d patch: %d", opt_cfg_p->da_data.rel_nbr, opt_cfg_p->da_data.patch_nbr);
+ LOG_INFO("Optimizer config cmd_stream_version: %d macs_per_cc: %d shram_size: %d custom_dma: %d",
opt_cfg_p->cmd_stream_version,
opt_cfg_p->macs_per_cc,
opt_cfg_p->shram_size,
opt_cfg_p->custom_dma);
- LOG_INFO("Optimizer config Ethos-U version: %d.%d.%d\n",
+ LOG_INFO("Optimizer config Ethos-U version: %d.%d.%d",
opt_cfg_p->arch_major_rev,
opt_cfg_p->arch_minor_rev,
opt_cfg_p->arch_patch_rev);
- (void)ethosu_get_config(&drv->dev, &cfg);
- (void)ethosu_get_id(&drv->dev, &id);
+ (void)ethosu_dev_get_config(&drv->dev, &cfg);
+ (void)ethosu_dev_get_id(&drv->dev, &id);
LOG_INFO("Ethos-U config cmd_stream_version: %" PRIu32 " macs_per_cc: %" PRIu32 " shram_size: %" PRIu32
- " custom_dma: %" PRIu32 "\n",
+ " custom_dma: %" PRIu32 "",
cfg.cmd_stream_version,
cfg.macs_per_cc,
cfg.shram_size,
cfg.custom_dma);
- LOG_INFO("Ethos-U version: %" PRIu32 ".%" PRIu32 ".%" PRIu32 "\n",
+ LOG_INFO("Ethos-U version: %" PRIu32 ".%" PRIu32 ".%" PRIu32 "",
id.arch_major_rev,
id.arch_minor_rev,
id.arch_patch_rev);
@@ -726,25 +408,25 @@ static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s *
{
if (cfg.macs_per_cc != opt_cfg_p->macs_per_cc)
{
- LOG_ERR("NPU config mismatch: npu.macs_per_cc=%" PRIu32 " optimizer.macs_per_cc=%d\n",
+ LOG_ERR("NPU config mismatch: npu.macs_per_cc=%" PRIu32 " optimizer.macs_per_cc=%d",
cfg.macs_per_cc,
opt_cfg_p->macs_per_cc);
}
if (cfg.shram_size != opt_cfg_p->shram_size)
{
- LOG_ERR("NPU config mismatch: npu.shram_size=%" PRIu32 " optimizer.shram_size=%d\n",
+ LOG_ERR("NPU config mismatch: npu.shram_size=%" PRIu32 " optimizer.shram_size=%d",
cfg.shram_size,
opt_cfg_p->shram_size);
}
if (cfg.cmd_stream_version != opt_cfg_p->cmd_stream_version)
{
- LOG_ERR("NPU config mismatch: npu.cmd_stream_version=%" PRIu32 " optimizer.cmd_stream_version=%d\n",
+ LOG_ERR("NPU config mismatch: npu.cmd_stream_version=%" PRIu32 " optimizer.cmd_stream_version=%d",
cfg.cmd_stream_version,
opt_cfg_p->cmd_stream_version);
}
if (!cfg.custom_dma && opt_cfg_p->custom_dma)
{
- LOG_ERR("NPU config mismatch: npu.custom_dma=%" PRIu32 " optimize.custom_dma=%d\n",
+ LOG_ERR("NPU config mismatch: npu.custom_dma=%" PRIu32 " optimize.custom_dma=%d",
cfg.custom_dma,
opt_cfg_p->custom_dma);
}
@@ -753,7 +435,7 @@ static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s *
if ((id.arch_major_rev != opt_cfg_p->arch_major_rev) || (id.arch_minor_rev < opt_cfg_p->arch_minor_rev))
{
- LOG_ERR("NPU arch mismatch: npu.arch=%" PRIu32 ".%" PRIu32 ".%" PRIu32 " optimizer.arch=%d.%d.%d\n",
+ LOG_ERR("NPU arch mismatch: npu.arch=%" PRIu32 ".%" PRIu32 ".%" PRIu32 " optimizer.arch=%d.%d.%d",
id.arch_major_rev,
id.arch_minor_rev,
id.arch_patch_rev,
@@ -769,59 +451,6 @@ static int handle_optimizer_config(struct ethosu_driver *drv, struct opt_cfg_s *
return return_code;
}
-static void npu_axi_init(struct ethosu_driver *drv)
-{
- ethosu_set_qconfig(&drv->dev, NPU_QCONFIG);
-
- ethosu_set_regioncfg(&drv->dev, 0, NPU_REGIONCFG_0);
- ethosu_set_regioncfg(&drv->dev, 1, NPU_REGIONCFG_1);
- ethosu_set_regioncfg(&drv->dev, 2, NPU_REGIONCFG_2);
- ethosu_set_regioncfg(&drv->dev, 3, NPU_REGIONCFG_3);
- ethosu_set_regioncfg(&drv->dev, 4, NPU_REGIONCFG_4);
- ethosu_set_regioncfg(&drv->dev, 5, NPU_REGIONCFG_5);
- ethosu_set_regioncfg(&drv->dev, 6, NPU_REGIONCFG_6);
- ethosu_set_regioncfg(&drv->dev, 7, NPU_REGIONCFG_7);
-
- (void)ethosu_set_axi_limit0(&drv->dev,
- AXI_LIMIT0_MAX_BEATS_BYTES,
- AXI_LIMIT0_MEM_TYPE,
- AXI_LIMIT0_MAX_OUTSTANDING_READS,
- AXI_LIMIT0_MAX_OUTSTANDING_WRITES);
- (void)ethosu_set_axi_limit1(&drv->dev,
- AXI_LIMIT1_MAX_BEATS_BYTES,
- AXI_LIMIT1_MEM_TYPE,
- AXI_LIMIT1_MAX_OUTSTANDING_READS,
- AXI_LIMIT1_MAX_OUTSTANDING_WRITES);
- (void)ethosu_set_axi_limit2(&drv->dev,
- AXI_LIMIT2_MAX_BEATS_BYTES,
- AXI_LIMIT2_MEM_TYPE,
- AXI_LIMIT2_MAX_OUTSTANDING_READS,
- AXI_LIMIT2_MAX_OUTSTANDING_WRITES);
- (void)ethosu_set_axi_limit3(&drv->dev,
- AXI_LIMIT3_MAX_BEATS_BYTES,
- AXI_LIMIT3_MEM_TYPE,
- AXI_LIMIT3_MAX_OUTSTANDING_READS,
- AXI_LIMIT3_MAX_OUTSTANDING_WRITES);
-}
-
-/* Default implementation to flush the data cache. Override if available on the targeted device.
- * Passing NULL as p argument expects the whole cache to be flushed.
- */
-void __attribute__((weak)) ethosu_flush_dcache(uint32_t *p, size_t bytes)
-{
- (void)p;
- (void)bytes;
-}
-
-/* Default implementation to invalidate the data cache. Override if available on the targeted device.
- * Passing NULL as p argument expects the whole cache to be flushed.
- */
-void __attribute__((weak)) ethosu_invalidate_dcache(uint32_t *p, size_t bytes)
-{
- (void)p;
- (void)bytes;
-}
-
static int handle_command_stream(struct ethosu_driver *drv,
const uint8_t *cmd_stream,
const int cms_length,
@@ -833,11 +462,11 @@ static int handle_command_stream(struct ethosu_driver *drv,
uint32_t cms_bytes = cms_length * BYTES_IN_32_BITS;
ptrdiff_t cmd_stream_ptr = (ptrdiff_t)cmd_stream;
- LOG_INFO("handle_command_stream: cmd_stream=%p, cms_length %d\n", cmd_stream, cms_length);
+ LOG_INFO("handle_command_stream: cmd_stream=%p, cms_length %d", cmd_stream, cms_length);
if (0 != ((ptrdiff_t)cmd_stream & MASK_16_BYTE_ALIGN))
{
- LOG_ERR("Error: Command stream addr %p not aligned to 16 bytes\n", cmd_stream);
+ LOG_ERR("Command stream addr %p not aligned to 16 bytes", cmd_stream);
return -1;
}
@@ -846,7 +475,7 @@ static int handle_command_stream(struct ethosu_driver *drv,
{
if (0 != (base_addr[i] & MASK_16_BYTE_ALIGN))
{
- LOG_ERR("Error: Base addr %d: 0x%llx not aligned to 16 bytes\n", i, base_addr[i]);
+ LOG_ERR("Base addr %d: 0x%llx not aligned to 16 bytes", i, base_addr[i]);
base_addr_invalid = true;
}
}
@@ -875,7 +504,7 @@ static int handle_command_stream(struct ethosu_driver *drv,
ethosu_flush_dcache(NULL, 0);
}
- if (ETHOSU_SUCCESS != ethosu_run_command_stream(&drv->dev, cmd_stream, cms_bytes, base_addr, num_base_addr))
+ if (ETHOSU_SUCCESS != ethosu_dev_run_command_stream(&drv->dev, cmd_stream, cms_bytes, base_addr, num_base_addr))
{
return -1;
}
@@ -899,11 +528,10 @@ static int handle_command_stream(struct ethosu_driver *drv,
ethosu_invalidate_dcache(NULL, 0);
}
- (void)ethosu_get_qread(&drv->dev, &qread);
+ qread = ethosu_dev_get_qread(&drv->dev);
if (qread != cms_bytes)
{
- LOG_WARN(
- "Failure: IRQ received but qread (%" PRIu32 ") not at end of stream (%" PRIu32 ").\n", qread, cms_bytes);
+ LOG_WARN("IRQ received but qread (%" PRIu32 ") not at end of stream (%" PRIu32 ").", qread, cms_bytes);
return -1;
}
@@ -919,16 +547,16 @@ static int read_apb_reg(struct ethosu_driver *drv, uint16_t da_data)
reg_p = (uint32_t *)malloc(num_reg * sizeof(uint32_t));
if (reg_p == NULL)
{
- LOG_INFO("read_apb_reg, Error! memory not allocated.");
+ LOG_ERR("Memory allocation failed");
return -1;
}
- if (ETHOSU_SUCCESS == ethosu_read_apb_reg(&drv->dev, start_address, num_reg, reg_p))
+ if (ETHOSU_SUCCESS == ethosu_dev_read_apb_reg(&drv->dev, start_address, num_reg, reg_p))
{
for (int i = 0; i < num_reg; i++)
{
LOG_INFO(
- "NPU_REG ADDR 0x%04" PRIu32 " = 0x%08" PRIu32 "\n", (start_address + (i * BYTES_IN_32_BITS)), reg_p[i]);
+ "NPU_REG ADDR 0x%04" PRIu32 " = 0x%08" PRIu32 "", (start_address + (i * BYTES_IN_32_BITS)), reg_p[i]);
}
}
else
@@ -945,25 +573,25 @@ static int dump_shram(struct ethosu_driver *drv)
{
struct ethosu_config cfg;
uint32_t *shram_p;
- (void)ethosu_get_config(&drv->dev, &cfg);
+ (void)ethosu_dev_get_config(&drv->dev, &cfg);
- LOG_INFO("dump_shram size = %" PRIu32 " KB\n", cfg.shram_size);
+ LOG_INFO("dump_shram size = %" PRIu32 " KB", cfg.shram_size);
shram_p = (uint32_t *)malloc(BYTES_1KB);
if (shram_p == NULL)
{
- LOG_ERR("read_shram, Error! memory not allocated.");
+ LOG_ERR("Memory allocation failed for shram data");
return -1;
}
for (uint32_t i = 0; i < cfg.shram_size; i++)
{
- ethosu_get_shram_data(&drv->dev, i, (uint32_t *)shram_p);
+ ethosu_dev_get_shram_data(&drv->dev, i, (uint32_t *)shram_p);
// Output 1KB of SHRAM
- LOG_INFO("***SHRAM SECTION %" PRIu32 "***\n", i);
+ LOG_INFO("***SHRAM SECTION %" PRIu32 "***", i);
for (int j = 0; j < (BYTES_1KB / BYTES_IN_32_BITS); j++)
{
- LOG_INFO("[0x%04" PRIx32 "] %" PRIx32 "\n", (i * 1024 + j * 4), shram_p[j]);
+ LOG_INFO("[0x%04" PRIx32 "] %" PRIx32 "", (i * 1024 + j * 4), shram_p[j]);
}
}
free(shram_p);
@@ -971,317 +599,330 @@ static int dump_shram(struct ethosu_driver *drv)
return 0;
}
-typedef struct
+/******************************************************************************
+ * Weak functions - Interrupt handler
+ ******************************************************************************/
+void __attribute__((weak)) ethosu_irq_handler(struct ethosu_driver *drv)
{
- int number;
- const char *name;
-} name_lookup_t;
-
-static const name_lookup_t npu_reg_name_tbl[] = {
- {0x200, "KERNEL_X"},
- {0x204, "KERNEL_Y"},
- {0x208, "KERNEL_W_M1"},
- {0x20C, "KERNEL_H_M1"},
- {0x210, "OFM_CBLK_WIDTH_M1"},
- {0x214, "OFM_CBLK_HEIGHT_M1"},
- {0x218, "OFM_CBLK_DEPTH_M1"},
- {0x21c, "IFM_CBLK_DEPTH_M1"},
- {0x220, "OFM_X"},
- {0x224, "OFM_Y"},
- {0x228, "OFM_Z"},
- {0x22C, "IFM_Z"},
- {0x230, "PAD_TOP"},
- {0x234, "PAD_LEFT"},
- {0x238, "IFM_CBLK_WIDTH"},
- {0x23C, "IFM_CBLK_HEIGHT"},
- {0x240, "DMA_IFM_SRC"},
- {0x244, "DMA_IFM_SRC_HI"},
- {0x248, "DMA_IFM_DST"},
- {0x24c, "DMA_OFM_SRC"},
- {0x250, "DMA_OFM_DST"},
- {0x254, "DMA_OFM_DST_HI"},
- {0x258, "DMA_WEIGHT_SRC"},
- {0x25c, "DMA_WEIGHT_SRC_HI"},
- {0x260, "DMA_CMD_SRC"},
- {0x264, "DMA_CMD_SRC_HI"},
- {0x268, "DMA_CMD_SIZE"},
- {0x26c, "DMA_M2M_SRC"},
- {0x270, "DMA_M2M_SRC_HI"},
- {0x274, "DMA_M2M_DST"},
- {0x278, "DMA_M2M_DST_HI"},
- {0x27c, "CURRENT_QREAD"},
- {0x280, "DMA_SCALE_SRC"},
- {0x284, "DMA_SCALE_SRC_HI"},
- {0x2BC, "CURRENT_CMD"},
- {0x800, "IFM_PAD_TOP"},
- {0x804, "IFM_PAD_LEFT"},
- {0x808, "IFM_PAD_RIGHT"},
- {0x80C, "IFM_PAD_BOTTOM"},
- {0x810, "IFM_DEPTH_M1"},
- {0x814, "IFM_PRECISION"},
- {0x81C, "IFM_UPSCALE"},
- {0x824, "IFM_ZERO_POINT"},
- {0x828, "IFM_WIDTH0_M1"},
- {0x82C, "IFM_HEIGHT0_M1"},
- {0x830, "IFM_HEIGHT1_M1"},
- {0x834, "IFM_IB_END"},
- {0x83C, "IFM_REGION"},
- {0x844, "OFM_WIDTH_M1"},
- {0x848, "OFM_HEIGHT_M1"},
- {0x84C, "OFM_DEPTH_M1"},
- {0x850, "OFM_PRECISION"},
- {0x854, "OFM_BLK_WIDTH_M1"},
- {0x858, "OFM_BLK_HEIGHT_M1"},
- {0x85C, "OFM_BLK_DEPTH_M1"},
- {0x860, "OFM_ZERO_POINT"},
- {0x868, "OFM_WIDTH0_M1"},
- {0x86C, "OFM_HEIGHT0_M1"},
- {0x870, "OFM_HEIGHT1_M1"},
- {0x87C, "OFM_REGION"},
- {0x880, "KERNEL_WIDTH_M1"},
- {0x884, "KERNEL_HEIGHT_M1"},
- {0x888, "KERNEL_STRIDE"},
- {0x88C, "PARALLEL_MODE"},
- {0x890, "ACC_FORMAT"},
- {0x894, "ACTIVATION"},
- {0x898, "ACTIVATION_MIN"},
- {0x89C, "ACTIVATION_MAX"},
- {0x8A0, "WEIGHT_REGION"},
- {0x8A4, "SCALE_REGION"},
- {0x8B4, "AB_START"},
- {0x8BC, "BLOCKDEP"},
- {0x8C0, "DMA0_SRC_REGION"},
- {0x8C4, "DMA0_DST_REGION"},
- {0x8C8, "DMA0_SIZE0"},
- {0x8CC, "DMA0_SIZE1"},
- {0x900, "IFM2_BROADCAST"},
- {0x904, "IFM2_SCALAR"},
- {0x924, "IFM2_ZERO_POINT"},
- {0x928, "IFM2_WIDTH0_M1"},
- {0x92C, "IFM2_HEIGHT0_M1"},
- {0x930, "IFM2_HEIGHT1_M1"},
- {0x934, "IFM2_IB_START"},
- {0x93C, "IFM2_REGION"},
- {0xA00, "IFM_BASE0"},
- {0xA04, "IFM_BASE0_HI"},
- {0xA08, "IFM_BASE1"},
- {0xA0C, "IFM_BASE1_HI"},
- {0xA10, "IFM_BASE2"},
- {0xA14, "IFM_BASE2_HI"},
- {0xA18, "IFM_BASE3"},
- {0xA1C, "IFM_BASE3_HI"},
- {0xA20, "IFM_STRIDE_X"},
- {0xA24, "IFM_STRIDE_X_HI"},
- {0xA28, "IFM_STRIDE_Y"},
- {0xA2C, "IFM_STRIDE_Y_HI"},
- {0xA30, "IFM_STRIDE_C"},
- {0xA34, "IFM_STRIDE_C_HI"},
- {0xA40, "OFM_BASE0"},
- {0xA44, "OFM_BASE0_HI"},
- {0xA48, "OFM_BASE1"},
- {0xA4C, "OFM_BASE1_HI"},
- {0xA50, "OFM_BASE2"},
- {0xA54, "OFM_BASE2_HI"},
- {0xA58, "OFM_BASE3"},
- {0xA5C, "OFM_BASE3_HI"},
- {0xA60, "OFM_STRIDE_X"},
- {0xA64, "OFM_STRIDE_X_HI"},
- {0xA68, "OFM_STRIDE_Y"},
- {0xA6C, "OFM_STRIDE_Y_HI"},
- {0xA70, "OFM_STRIDE_C"},
- {0xA74, "OFM_STRIDE_C_HI"},
- {0xA80, "WEIGHT_BASE"},
- {0xA84, "WEIGHT_BASE_HI"},
- {0xA88, "WEIGHT_LENGTH"},
- {0xA8C, "WEIGHT_LENGTH_HI"},
- {0xA90, "SCALE_BASE"},
- {0xA94, "SCALE_BASE_HI"},
- {0xA98, "SCALE_LENGTH"},
- {0xAA0, "OFM_SCALE"},
- {0xAA4, "OFM_SCALE_SHIFT"},
- {0xAA8, "OPA_SCALE "},
- {0xAB0, "OPB_SCALE"},
- {0xAC0, "DMA0_SRC"},
- {0xAC4, "DMA0_SRC_HI"},
- {0xAC8, "DMA0_DST"},
- {0xACC, "DMA0_DST_HI"},
- {0xAD0, "DMA0_LEN"},
- {0xAD4, "DMA0_LEN_HI"},
- {0xAD8, "DMA0_SKIP0"},
- {0xADC, "DMA0_SKIP0_HI"},
- {0xAE0, "DMA0_SKIP1"},
- {0xAE4, "DMA0_SKIP1_HI"},
- {0xB00, "IFM2_BASE0"},
- {0xB04, "IFM2_BASE0_HI"},
- {0xB08, "IFM2_BASE1"},
- {0xB0C, "IFM2_BASE1_HI"},
- {0xB10, "IFM2_BASE2"},
- {0xB14, "IFM2_BASE2_HI"},
- {0xB18, "IFM2_BASE3"},
- {0xB1C, "IFM2_BASE3_HI"},
- {0xB20, "IFM2_STRIDE_X"},
- {0xB24, "IFM2_STRIDE_X_HI"},
- {0xB28, "IFM2_STRIDE_Y"},
- {0xB2C, "IFM2_STRIDE_Y_HI"},
- {0xB30, "IFM2_STRIDE_C"},
- {0xB34, "IFM2_STRIDE_C_HI"},
- {0xB40, "WEIGHT1_BASE"},
- {0xB44, "WEIGHT1_BASE_HI"},
- {0xB48, "WEIGHT1_LENGTH"},
- {0xB4C, "WEIGHT1_LENGTH_HI"},
- {0xB50, "SCALE1_BASE"},
- {0xB54, "SCALE1_BASE_HI"},
- {0xB58, "SCALE1_LENGTH"},
-};
+ uint8_t irq_raised = 0;
-static const char *lookup_name(const name_lookup_t *lookup_table, int lookup_table_count, int find)
-{
- int n;
- for (n = 0; n < lookup_table_count; n++)
+ LOG_DEBUG("Interrupt. status=0x%08x, qread=%d", ethosu_dev_get_status(&drv->dev), ethosu_dev_get_qread(&drv->dev));
+
+ // Verify that interrupt has been raised
+ (void)ethosu_dev_is_irq_raised(&drv->dev, &irq_raised);
+ assert(irq_raised == 1);
+ drv->irq_triggered = true;
+
+ // Clear interrupt
+ (void)ethosu_dev_clear_irq_status(&drv->dev);
+
+ // Verify that interrupt has been successfully cleared
+ (void)ethosu_dev_is_irq_raised(&drv->dev, &irq_raised);
+ assert(irq_raised == 0);
+
+ if (ethosu_dev_status_has_error(&drv->dev))
{
- if (lookup_table[n].number == find)
- {
- return lookup_table[n].name;
- }
+ ethosu_soft_reset_and_restore(drv);
+ drv->status_error = true;
}
- // Not found
- return 0;
+
+ ethosu_semaphore_give(drv->semaphore);
}
-static void dump_npu_register(struct ethosu_driver *drv, int npu_reg, int npu_reg_end)
+/******************************************************************************
+ * Functions API
+ ******************************************************************************/
+
+int ethosu_init(struct ethosu_driver *drv,
+ const void *base_address,
+ const void *fast_memory,
+ const size_t fast_memory_size,
+ uint32_t secure_enable,
+ uint32_t privilege_enable)
{
- unsigned int reg_val;
- const char *reg_name;
- int npu_reg_name_tbl_count = sizeof(npu_reg_name_tbl) / sizeof(npu_reg_name_tbl[0]);
+ int return_code = 0;
+
+ LOG_INFO("Initializing NPU: base_address=%p, fast_memory=%p, fast_memory_size=%zu, secure=%" PRIu32
+ ", privileged=%" PRIu32,
+ base_address,
+ fast_memory,
+ fast_memory_size,
+ secure_enable,
+ privilege_enable);
+
+ if (!ethosu_mutex)
+ {
+ ethosu_mutex = ethosu_mutex_create();
+ }
- LOG_INFO("dump_register %X - %X\n", npu_reg, npu_reg_end);
- for (; npu_reg <= npu_reg_end; npu_reg += sizeof(int))
+ if (!ethosu_semaphore)
{
- reg_val = ethosu_read_reg(&drv->dev, npu_reg);
- reg_name = lookup_name(npu_reg_name_tbl, npu_reg_name_tbl_count, npu_reg);
- LOG_INFO("[0x%.4X] 0x%.8X\t%s\n", npu_reg, reg_val, (reg_name) ? reg_name : "");
+ ethosu_semaphore = ethosu_semaphore_create();
}
+
+ drv->fast_memory = (uint32_t)fast_memory;
+ drv->fast_memory_size = fast_memory_size;
+ drv->irq_triggered = false;
+ drv->semaphore = ethosu_semaphore_create();
+
+ if (ETHOSU_SUCCESS != ethosu_dev_init(&drv->dev, base_address, secure_enable, privilege_enable))
+ {
+ LOG_ERR("Failed to initialize Ethos-U device");
+ return -1;
+ }
+
+ if (ETHOSU_SUCCESS !=
+ set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_DISABLE, ETHOSU_POWER_Q_DISABLE))
+ {
+ LOG_ERR("Failed to disable clock-q & power-q for Ethos-U");
+ return -1;
+ }
+
+ if (ETHOSU_SUCCESS != ethosu_dev_soft_reset(&drv->dev))
+ {
+ return -1;
+ }
+
+ if (ETHOSU_SUCCESS != ethosu_dev_wait_for_reset(&drv->dev))
+ {
+ LOG_ERR("Failed reset of Ethos-U");
+ return -1;
+ }
+
+ drv->status_error = false;
+
+ ethosu_register_driver(drv);
+
+ return return_code;
}
-static const name_lookup_t cmd0_name_tbl[] = {
- {0x000, "NPU_OP_STOP"},
- {0x001, "NPU_OP_IRQ"},
- {0x002, "NPU_OP_CONV"},
- {0x003, "NPU_OP_DEPTHWISE"},
- {0x004, "NPU_OP_VECTOR_PROD"},
- {0x005, "NPU_OP_POOL"},
- {0x006, "NPU_OP_ELEMENTWISE"},
- {0x010, "NPU_OP_DMA_START"},
- {0x011, "NPU_OP_DMA_WAIT"},
- {0x012, "NPU_OP_KERNEL_WAIT"},
- {0x100, "NPU_SET_IFM_PAD_TOP"},
- {0x101, "NPU_SET_IFM_PAD_LEFT"},
- {0x102, "NPU_SET_IFM_PAD_RIGHT"},
- {0x103, "NPU_SET_IFM_PAD_BOTTOM"},
- {0x104, "NPU_SET_IFM_DEPTH_M1"},
- {0x105, "NPU_SET_IFM_PRECISION"},
- {0x107, "NPU_SET_IFM_UPSCALE"},
- {0x109, "NPU_SET_IFM_ZERO_POINT"},
- {0x10A, "NPU_SET_IFM_WIDTH0_M1"},
- {0x10B, "NPU_SET_IFM_HEIGHT0_M1"},
- {0x10C, "NPU_SET_IFM_HEIGHT1_M1"},
- {0x10D, "NPU_SET_IFM_IB_END"},
- {0x10F, "NPU_SET_IFM_REGION"},
- {0x110, "NPU_SET_OFM_BATCH_SIZE_M1"},
- {0x111, "NPU_SET_OFM_WIDTH_M1"},
- {0x112, "NPU_SET_OFM_HEIGHT_M1"},
- {0x113, "NPU_SET_OFM_DEPTH_M1"},
- {0x114, "NPU_SET_OFM_PRECISION"},
- {0x115, "NPU_SET_OFM_BLK_WIDTH_M1"},
- {0x116, "NPU_SET_OFM_BLK_HEIGHT_M1"},
- {0x117, "NPU_SET_OFM_BLK_DEPTH_M1"},
- {0x118, "NPU_SET_OFM_ZERO_POINT"},
- {0x11A, "NPU_SET_OFM_WIDTH0_M1"},
- {0x11B, "NPU_SET_OFM_HEIGHT0_M1"},
- {0x11C, "NPU_SET_OFM_HEIGHT1_M1"},
- {0x11F, "NPU_SET_OFM_REGION"},
- {0x120, "NPU_SET_KERNEL_WIDTH_M1"},
- {0x121, "NPU_SET_KERNEL_HEIGHT_M1"},
- {0x122, "NPU_SET_KERNEL_STRIDE"},
- {0x124, "NPU_SET_ACC_FORMAT"},
- {0x125, "NPU_SET_ACTIVATION"},
- {0x126, "NPU_SET_ACTIVATION_MIN"},
- {0x127, "NPU_SET_ACTIVATION_MAX"},
- {0x128, "NPU_SET_WEIGHT_REGION"},
- {0x129, "NPU_SET_SCALE_REGION"},
- {0x12D, "NPU_SET_AB_START"},
- {0x12F, "NPU_SET_BLOCKDEP"},
- {0x130, "NPU_SET_DMA0_SRC_REGION"},
- {0x131, "NPU_SET_DMA0_DST_REGION"},
- {0x180, "NPU_SET_IFM2_BROADCAST"},
- {0x181, "NPU_SET_IFM2_SCALAR"},
- {0x185, "NPU_SET_IFM2_PRECISION"},
- {0x189, "NPU_SET_IFM2_ZERO_POINT"},
- {0x18A, "NPU_SET_IFM2_WIDTH0_M1"},
- {0x18B, "NPU_SET_IFM2_HEIGHT0_M1"},
- {0x18C, "NPU_SET_IFM2_HEIGHT1_M1"},
- {0x18D, "NPU_SET_IFM2_IB_START"},
- {0x18F, "NPU_SET_IFM2_REGION"},
-};
+void ethosu_get_driver_version(struct ethosu_driver_version *ver)
+{
+ assert(ver != NULL);
+ ver->major = ETHOSU_DRIVER_VERSION_MAJOR;
+ ver->minor = ETHOSU_DRIVER_VERSION_MINOR;
+ ver->patch = ETHOSU_DRIVER_VERSION_PATCH;
+}
-static const name_lookup_t cmd1_name_tbl[] = {
- {0x000, "NPU_SET_IFM_BASE0"}, {0x001, "NPU_SET_IFM_BASE1"}, {0x002, "NPU_SET_IFM_BASE2"},
- {0x003, "NPU_SET_IFM_BASE3"}, {0x004, "NPU_SET_IFM_STRIDE_X"}, {0x005, "NPU_SET_IFM_STRIDE_Y"},
- {0x006, "NPU_SET_IFM_STRIDE_C"}, {0x007, "NPU_SET_IFM_STRIDE_N"}, {0x010, "NPU_SET_OFM_BASE0"},
- {0x011, "NPU_SET_OFM_BASE1"}, {0x012, "NPU_SET_OFM_BASE2"}, {0x013, "NPU_SET_OFM_BASE3"},
- {0x014, "NPU_SET_OFM_STRIDE_X"}, {0x015, "NPU_SET_OFM_STRIDE_Y"}, {0x016, "NPU_SET_OFM_STRIDE_C"},
- {0x017, "NPU_SET_OFM_STRIDE_N"}, {0x020, "NPU_SET_WEIGHT_BASE"}, {0x021, "NPU_SET_WEIGHT_LENGTH"},
- {0x022, "NPU_SET_SCALE_BASE"}, {0x023, "NPU_SET_SCALE_LENGTH"}, {0x024, "NPU_SET_OFM_SCALE"},
- {0x025, "NPU_SET_OPA_SCALE"}, {0x026, "NPU_SET_OPB_SCALE"}, {0x030, "NPU_SET_DMA0_SRC"},
- {0x031, "NPU_SET_DMA0_DST"}, {0x032, "NPU_SET_DMA0_LEN"}, {0x080, "NPU_SET_IFM2_BASE0"},
- {0x081, "NPU_SET_IFM2_BASE1"}, {0x082, "NPU_SET_IFM2_BASE2"}, {0x083, "NPU_SET_IFM2_BASE3"},
- {0x084, "NPU_SET_IFM2_STRIDE_X"}, {0x085, "NPU_SET_IFM2_STRIDE_Y"}, {0x086, "NPU_SET_IFM2_STRIDE_C"},
-};
+void ethosu_get_hw_info(struct ethosu_driver *drv, struct ethosu_hw_info *hw)
+{
+ assert(hw != NULL);
-static void dump_command_stream(const uint32_t *cmd_stream, const int cms_length, int qread)
+ (void)ethosu_dev_get_id(&drv->dev, &hw->version);
+ (void)ethosu_dev_get_config(&drv->dev, &hw->cfg);
+}
+
+int ethosu_invoke(struct ethosu_driver *drv,
+ const void *custom_data_ptr,
+ const int custom_data_size,
+ const uint64_t *base_addr,
+ const size_t *base_addr_size,
+ const int num_base_addr)
{
- int n;
- int offset;
- uint32_t cmd_val;
- const uint8_t *cmd_ptr;
- const char *cmd_name;
- int cmd0_name_tbl_count = sizeof(cmd0_name_tbl) / sizeof(cmd0_name_tbl[0]);
- int cmd1_name_tbl_count = sizeof(cmd1_name_tbl) / sizeof(cmd1_name_tbl[0]);
-
- LOG_INFO("dump_command_stream cmd_stream = 0x%8p cms_length = %d\n", cmd_stream, cms_length);
- for (n = 0; n < cms_length; n++)
+ const struct custom_data_s *data_ptr = custom_data_ptr;
+ const struct custom_data_s *data_end = custom_data_ptr + custom_data_size;
+ int return_code = 0;
+
+ // First word in custom_data_ptr should contain "Custom Operator Payload 1"
+ if (data_ptr->word != ETHOSU_FOURCC)
+ {
+ LOG_ERR("Custom Operator Payload: %" PRIu32 " is not correct, expected %x", data_ptr->word, ETHOSU_FOURCC);
+ return -1;
+ }
+
+ // Custom data length must be a multiple of 32 bits
+ if ((custom_data_size % BYTES_IN_32_BITS) != 0)
{
- // Offset
- offset = n * sizeof(int);
- LOG_INFO("[%.4d] ", offset);
- // Command
- cmd_ptr = (const uint8_t *)&cmd_stream[n];
- LOG_INFO("0x%.2X 0x%.2X 0x%.2X 0x%.2X ", cmd_ptr[0], cmd_ptr[1], cmd_ptr[2], cmd_ptr[3]);
- // Command name and payload
- if (cmd_stream[n] & 0x4000)
+ LOG_ERR("custom_data_size=0x%x not a multiple of 4", custom_data_size);
+ return -1;
+ }
+
+ ++data_ptr;
+
+ // Adjust base address to fast memory area
+ if (drv->fast_memory != 0 && num_base_addr >= FAST_MEMORY_BASE_ADDR_INDEX)
+ {
+ uint64_t *fast_memory = (uint64_t *)&base_addr[FAST_MEMORY_BASE_ADDR_INDEX];
+
+ if (base_addr_size != NULL && base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX] > drv->fast_memory_size)
{
- cmd_name = lookup_name(cmd1_name_tbl, cmd1_name_tbl_count, cmd_stream[n] & 0x3FF);
- n++;
- cmd_val = cmd_stream[n];
- cmd_ptr = (const uint8_t *)&cmd_stream[n];
- LOG_INFO("0x%.2X 0x%.2X 0x%.2X 0x%.2X ", cmd_ptr[0], cmd_ptr[1], cmd_ptr[2], cmd_ptr[3]);
+ LOG_ERR("Fast memory area too small. fast_memory_size=%u, base_addr_size=%u",
+ drv->fast_memory_size,
+ base_addr_size[FAST_MEMORY_BASE_ADDR_INDEX]);
+ return -1;
}
- else
+
+ *fast_memory = drv->fast_memory;
+ }
+
+ if (!drv->dev_power_always_on)
+ {
+ // Only soft reset if security state or privilege level needs changing
+ if (ethosu_dev_prot_has_changed(&drv->dev))
{
- cmd_val = cmd_stream[n] >> 16;
- cmd_name = lookup_name(cmd0_name_tbl, cmd0_name_tbl_count, cmd_stream[n] & 0x3FF);
+ if (ETHOSU_SUCCESS != ethosu_dev_soft_reset(&drv->dev))
+ {
+ return -1;
+ }
}
- if (cmd_name)
+
+ drv->status_error = false;
+ set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_DISABLE);
+ ethosu_dev_restore_pmu_config(&drv->dev);
+ npu_axi_init(drv);
+ }
+
+ drv->status_error = false;
+
+ ethosu_inference_begin(drv, custom_data_ptr);
+ while (data_ptr < data_end)
+ {
+ int ret = 0;
+ switch (data_ptr->driver_action_command)
{
- LOG_INFO("\t%s 0x%.8" PRIX32, cmd_name, cmd_val);
+ case OPTIMIZER_CONFIG:
+ LOG_DEBUG("OPTIMIZER_CONFIG");
+ struct opt_cfg_s *opt_cfg_p = (struct opt_cfg_s *)data_ptr;
+
+ ret = handle_optimizer_config(drv, opt_cfg_p);
+ data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + OPTIMIZER_CONFIG_LENGTH_32_BIT_WORD;
+ break;
+ case COMMAND_STREAM:
+ LOG_DEBUG("COMMAND_STREAM");
+ void *command_stream = (uint8_t *)(data_ptr) + sizeof(struct custom_data_s);
+ int cms_length = (data_ptr->reserved << 16) | data_ptr->length;
+
+ drv->abort_inference = false;
+ // It is safe to clear this flag without atomic, because npu is not running.
+ drv->irq_triggered = false;
+
+ ret = handle_command_stream(drv, command_stream, cms_length, base_addr, base_addr_size, num_base_addr);
+
+ if (return_code == -1 && drv->abort_inference)
+ {
+ LOG_ERR("NPU timeout. qread=%" PRIu32, ethosu_dev_get_qread(&drv->dev));
+ dump_shram(drv);
+ }
+
+ data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD + cms_length;
+ break;
+ case READ_APB_REG:
+ LOG_DEBUG("READ_APB_REG");
+ ret = read_apb_reg(drv, data_ptr->driver_action_data);
+ data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
+ break;
+ case DUMP_SHRAM:
+ LOG_DEBUG("DUMP_SHRAM");
+ ret = dump_shram(drv);
+ data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
+ break;
+ case NOP:
+ LOG_DEBUG("NOP");
+ data_ptr += DRIVER_ACTION_LENGTH_32_BIT_WORD;
+ break;
+ default:
+ LOG_ERR("UNSUPPORTED driver_action_command: %d ", data_ptr->driver_action_command);
+ ret = -1;
+ break;
}
- if (offset == qread)
+ if (ret != 0)
{
- LOG_INFO(" <<== QREAD\n");
+ return_code = -1;
+ break;
}
- else
+ }
+ ethosu_inference_end(drv, custom_data_ptr);
+
+ if (!drv->status_error && !drv->dev_power_always_on)
+ {
+ ethosu_dev_save_pmu_counters(&drv->dev);
+ set_clock_and_power_request(drv, ETHOSU_INFERENCE_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
+ }
+
+ return return_code;
+}
+
+void ethosu_abort(struct ethosu_driver *drv)
+{
+ drv->abort_inference = true;
+}
+
+void ethosu_set_power_mode(struct ethosu_driver *drv, bool always_on)
+{
+ drv->dev_power_always_on = always_on;
+
+ if (always_on)
+ {
+ npu_axi_init(drv);
+ }
+}
+
+struct ethosu_driver *ethosu_reserve_driver(void)
+{
+ struct ethosu_driver *drv = NULL;
+
+ do
+ {
+ ethosu_mutex_lock(ethosu_mutex);
+ drv = ethosu_find_and_reserve_driver();
+ ethosu_mutex_unlock(ethosu_mutex);
+
+ if (drv != NULL)
{
- LOG_INFO("\n");
+ break;
}
+
+ LOG_INFO("Waiting for NPU driver handle to become available...");
+ ethosu_semaphore_take(ethosu_semaphore);
+
+ } while (1);
+
+ return drv;
+}
+
+void ethosu_release_driver(struct ethosu_driver *drv)
+{
+ ethosu_mutex_lock(ethosu_mutex);
+ if (drv != NULL && drv->reserved)
+ {
+ drv->reserved = false;
+ LOG_DEBUG("NPU driver handle %p released", drv);
+ ethosu_semaphore_give(ethosu_semaphore);
+ }
+ ethosu_mutex_unlock(ethosu_mutex);
+}
+
+enum ethosu_error_codes set_clock_and_power_request(struct ethosu_driver *drv,
+ enum ethosu_request_clients client,
+ enum ethosu_clock_q_request clock_request,
+ enum ethosu_power_q_request power_request)
+{
+ // Set clock request bit for client
+ if (clock_request == ETHOSU_CLOCK_Q_DISABLE)
+ {
+ drv->clock_request |= (1 << client);
+ }
+ else
+ {
+ drv->clock_request &= ~(1 << client);
+ }
+ // Get current clock request (ENABLE if both PMU and INFERENCE asks for clock request, else DISABLE)
+ clock_request = drv->clock_request == 0 ? ETHOSU_CLOCK_Q_ENABLE : ETHOSU_CLOCK_Q_DISABLE;
+
+ // Set power request bit for client
+ if (power_request == ETHOSU_POWER_Q_DISABLE)
+ {
+ drv->power_request |= (1 << client);
}
+ else
+ {
+ drv->power_request &= ~(1 << client);
+ }
+ // Get current power request (ENABLE if both PMU and INFERENCE asks for power request, else DISABLE)
+ power_request = drv->power_request == 0 ? ETHOSU_POWER_Q_ENABLE : ETHOSU_POWER_Q_DISABLE;
+
+ // Set clock and power
+ enum ethosu_error_codes ret = ethosu_dev_set_clock_and_power(&drv->dev, clock_request, power_request);
+
+ return ret;
}
diff --git a/src/ethosu_pmu.c b/src/ethosu_pmu.c
index 5872d18..52aa393 100644
--- a/src/ethosu_pmu.c
+++ b/src/ethosu_pmu.c
@@ -91,7 +91,7 @@ void ETHOSU_PMU_Enable(struct ethosu_driver *drv)
pmcr.word = drv->dev.pmcr;
pmcr.cnt_en = 1;
set_clock_and_power_request(drv, ETHOSU_PMU_REQUEST, ETHOSU_CLOCK_Q_DISABLE, ETHOSU_POWER_Q_DISABLE);
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr);
}
void ETHOSU_PMU_Disable(struct ethosu_driver *drv)
@@ -101,7 +101,7 @@ void ETHOSU_PMU_Disable(struct ethosu_driver *drv)
pmcr.word = drv->dev.pmcr;
pmcr.cnt_en = 0;
set_clock_and_power_request(drv, ETHOSU_PMU_REQUEST, ETHOSU_CLOCK_Q_ENABLE, ETHOSU_POWER_Q_ENABLE);
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr);
}
void ETHOSU_PMU_Set_EVTYPER(struct ethosu_driver *drv, uint32_t num, enum ethosu_pmu_event_type type)
@@ -109,7 +109,7 @@ void ETHOSU_PMU_Set_EVTYPER(struct ethosu_driver *drv, uint32_t num, enum ethosu
assert(num < ETHOSU_PMU_NCOUNTERS);
uint32_t val = pmu_event_value(type);
LOG_DEBUG("%s: num=%u, type=%d, val=%u\n", __FUNCTION__, num, type, val);
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMEVTYPER(num), val, &drv->dev.pmu_evtypr[num]);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMEVTYPER(num), val, &drv->dev.pmu_evtypr[num]);
}
enum ethosu_pmu_event_type ETHOSU_PMU_Get_EVTYPER(struct ethosu_driver *drv, uint32_t num)
@@ -127,7 +127,7 @@ void ETHOSU_PMU_CYCCNT_Reset(struct ethosu_driver *drv)
struct pmcr_r pmcr;
pmcr.word = drv->dev.pmcr;
pmcr.cycle_cnt_rst = 1;
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr);
drv->dev.pmccntr[0] = 0;
drv->dev.pmccntr[1] = 0;
}
@@ -138,7 +138,7 @@ void ETHOSU_PMU_EVCNTR_ALL_Reset(struct ethosu_driver *drv)
struct pmcr_r pmcr;
pmcr.word = drv->dev.pmcr;
pmcr.event_cnt_rst = 1;
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCR, pmcr.word, &drv->dev.pmcr);
for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
{
@@ -149,13 +149,13 @@ void ETHOSU_PMU_EVCNTR_ALL_Reset(struct ethosu_driver *drv)
void ETHOSU_PMU_CNTR_Enable(struct ethosu_driver *drv, uint32_t mask)
{
LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCNTENSET, mask, &drv->dev.pmcnten);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCNTENSET, mask, &drv->dev.pmcnten);
}
void ETHOSU_PMU_CNTR_Disable(struct ethosu_driver *drv, uint32_t mask)
{
LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCNTENCLR, mask, &drv->dev.pmcnten);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCNTENCLR, mask, &drv->dev.pmcnten);
}
uint32_t ETHOSU_PMU_CNTR_Status(struct ethosu_driver *drv)
@@ -166,8 +166,8 @@ uint32_t ETHOSU_PMU_CNTR_Status(struct ethosu_driver *drv)
uint64_t ETHOSU_PMU_Get_CCNTR(struct ethosu_driver *drv)
{
- uint32_t val_lo = ethosu_read_reg(&drv->dev, NPU_REG_PMCCNTR_LO);
- uint32_t val_hi = ethosu_read_reg(&drv->dev, NPU_REG_PMCCNTR_HI);
+ uint32_t val_lo = ethosu_dev_read_reg(&drv->dev, NPU_REG_PMCCNTR_LO);
+ uint32_t val_hi = ethosu_dev_read_reg(&drv->dev, NPU_REG_PMCCNTR_HI);
uint64_t val = ((uint64_t)val_hi << 32) | val_lo;
uint64_t shadow = ((uint64_t)drv->dev.pmccntr[1] << 32) | drv->dev.pmccntr[0];
@@ -197,8 +197,8 @@ void ETHOSU_PMU_Set_CCNTR(struct ethosu_driver *drv, uint64_t val)
ETHOSU_PMU_CNTR_Disable(drv, ETHOSU_PMU_CCNT_Msk);
}
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_LO, val & MASK_0_31_BITS, &drv->dev.pmccntr[0]);
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32, &drv->dev.pmccntr[1]);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_LO, val & MASK_0_31_BITS, &drv->dev.pmccntr[0]);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32, &drv->dev.pmccntr[1]);
if (active)
{
@@ -209,7 +209,7 @@ void ETHOSU_PMU_Set_CCNTR(struct ethosu_driver *drv, uint64_t val)
uint32_t ETHOSU_PMU_Get_EVCNTR(struct ethosu_driver *drv, uint32_t num)
{
assert(num < ETHOSU_PMU_NCOUNTERS);
- uint32_t val = ethosu_read_reg(&drv->dev, NPU_REG_PMEVCNTR(num));
+ uint32_t val = ethosu_dev_read_reg(&drv->dev, NPU_REG_PMEVCNTR(num));
LOG_DEBUG("%s: num=%u, val=%u, shadow=%u\n", __FUNCTION__, num, val, drv->dev.pmu_evcntr[num]);
// Return the shadow variable in case the NPU was powered off and lost the event count
@@ -228,31 +228,31 @@ void ETHOSU_PMU_Set_EVCNTR(struct ethosu_driver *drv, uint32_t num, uint32_t val
{
assert(num < ETHOSU_PMU_NCOUNTERS);
LOG_DEBUG("%s: num=%u, val=%u\n", __FUNCTION__, num, val);
- ethosu_write_reg(&drv->dev, NPU_REG_PMEVCNTR(num), val);
+ ethosu_dev_write_reg(&drv->dev, NPU_REG_PMEVCNTR(num), val);
}
uint32_t ETHOSU_PMU_Get_CNTR_OVS(struct ethosu_driver *drv)
{
LOG_DEBUG("%s:\n", __FUNCTION__);
- return ethosu_read_reg(&drv->dev, NPU_REG_PMOVSSET);
+ return ethosu_dev_read_reg(&drv->dev, NPU_REG_PMOVSSET);
}
void ETHOSU_PMU_Set_CNTR_OVS(struct ethosu_driver *drv, uint32_t mask)
{
LOG_DEBUG("%s:\n", __FUNCTION__);
- ethosu_write_reg(&drv->dev, NPU_REG_PMOVSCLR, mask);
+ ethosu_dev_write_reg(&drv->dev, NPU_REG_PMOVSCLR, mask);
}
void ETHOSU_PMU_Set_CNTR_IRQ_Enable(struct ethosu_driver *drv, uint32_t mask)
{
LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMINTSET, mask, &drv->dev.pmint);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMINTSET, mask, &drv->dev.pmint);
}
void ETHOSU_PMU_Set_CNTR_IRQ_Disable(struct ethosu_driver *drv, uint32_t mask)
{
LOG_DEBUG("%s: mask=0x%08x\n", __FUNCTION__, mask);
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMINTCLR, mask, &drv->dev.pmint);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMINTCLR, mask, &drv->dev.pmint);
}
uint32_t ETHOSU_PMU_Get_IRQ_Enable(struct ethosu_driver *drv)
@@ -273,8 +273,8 @@ void ETHOSU_PMU_CNTR_Increment(struct ethosu_driver *drv, uint32_t mask)
if (mask & ETHOSU_PMU_CCNT_Msk)
{
uint64_t val = ETHOSU_PMU_Get_CCNTR(drv) + 1;
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_LO, val & MASK_0_31_BITS, &drv->dev.pmccntr[0]);
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32, &drv->dev.pmccntr[1]);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_LO, val & MASK_0_31_BITS, &drv->dev.pmccntr[0]);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_HI, (val & MASK_32_47_BITS) >> 32, &drv->dev.pmccntr[1]);
}
for (int i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
@@ -282,7 +282,7 @@ void ETHOSU_PMU_CNTR_Increment(struct ethosu_driver *drv, uint32_t mask)
if (mask & (1 << i))
{
uint32_t val = ETHOSU_PMU_Get_EVCNTR(drv, i);
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMEVCNTR(i), val + 1, &drv->dev.pmu_evcntr[i]);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMEVCNTR(i), val + 1, &drv->dev.pmu_evcntr[i]);
}
}
@@ -297,7 +297,7 @@ void ETHOSU_PMU_PMCCNTR_CFG_Set_Start_Event(struct ethosu_driver *drv, enum etho
struct pmccntr_cfg_r cfg;
cfg.word = drv->dev.pmccntr_cfg;
cfg.CYCLE_CNT_CFG_START = val;
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_CFG, cfg.word, &drv->dev.pmccntr_cfg);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_CFG, cfg.word, &drv->dev.pmccntr_cfg);
}
void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(struct ethosu_driver *drv, enum ethosu_pmu_event_type stop_event)
@@ -307,5 +307,5 @@ void ETHOSU_PMU_PMCCNTR_CFG_Set_Stop_Event(struct ethosu_driver *drv, enum ethos
struct pmccntr_cfg_r cfg;
cfg.word = drv->dev.pmccntr_cfg;
cfg.CYCLE_CNT_CFG_STOP = val;
- ethosu_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_CFG, cfg.word, &drv->dev.pmccntr_cfg);
+ ethosu_dev_write_reg_shadow(&drv->dev, NPU_REG_PMCCNTR_CFG, cfg.word, &drv->dev.pmccntr_cfg);
}