diff options
Diffstat (limited to 'source/application/hal/hal.c')
-rw-r--r-- | source/application/hal/hal.c | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/source/application/hal/hal.c b/source/application/hal/hal.c new file mode 100644 index 0000000..dbf94ba --- /dev/null +++ b/source/application/hal/hal.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 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 + * + * http://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 "hal.h" /* API */ + +#include "hal_config.h" /* HAL configuration */ +#include "system_init.h" + +#include <stdio.h> +#include <assert.h> + +#if defined(ARM_NPU) + +#include "ethosu_driver.h" /* Arm Ethos-U55 driver header */ +#include "timing_adapter.h" /* Arm Ethos-U55 timing adapter driver header */ +#include "timing_adapter_settings.h" /* Arm Ethos-U55 timing adapter settings */ + +/** + * @brief Initialises the Arm Ethos-U55 NPU + * @return 0 if successful, error code otherwise + **/ +static int _arm_npu_init(void); + +#endif /* ARM_NPU */ + +int hal_init(hal_platform* platform, data_acq_module* data_acq, + data_psn_module* data_psn, platform_timer* timer) +{ + assert(platform && data_acq && data_psn); + + platform->data_acq = data_acq; + platform->data_psn = data_psn; + platform->timer = timer; + platform->platform_init = system_init; + platform->platform_release = system_release; + system_name(platform->plat_name, sizeof(platform->plat_name)); + + return 0; +} + +/** + * @brief Local helper function to clean the slate for current platform. + **/ +static void _hal_platform_clear(hal_platform* platform) +{ + assert(platform); + platform->inited = 0; +} + +int hal_platform_init(hal_platform* platform) +{ + int state; + assert(platform && platform->platform_init); + _hal_platform_clear(platform); + + /* Initialise platform */ + if (0 != (state = platform->platform_init())) { + printf_err("failed to initialise platform %s\n", platform->plat_name); + return state; + } + + /* Initialise the data acquisition module */ + if (0 != (state = data_acq_channel_init(platform->data_acq))) { + if (!platform->data_acq->inited) { + printf_err("failed to initialise data acq module: %s\n", + platform->data_acq->system_name); + } + hal_platform_release(platform); + return state; + } + + /* Initialise the presentation module */ + if (0 != (state = data_psn_system_init(platform->data_psn))) { + printf_err("failed to initialise data psn module: %s\n", + platform->data_psn->system_name); + data_acq_channel_release(platform->data_acq); + hal_platform_release(platform); + return state; + } + +#if defined(ARM_NPU) + + /* If Arm Ethos-U55 NPU is to be used, we initialise it here */ + if (0 != (state = _arm_npu_init())) { + return state; + } + +#endif /* ARM_NPU */ + + /* followed by the timer module */ + init_timer(platform->timer); + + info("%s platform initialised\n", platform->plat_name); + debug("using %s module for data acquisition\n", + platform->data_acq->system_name); + debug("using %s module for data presentation\n", + platform->data_psn->system_name); + + platform->inited = !state; + + return state; +} + +void hal_platform_release(hal_platform *platform) +{ + assert(platform && platform->platform_release); + data_acq_channel_release(platform->data_acq); + data_psn_system_release(platform->data_psn); + + _hal_platform_clear(platform); + info("releasing platform %s\n", platform->plat_name); + platform->platform_release(); +} + +#if defined(ARM_NPU) +/** + * @brief Defines the Ethos-U interrupt handler: just a wrapper around the default + * implementation. + **/ +static void _arm_npu_irq_handler(void) +{ + /* Call the default interrupt handler from the NPU driver */ + ethosu_irq_handler(); +} + +/** + * @brief Initialises the NPU IRQ + **/ +static void _arm_npu_irq_init(void) +{ + const IRQn_Type ethosu_irqnum = (IRQn_Type)EthosU_IRQn; + + /* Register the EthosU IRQ handler in our vector table. + * Note, this handler comes from the EthosU driver */ + NVIC_SetVector(ethosu_irqnum, (uint32_t)_arm_npu_irq_handler); + + /* Enable the IRQ */ + NVIC_EnableIRQ(ethosu_irqnum); + + debug("EthosU IRQ#: %u, Handler: 0x%p\n", + ethosu_irqnum, _arm_npu_irq_handler); +} + +static int _arm_npu_timing_adapter_init(void) +{ +#if defined (TA0_BASE) + struct timing_adapter ta_0; + struct timing_adapter_settings ta_0_settings = { + .maxr = TA0_MAXR, + .maxw = TA0_MAXW, + .maxrw = TA0_MAXRW, + .rlatency = TA0_RLATENCY, + .wlatency = TA0_WLATENCY, + .pulse_on = TA0_PULSE_ON, + .pulse_off = TA0_PULSE_OFF, + .bwcap = TA0_BWCAP, + .perfctrl = TA0_PERFCTRL, + .perfcnt = TA0_PERFCNT, + .mode = TA0_MODE, + .maxpending = 0, /* This is a read-only parameter */ + .histbin = TA0_HISTBIN, + .histcnt = TA0_HISTCNT + }; + + if (0 != ta_init(&ta_0, TA0_BASE)) { + printf_err("TA0 initialisation failed\n"); + return 1; + } + + ta_set_all(&ta_0, &ta_0_settings); +#endif /* defined (TA0_BASE) */ + +#if defined (TA1_BASE) + struct timing_adapter ta_1; + struct timing_adapter_settings ta_1_settings = { + .maxr = TA1_MAXR, + .maxw = TA1_MAXW, + .maxrw = TA1_MAXRW, + .rlatency = TA1_RLATENCY, + .wlatency = TA1_WLATENCY, + .pulse_on = TA1_PULSE_ON, + .pulse_off = TA1_PULSE_OFF, + .bwcap = TA1_BWCAP, + .perfctrl = TA1_PERFCTRL, + .perfcnt = TA1_PERFCNT, + .mode = TA1_MODE, + .maxpending = 0, /* This is a read-only parameter */ + .histbin = TA1_HISTBIN, + .histcnt = TA1_HISTCNT + }; + + if (0 != ta_init(&ta_1, TA1_BASE)) { + printf_err("TA1 initialisation failed\n"); + return 1; + } + + ta_set_all(&ta_1, &ta_1_settings); +#endif /* defined (TA1_BASE) */ + + return 0; +} + +static int _arm_npu_init(void) +{ + int err = 0; + + /* If the platform has timing adapter blocks along with Ethos-U55 core + * block, initialise them here. */ + if (0 != (err = _arm_npu_timing_adapter_init())) { + return err; + } + + /* Initialise the IRQ */ + _arm_npu_irq_init(); + + /* Initialise Ethos-U55 device */ + const void * ethosu_base_address = (void *)(SEC_ETHOS_U55_BASE); + + if (0 != (err = ethosu_init_v3( + ethosu_base_address, /* Ethos-U55's base address. */ + NULL, /* Pointer to fast mem area - NULL for U55. */ + 0, /* Fast mem region size. */ + 1, /* Security enable. */ + 1))) { /* Privilege enable. */ + printf_err("failed to initalise Ethos-U55 device\n"); + return err; + } + + info("Ethos-U55 device initialised\n"); + + /* Get Ethos-U55 version */ + struct ethosu_version version; + if (0 != (err = ethosu_get_version(&version))) { + printf_err("failed to fetch Ethos-U55 version info\n"); + return err; + } + + info("Ethos-U55 version info:\n"); + info("\tArch: v%u.%u.%u\n", version.id.arch_major_rev, + version.id.arch_minor_rev, + version.id.arch_patch_rev); + info("\tDriver: v%u.%u.%u\n", version.id.driver_major_rev, + version.id.driver_minor_rev, + version.id.driver_patch_rev); + info("\tMACs/cc: %u\n", (1 << version.cfg.macs_per_cc)); + info("\tCmd stream: v%u\n", version.cfg.cmd_stream_version); + info("\tSHRAM size: %u\n", version.cfg.shram_size); + + return 0; +} +#endif /* ARM_NPU */ |