mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-21 03:54:34 +00:00
feat(ethos-n)!: add support for SMMU streams
The Arm(R) Ethos(TM)-N NPU driver now supports configuring the SMMU streams that the NPU shall use and will therefore no longer delegate access to these registers to the non-secure world. In order for the driver to support this, the device tree parsing has been updated to support parsing the allocators used by the NPU and what SMMU stream that is associated with each allocator. To keep track of what NPU device each allocator is associated with, the resulting config from the device tree parsing will now group the NPU cores and allocators into their respective NPU device. The SMC API has been changed to allow the caller to specify what allocator the NPU shall be configured to use and the API version has been bumped to indicate this change. Signed-off-by: Mikael Olsson <mikael.olsson@arm.com> Change-Id: I6ac43819133138614e3f55a014e93466fe3d5277
This commit is contained in:
parent
aa9d315009
commit
b139f1cf97
8 changed files with 475 additions and 107 deletions
|
@ -92,7 +92,7 @@ Arm Platform Build Options
|
||||||
SBROM library must be specified via ``CCSBROM_LIB_PATH`` flag.
|
SBROM library must be specified via ``CCSBROM_LIB_PATH`` flag.
|
||||||
|
|
||||||
- ``ARM_ETHOSN_NPU_DRIVER``: boolean option to enable a SiP service that can
|
- ``ARM_ETHOSN_NPU_DRIVER``: boolean option to enable a SiP service that can
|
||||||
configure an Arm Ethos-N NPU. To use this service the target platform's
|
configure an Arm® Ethos™-N NPU. To use this service the target platform's
|
||||||
``HW_CONFIG`` must include the device tree nodes for the NPU. Currently, only
|
``HW_CONFIG`` must include the device tree nodes for the NPU. Currently, only
|
||||||
the Arm Juno platform has this included in its ``HW_CONFIG`` and the platform
|
the Arm Juno platform has this included in its ``HW_CONFIG`` and the platform
|
||||||
only loads the ``HW_CONFIG`` in AArch64 builds. Default is 0.
|
only loads the ``HW_CONFIG`` in AArch64 builds. Default is 0.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Arm Limited. All rights reserved.
|
* Copyright (c) 2021-2022, Arm Limited. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -12,18 +12,17 @@
|
||||||
#include <drivers/arm/ethosn.h>
|
#include <drivers/arm/ethosn.h>
|
||||||
#include <drivers/delay_timer.h>
|
#include <drivers/delay_timer.h>
|
||||||
#include <lib/mmio.h>
|
#include <lib/mmio.h>
|
||||||
|
#include <lib/utils_def.h>
|
||||||
#include <plat/arm/common/fconf_ethosn_getter.h>
|
#include <plat/arm/common/fconf_ethosn_getter.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of Arm Ethos-N NPU (NPU) cores available for a
|
* Number of Arm(R) Ethos(TM)-N NPU (NPU) devices available
|
||||||
* particular parent device
|
|
||||||
*/
|
*/
|
||||||
#define ETHOSN_NUM_CORES \
|
#define ETHOSN_NUM_DEVICES \
|
||||||
FCONF_GET_PROPERTY(hw_config, ethosn_config, num_cores)
|
FCONF_GET_PROPERTY(hw_config, ethosn_config, num_devices)
|
||||||
|
|
||||||
/* Address to an NPU core */
|
#define ETHOSN_GET_DEVICE(dev_idx) \
|
||||||
#define ETHOSN_CORE_ADDR(core_idx) \
|
FCONF_GET_PROPERTY(hw_config, ethosn_device, dev_idx)
|
||||||
FCONF_GET_PROPERTY(hw_config, ethosn_core_addr, core_idx)
|
|
||||||
|
|
||||||
/* NPU core sec registry address */
|
/* NPU core sec registry address */
|
||||||
#define ETHOSN_CORE_SEC_REG(core_addr, reg_offset) \
|
#define ETHOSN_CORE_SEC_REG(core_addr, reg_offset) \
|
||||||
|
@ -40,9 +39,6 @@
|
||||||
#define SEC_SECCTLR_REG U(0x0010)
|
#define SEC_SECCTLR_REG U(0x0010)
|
||||||
#define SEC_SECCTLR_VAL U(0x3)
|
#define SEC_SECCTLR_VAL U(0x3)
|
||||||
|
|
||||||
#define SEC_DEL_MMUSID_REG U(0x2008)
|
|
||||||
#define SEC_DEL_MMUSID_VAL U(0x3FFFF)
|
|
||||||
|
|
||||||
#define SEC_DEL_ADDR_EXT_REG U(0x201C)
|
#define SEC_DEL_ADDR_EXT_REG U(0x201C)
|
||||||
#define SEC_DEL_ADDR_EXT_VAL U(0x15)
|
#define SEC_DEL_ADDR_EXT_VAL U(0x15)
|
||||||
|
|
||||||
|
@ -50,17 +46,63 @@
|
||||||
#define SEC_SYSCTRL0_SOFT_RESET U(3U << 29)
|
#define SEC_SYSCTRL0_SOFT_RESET U(3U << 29)
|
||||||
#define SEC_SYSCTRL0_HARD_RESET U(1U << 31)
|
#define SEC_SYSCTRL0_HARD_RESET U(1U << 31)
|
||||||
|
|
||||||
static bool ethosn_is_core_addr_valid(uintptr_t core_addr)
|
#define SEC_MMUSID_REG_BASE U(0x3008)
|
||||||
|
#define SEC_MMUSID_OFFSET U(0x1000)
|
||||||
|
|
||||||
|
static bool ethosn_get_device_and_core(uintptr_t core_addr,
|
||||||
|
const struct ethosn_device_t **dev_match,
|
||||||
|
const struct ethosn_core_t **core_match)
|
||||||
{
|
{
|
||||||
for (uint32_t core_idx = 0U; core_idx < ETHOSN_NUM_CORES; core_idx++) {
|
uint32_t dev_idx;
|
||||||
if (ETHOSN_CORE_ADDR(core_idx) == core_addr) {
|
uint32_t core_idx;
|
||||||
|
|
||||||
|
for (dev_idx = 0U; dev_idx < ETHOSN_NUM_DEVICES; ++dev_idx) {
|
||||||
|
const struct ethosn_device_t *dev = ETHOSN_GET_DEVICE(dev_idx);
|
||||||
|
|
||||||
|
for (core_idx = 0U; core_idx < dev->num_cores; ++core_idx) {
|
||||||
|
const struct ethosn_core_t *core = &(dev->cores[core_idx]);
|
||||||
|
|
||||||
|
if (core->addr == core_addr) {
|
||||||
|
*dev_match = dev;
|
||||||
|
*core_match = core;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN("ETHOSN: Unknown core address given to SMC call.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ethosn_configure_smmu_streams(const struct ethosn_device_t *device,
|
||||||
|
const struct ethosn_core_t *core,
|
||||||
|
uint32_t asset_alloc_idx)
|
||||||
|
{
|
||||||
|
const struct ethosn_main_allocator_t *main_alloc =
|
||||||
|
&(core->main_allocator);
|
||||||
|
const struct ethosn_asset_allocator_t *asset_alloc =
|
||||||
|
&(device->asset_allocators[asset_alloc_idx]);
|
||||||
|
const uint32_t streams[9] = {
|
||||||
|
main_alloc->firmware.stream_id,
|
||||||
|
main_alloc->working_data.stream_id,
|
||||||
|
asset_alloc->command_stream.stream_id,
|
||||||
|
0U, /* Not used*/
|
||||||
|
main_alloc->firmware.stream_id,
|
||||||
|
asset_alloc->weight_data.stream_id,
|
||||||
|
asset_alloc->buffer_data.stream_id,
|
||||||
|
asset_alloc->intermediate_data.stream_id,
|
||||||
|
asset_alloc->buffer_data.stream_id
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0U; i < ARRAY_SIZE(streams); ++i) {
|
||||||
|
const uintptr_t reg_addr = SEC_MMUSID_REG_BASE +
|
||||||
|
(SEC_MMUSID_OFFSET * i);
|
||||||
|
mmio_write_32(ETHOSN_CORE_SEC_REG(core->addr, reg_addr),
|
||||||
|
streams[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ethosn_delegate_to_ns(uintptr_t core_addr)
|
static void ethosn_delegate_to_ns(uintptr_t core_addr)
|
||||||
{
|
{
|
||||||
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SECCTLR_REG),
|
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SECCTLR_REG),
|
||||||
|
@ -69,9 +111,6 @@ static void ethosn_delegate_to_ns(uintptr_t core_addr)
|
||||||
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG),
|
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG),
|
||||||
SEC_DEL_VAL);
|
SEC_DEL_VAL);
|
||||||
|
|
||||||
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_MMUSID_REG),
|
|
||||||
SEC_DEL_MMUSID_VAL);
|
|
||||||
|
|
||||||
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_ADDR_EXT_REG),
|
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_ADDR_EXT_REG),
|
||||||
SEC_DEL_ADDR_EXT_VAL);
|
SEC_DEL_ADDR_EXT_VAL);
|
||||||
}
|
}
|
||||||
|
@ -112,7 +151,7 @@ static bool ethosn_reset(uintptr_t core_addr, int hard_reset)
|
||||||
|
|
||||||
uintptr_t ethosn_smc_handler(uint32_t smc_fid,
|
uintptr_t ethosn_smc_handler(uint32_t smc_fid,
|
||||||
u_register_t core_addr,
|
u_register_t core_addr,
|
||||||
u_register_t x2,
|
u_register_t asset_alloc_idx,
|
||||||
u_register_t x3,
|
u_register_t x3,
|
||||||
u_register_t x4,
|
u_register_t x4,
|
||||||
void *cookie,
|
void *cookie,
|
||||||
|
@ -120,6 +159,8 @@ uintptr_t ethosn_smc_handler(uint32_t smc_fid,
|
||||||
u_register_t flags)
|
u_register_t flags)
|
||||||
{
|
{
|
||||||
int hard_reset = 0;
|
int hard_reset = 0;
|
||||||
|
const struct ethosn_device_t *device = NULL;
|
||||||
|
const struct ethosn_core_t *core = NULL;
|
||||||
const uint32_t fid = smc_fid & FUNCID_NUM_MASK;
|
const uint32_t fid = smc_fid & FUNCID_NUM_MASK;
|
||||||
|
|
||||||
/* Only SiP fast calls are expected */
|
/* Only SiP fast calls are expected */
|
||||||
|
@ -131,12 +172,14 @@ uintptr_t ethosn_smc_handler(uint32_t smc_fid,
|
||||||
/* Truncate parameters to 32-bits for SMC32 */
|
/* Truncate parameters to 32-bits for SMC32 */
|
||||||
if (GET_SMC_CC(smc_fid) == SMC_32) {
|
if (GET_SMC_CC(smc_fid) == SMC_32) {
|
||||||
core_addr &= 0xFFFFFFFF;
|
core_addr &= 0xFFFFFFFF;
|
||||||
x2 &= 0xFFFFFFFF;
|
asset_alloc_idx &= 0xFFFFFFFF;
|
||||||
x3 &= 0xFFFFFFFF;
|
x3 &= 0xFFFFFFFF;
|
||||||
x4 &= 0xFFFFFFFF;
|
x4 &= 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_ethosn_fid(smc_fid)) {
|
if (!is_ethosn_fid(smc_fid) ||
|
||||||
|
(fid < ETHOSN_FNUM_VERSION || fid > ETHOSN_FNUM_SOFT_RESET)) {
|
||||||
|
WARN("ETHOSN: Unknown SMC call: 0x%x\n", smc_fid);
|
||||||
SMC_RET1(handle, SMC_UNK);
|
SMC_RET1(handle, SMC_UNK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,25 +189,41 @@ uintptr_t ethosn_smc_handler(uint32_t smc_fid,
|
||||||
SMC_RET2(handle, ETHOSN_VERSION_MAJOR, ETHOSN_VERSION_MINOR);
|
SMC_RET2(handle, ETHOSN_VERSION_MAJOR, ETHOSN_VERSION_MINOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ethosn_is_core_addr_valid(core_addr)) {
|
if (!ethosn_get_device_and_core(core_addr, &device, &core)) {
|
||||||
WARN("ETHOSN: Unknown core address given to SMC call.\n");
|
|
||||||
SMC_RET1(handle, ETHOSN_UNKNOWN_CORE_ADDRESS);
|
SMC_RET1(handle, ETHOSN_UNKNOWN_CORE_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Commands that require a valid addr */
|
/* Commands that require a valid core address */
|
||||||
switch (fid) {
|
switch (fid) {
|
||||||
case ETHOSN_FNUM_IS_SEC:
|
case ETHOSN_FNUM_IS_SEC:
|
||||||
SMC_RET1(handle, ethosn_is_sec(core_addr));
|
SMC_RET1(handle, ethosn_is_sec(core->addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!device->has_reserved_memory &&
|
||||||
|
asset_alloc_idx >= device->num_allocators) {
|
||||||
|
WARN("ETHOSN: Unknown asset allocator index given to SMC call.\n");
|
||||||
|
SMC_RET1(handle, ETHOSN_UNKNOWN_ALLOCATOR_IDX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Commands that require a valid device, core and asset allocator */
|
||||||
|
switch (fid) {
|
||||||
case ETHOSN_FNUM_HARD_RESET:
|
case ETHOSN_FNUM_HARD_RESET:
|
||||||
hard_reset = 1;
|
hard_reset = 1;
|
||||||
/* Fallthrough */
|
/* Fallthrough */
|
||||||
case ETHOSN_FNUM_SOFT_RESET:
|
case ETHOSN_FNUM_SOFT_RESET:
|
||||||
if (!ethosn_reset(core_addr, hard_reset)) {
|
if (!ethosn_reset(core->addr, hard_reset)) {
|
||||||
SMC_RET1(handle, ETHOSN_FAILURE);
|
SMC_RET1(handle, ETHOSN_FAILURE);
|
||||||
}
|
}
|
||||||
ethosn_delegate_to_ns(core_addr);
|
|
||||||
|
if (!device->has_reserved_memory) {
|
||||||
|
ethosn_configure_smmu_streams(device, core,
|
||||||
|
asset_alloc_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
ethosn_delegate_to_ns(core->addr);
|
||||||
SMC_RET1(handle, ETHOSN_SUCCESS);
|
SMC_RET1(handle, ETHOSN_SUCCESS);
|
||||||
default:
|
default:
|
||||||
|
WARN("ETHOSN: Unimplemented SMC call: 0x%x\n", fid);
|
||||||
SMC_RET1(handle, SMC_UNK);
|
SMC_RET1(handle, SMC_UNK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Arm Limited. All rights reserved.
|
* Copyright (c) 2021-2022, Arm Limited. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For examples of multi-core and multi-device NPU, refer to the examples given in the
|
* This device tree is only an example and some properties have been omitted.
|
||||||
* Arm Ethos-N NPU driver stack.
|
*
|
||||||
|
* Refer to the Arm(R) Ethos(TM)-N driver stack for complete device tree examples.
|
||||||
* https://github.com/ARM-software/ethos-n-driver-stack
|
* https://github.com/ARM-software/ethos-n-driver-stack
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -14,6 +15,14 @@
|
||||||
#address-cells = <2>;
|
#address-cells = <2>;
|
||||||
#size-cells = <2>;
|
#size-cells = <2>;
|
||||||
|
|
||||||
|
smmu_ethosn0: iommu@6f400000 {
|
||||||
|
compatible = "arm,smmu-v3";
|
||||||
|
reg = <0 0x6f400000 0 0x80000>;
|
||||||
|
status = "okay";
|
||||||
|
/* msi-parent omitted */
|
||||||
|
#iommu-cells = <0x1>;
|
||||||
|
};
|
||||||
|
|
||||||
ethosn0: ethosn@6f300000 {
|
ethosn0: ethosn@6f300000 {
|
||||||
compatible = "ethosn";
|
compatible = "ethosn";
|
||||||
reg = <0 0x6f300000 0 0x00100000>;
|
reg = <0 0x6f300000 0 0x00100000>;
|
||||||
|
@ -22,6 +31,46 @@
|
||||||
core0 {
|
core0 {
|
||||||
compatible = "ethosn-core";
|
compatible = "ethosn-core";
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
||||||
|
main_allocator {
|
||||||
|
compatible = "ethosn-main_allocator";
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
firmware {
|
||||||
|
compatible = "ethosn-memory";
|
||||||
|
iommus = <&smmu_ethosn0 0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
working_data {
|
||||||
|
compatible = "ethosn-memory";
|
||||||
|
iommus = <&smmu_ethosn0 1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
asset_allocator {
|
||||||
|
compatible = "ethosn-asset_allocator";
|
||||||
|
status = "okay";
|
||||||
|
|
||||||
|
command_stream {
|
||||||
|
compatible = "ethosn-memory";
|
||||||
|
iommus = <&smmu_ethosn0 2>;
|
||||||
|
};
|
||||||
|
|
||||||
|
weight_data {
|
||||||
|
compatible = "ethosn-memory";
|
||||||
|
iommus = <&smmu_ethosn0 3>;
|
||||||
|
};
|
||||||
|
|
||||||
|
buffer_data {
|
||||||
|
compatible = "ethosn-memory";
|
||||||
|
iommus = <&smmu_ethosn0 4>;
|
||||||
|
};
|
||||||
|
|
||||||
|
intermediate_data {
|
||||||
|
compatible = "ethosn-memory";
|
||||||
|
iommus = <&smmu_ethosn0 5>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Arm Limited. All rights reserved.
|
* Copyright (c) 2021-2022, Arm Limited. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
#define is_ethosn_fid(_fid) (((_fid) & ETHOSN_FID_MASK) == ETHOSN_FID_VALUE)
|
#define is_ethosn_fid(_fid) (((_fid) & ETHOSN_FID_MASK) == ETHOSN_FID_VALUE)
|
||||||
|
|
||||||
/* Service version */
|
/* Service version */
|
||||||
#define ETHOSN_VERSION_MAJOR U(1)
|
#define ETHOSN_VERSION_MAJOR U(2)
|
||||||
#define ETHOSN_VERSION_MINOR U(0)
|
#define ETHOSN_VERSION_MINOR U(0)
|
||||||
|
|
||||||
/* Return codes for function calls */
|
/* Return codes for function calls */
|
||||||
|
@ -48,10 +48,11 @@
|
||||||
/* -3 Reserved for INVALID_PARAMETER */
|
/* -3 Reserved for INVALID_PARAMETER */
|
||||||
#define ETHOSN_FAILURE -4
|
#define ETHOSN_FAILURE -4
|
||||||
#define ETHOSN_UNKNOWN_CORE_ADDRESS -5
|
#define ETHOSN_UNKNOWN_CORE_ADDRESS -5
|
||||||
|
#define ETHOSN_UNKNOWN_ALLOCATOR_IDX -6
|
||||||
|
|
||||||
uintptr_t ethosn_smc_handler(uint32_t smc_fid,
|
uintptr_t ethosn_smc_handler(uint32_t smc_fid,
|
||||||
u_register_t core_addr,
|
u_register_t core_addr,
|
||||||
u_register_t x2,
|
u_register_t asset_alloc_idx,
|
||||||
u_register_t x3,
|
u_register_t x3,
|
||||||
u_register_t x4,
|
u_register_t x4,
|
||||||
void *cookie,
|
void *cookie,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016-2019,2021, ARM Limited and Contributors. All rights reserved.
|
* Copyright (c) 2016-2019,2021-2022, ARM Limited and Contributors. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
/* DEBUGFS_SMC_64 0xC2000030U */
|
/* DEBUGFS_SMC_64 0xC2000030U */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Arm Ethos-N NPU SiP SMC function IDs
|
* Arm(R) Ethos(TM)-N NPU SiP SMC function IDs
|
||||||
* 0xC2000050-0xC200005F
|
* 0xC2000050-0xC200005F
|
||||||
* 0x82000050-0x8200005F
|
* 0x82000050-0x8200005F
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Arm Limited. All rights reserved.
|
* Copyright (c) 2021-2022, Arm Limited. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -8,27 +8,52 @@
|
||||||
#define FCONF_ETHOSN_GETTER_H
|
#define FCONF_ETHOSN_GETTER_H
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <lib/fconf/fconf.h>
|
#include <lib/fconf/fconf.h>
|
||||||
|
|
||||||
#define hw_config__ethosn_config_getter(prop) ethosn_config.prop
|
#define hw_config__ethosn_config_getter(prop) ethosn_config.prop
|
||||||
#define hw_config__ethosn_core_addr_getter(idx) __extension__ ({ \
|
#define hw_config__ethosn_device_getter(dev_idx) __extension__ ({ \
|
||||||
assert(idx < ethosn_config.num_cores); \
|
assert(dev_idx < ethosn_config.num_devices); \
|
||||||
ethosn_config.core[idx].addr; \
|
ðosn_config.devices[dev_idx]; \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define ETHOSN_STATUS_DISABLED U(0)
|
#define ETHOSN_DEV_NUM_MAX U(2)
|
||||||
#define ETHOSN_STATUS_ENABLED U(1)
|
#define ETHOSN_DEV_CORE_NUM_MAX U(8)
|
||||||
|
#define ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX U(16)
|
||||||
|
|
||||||
#define ETHOSN_CORE_NUM_MAX U(64)
|
struct ethosn_allocator_t {
|
||||||
|
uint32_t stream_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ethosn_main_allocator_t {
|
||||||
|
struct ethosn_allocator_t firmware;
|
||||||
|
struct ethosn_allocator_t working_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ethosn_asset_allocator_t {
|
||||||
|
struct ethosn_allocator_t command_stream;
|
||||||
|
struct ethosn_allocator_t weight_data;
|
||||||
|
struct ethosn_allocator_t buffer_data;
|
||||||
|
struct ethosn_allocator_t intermediate_data;
|
||||||
|
};
|
||||||
|
|
||||||
struct ethosn_core_t {
|
struct ethosn_core_t {
|
||||||
uint64_t addr;
|
uint64_t addr;
|
||||||
|
struct ethosn_main_allocator_t main_allocator;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ethosn_device_t {
|
||||||
|
bool has_reserved_memory;
|
||||||
|
uint32_t num_cores;
|
||||||
|
struct ethosn_core_t cores[ETHOSN_DEV_CORE_NUM_MAX];
|
||||||
|
uint32_t num_allocators;
|
||||||
|
struct ethosn_asset_allocator_t asset_allocators[ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ethosn_config_t {
|
struct ethosn_config_t {
|
||||||
uint32_t num_cores;
|
uint32_t num_devices;
|
||||||
struct ethosn_core_t core[ETHOSN_CORE_NUM_MAX];
|
struct ethosn_device_t devices[ETHOSN_DEV_NUM_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
int fconf_populate_arm_ethosn(uintptr_t config);
|
int fconf_populate_arm_ethosn(uintptr_t config);
|
||||||
|
|
|
@ -114,7 +114,7 @@ ifeq (${ARM_LINUX_KERNEL_AS_BL33},1)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Arm Ethos-N NPU SiP service
|
# Arm(R) Ethos(TM)-N NPU SiP service
|
||||||
ARM_ETHOSN_NPU_DRIVER := 0
|
ARM_ETHOSN_NPU_DRIVER := 0
|
||||||
$(eval $(call assert_boolean,ARM_ETHOSN_NPU_DRIVER))
|
$(eval $(call assert_boolean,ARM_ETHOSN_NPU_DRIVER))
|
||||||
$(eval $(call add_define,ARM_ETHOSN_NPU_DRIVER))
|
$(eval $(call add_define,ARM_ETHOSN_NPU_DRIVER))
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Arm Limited. All rights reserved.
|
* Copyright (c) 2021-2022, Arm Limited. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -12,107 +12,341 @@
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
#include <plat/arm/common/fconf_ethosn_getter.h>
|
#include <plat/arm/common/fconf_ethosn_getter.h>
|
||||||
|
|
||||||
struct ethosn_config_t ethosn_config = {.num_cores = 0};
|
struct ethosn_config_t ethosn_config = {0};
|
||||||
|
|
||||||
static uint8_t fdt_node_get_status(const void *fdt, int node)
|
struct ethosn_sub_allocator_t {
|
||||||
|
const char *name;
|
||||||
|
size_t name_len;
|
||||||
|
uint32_t stream_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool fdt_node_is_enabled(const void *fdt, int node)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
uint8_t status = ETHOSN_STATUS_DISABLED;
|
|
||||||
const char *node_status;
|
const char *node_status;
|
||||||
|
|
||||||
node_status = fdt_getprop(fdt, node, "status", &len);
|
node_status = fdt_getprop(fdt, node, "status", &len);
|
||||||
if (node_status == NULL ||
|
if (node_status == NULL ||
|
||||||
(len == 5 && /* Includes null character */
|
(len == 5 && /* Includes null character */
|
||||||
strncmp(node_status, "okay", 4U) == 0)) {
|
strncmp(node_status, "okay", 4U) == 0)) {
|
||||||
status = ETHOSN_STATUS_ENABLED;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fdt_node_has_reserved_memory(const void *fdt, int dev_node)
|
||||||
|
{
|
||||||
|
return fdt_get_property(fdt, dev_node, "memory-region", NULL) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_node_get_iommus_stream_id(const void *fdt, int node, uint32_t *stream_id)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
uint32_t iommus_array[2] = {0U};
|
||||||
|
|
||||||
|
err = fdt_read_uint32_array(fdt, node, "iommus", 2U, iommus_array);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*stream_id = iommus_array[1];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_node_populate_sub_allocators(const void *fdt,
|
||||||
|
int alloc_node,
|
||||||
|
struct ethosn_sub_allocator_t *sub_allocators,
|
||||||
|
size_t num_allocs)
|
||||||
|
{
|
||||||
|
int sub_node;
|
||||||
|
size_t i;
|
||||||
|
int err = -FDT_ERR_NOTFOUND;
|
||||||
|
uint32_t found_sub_allocators = 0U;
|
||||||
|
|
||||||
|
fdt_for_each_subnode(sub_node, fdt, alloc_node) {
|
||||||
|
const char *node_name;
|
||||||
|
|
||||||
|
if (!fdt_node_is_enabled(fdt, sub_node)) {
|
||||||
|
/* Ignore disabled node */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fdt_node_check_compatible(fdt, sub_node, "ethosn-memory") != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_name = fdt_get_name(fdt, sub_node, NULL);
|
||||||
|
for (i = 0U; i < num_allocs; ++i) {
|
||||||
|
if (strncmp(node_name, sub_allocators[i].name,
|
||||||
|
sub_allocators[i].name_len) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_node_get_iommus_stream_id(fdt, sub_node,
|
||||||
|
&sub_allocators[i].stream_id);
|
||||||
|
if (err) {
|
||||||
|
ERROR("FCONF: Failed to get stream ID from sub-allocator %s\n",
|
||||||
|
node_name);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
++found_sub_allocators;
|
||||||
|
/* Nothing more to do for this node */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that at least one of the sub-allocators matched */
|
||||||
|
if (i == num_allocs) {
|
||||||
|
ERROR("FCONF: Unknown sub-allocator %s\n", node_name);
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
|
||||||
|
ERROR("FCONF: Failed to parse sub-allocators\n");
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == -FDT_ERR_NOTFOUND) {
|
||||||
|
ERROR("FCONF: No matching sub-allocator found\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_sub_allocators != num_allocs) {
|
||||||
|
ERROR("FCONF: Not all sub-allocators were found\n");
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_node_populate_main_allocator(const void *fdt,
|
||||||
|
int alloc_node,
|
||||||
|
struct ethosn_main_allocator_t *allocator)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct ethosn_sub_allocator_t sub_allocators[] = {
|
||||||
|
{.name = "firmware", .name_len = 8U},
|
||||||
|
{.name = "working_data", .name_len = 12U}
|
||||||
|
};
|
||||||
|
|
||||||
|
err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
|
||||||
|
ARRAY_SIZE(sub_allocators));
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
allocator->firmware.stream_id = sub_allocators[0].stream_id;
|
||||||
|
allocator->working_data.stream_id = sub_allocators[1].stream_id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_node_populate_asset_allocator(const void *fdt,
|
||||||
|
int alloc_node,
|
||||||
|
struct ethosn_asset_allocator_t *allocator)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct ethosn_sub_allocator_t sub_allocators[] = {
|
||||||
|
{.name = "command_stream", .name_len = 14U},
|
||||||
|
{.name = "weight_data", .name_len = 11U},
|
||||||
|
{.name = "buffer_data", .name_len = 11U},
|
||||||
|
{.name = "intermediate_data", .name_len = 17U}
|
||||||
|
};
|
||||||
|
|
||||||
|
err = fdt_node_populate_sub_allocators(fdt, alloc_node, sub_allocators,
|
||||||
|
ARRAY_SIZE(sub_allocators));
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
allocator->command_stream.stream_id = sub_allocators[0].stream_id;
|
||||||
|
allocator->weight_data.stream_id = sub_allocators[1].stream_id;
|
||||||
|
allocator->buffer_data.stream_id = sub_allocators[2].stream_id;
|
||||||
|
allocator->intermediate_data.stream_id = sub_allocators[3].stream_id;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fdt_node_populate_core(const void *fdt,
|
||||||
|
int device_node,
|
||||||
|
int core_node,
|
||||||
|
bool has_reserved_memory,
|
||||||
|
uint32_t core_index,
|
||||||
|
struct ethosn_core_t *core)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
int sub_node;
|
||||||
|
uintptr_t core_addr;
|
||||||
|
|
||||||
|
err = fdt_get_reg_props_by_index(fdt, device_node, core_index,
|
||||||
|
&core_addr, NULL);
|
||||||
|
if (err < 0) {
|
||||||
|
ERROR("FCONF: Failed to read reg property for NPU core %u\n",
|
||||||
|
core_index);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = -FDT_ERR_NOTFOUND;
|
||||||
|
fdt_for_each_subnode(sub_node, fdt, core_node) {
|
||||||
|
|
||||||
|
if (!fdt_node_is_enabled(fdt, sub_node)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fdt_node_check_compatible(fdt,
|
||||||
|
sub_node,
|
||||||
|
"ethosn-main_allocator") != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_reserved_memory) {
|
||||||
|
ERROR("FCONF: Main allocator not supported when using reserved memory\n");
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != -FDT_ERR_NOTFOUND) {
|
||||||
|
ERROR("FCONF: NPU core 0x%lx has more than one main allocator\n",
|
||||||
|
core_addr);
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_node_populate_main_allocator(fdt, sub_node, &core->main_allocator);
|
||||||
|
if (err) {
|
||||||
|
ERROR("FCONF: Failed to parse main allocator for NPU core 0x%lx\n",
|
||||||
|
core_addr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
|
||||||
|
ERROR("FCONF: Failed to parse core sub nodes\n");
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_reserved_memory && err) {
|
||||||
|
ERROR("FCONF: Main allocator not found for NPU core 0x%lx\n",
|
||||||
|
core_addr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
core->addr = core_addr;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fconf_populate_ethosn_config(uintptr_t config)
|
int fconf_populate_ethosn_config(uintptr_t config)
|
||||||
{
|
{
|
||||||
int ethosn_node;
|
int ethosn_node;
|
||||||
|
uint32_t dev_count = 0U;
|
||||||
const void *hw_conf_dtb = (const void *)config;
|
const void *hw_conf_dtb = (const void *)config;
|
||||||
|
|
||||||
/* Find offset to node with 'ethosn' compatible property */
|
INFO("Probing Arm(R) Ethos(TM)-N NPU\n");
|
||||||
INFO("Probing Arm Ethos-N NPU\n");
|
|
||||||
uint32_t total_core_count = 0U;
|
|
||||||
|
|
||||||
fdt_for_each_compatible_node(hw_conf_dtb, ethosn_node, "ethosn") {
|
fdt_for_each_compatible_node(hw_conf_dtb, ethosn_node, "ethosn") {
|
||||||
|
struct ethosn_device_t *dev = ðosn_config.devices[dev_count];
|
||||||
|
uint32_t dev_asset_alloc_count = 0U;
|
||||||
|
uint32_t dev_core_count = 0U;
|
||||||
|
bool has_reserved_memory;
|
||||||
int sub_node;
|
int sub_node;
|
||||||
uint8_t ethosn_status;
|
|
||||||
uint32_t device_core_count = 0U;
|
|
||||||
|
|
||||||
/* If the Arm Ethos-N NPU is disabled the core check can be skipped */
|
if (!fdt_node_is_enabled(hw_conf_dtb, ethosn_node)) {
|
||||||
ethosn_status = fdt_node_get_status(hw_conf_dtb, ethosn_node);
|
|
||||||
if (ethosn_status == ETHOSN_STATUS_DISABLED) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) {
|
if (dev_count >= ETHOSN_DEV_NUM_MAX) {
|
||||||
int err;
|
ERROR("FCONF: Reached max number of NPUs\n");
|
||||||
uintptr_t core_addr;
|
|
||||||
uint8_t core_status;
|
|
||||||
|
|
||||||
if (total_core_count >= ETHOSN_CORE_NUM_MAX) {
|
|
||||||
ERROR("FCONF: Reached max number of Arm Ethos-N NPU cores\n");
|
|
||||||
return -FDT_ERR_BADSTRUCTURE;
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the sub node is "ethosn-core" compatible */
|
has_reserved_memory = fdt_node_has_reserved_memory(hw_conf_dtb, ethosn_node);
|
||||||
|
fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!fdt_node_is_enabled(hw_conf_dtb, sub_node)) {
|
||||||
|
/* Ignore disabled sub node */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (fdt_node_check_compatible(hw_conf_dtb,
|
if (fdt_node_check_compatible(hw_conf_dtb,
|
||||||
sub_node,
|
sub_node,
|
||||||
"ethosn-core") != 0) {
|
"ethosn-core") == 0) {
|
||||||
/* Ignore incompatible sub node */
|
|
||||||
continue;
|
if (dev_core_count >= ETHOSN_DEV_CORE_NUM_MAX) {
|
||||||
|
ERROR("FCONF: Reached max number of NPU cores for NPU %u\n",
|
||||||
|
dev_count);
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
core_status = fdt_node_get_status(hw_conf_dtb, sub_node);
|
err = fdt_node_populate_core(hw_conf_dtb,
|
||||||
if (core_status == ETHOSN_STATUS_DISABLED) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = fdt_get_reg_props_by_index(hw_conf_dtb,
|
|
||||||
ethosn_node,
|
ethosn_node,
|
||||||
device_core_count,
|
sub_node,
|
||||||
&core_addr,
|
has_reserved_memory,
|
||||||
NULL);
|
dev_core_count,
|
||||||
if (err < 0) {
|
&(dev->cores[dev_core_count]));
|
||||||
ERROR(
|
if (err) {
|
||||||
"FCONF: Failed to read reg property for Arm Ethos-N NPU core %u\n",
|
|
||||||
device_core_count);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
++dev_core_count;
|
||||||
|
} else if (fdt_node_check_compatible(hw_conf_dtb,
|
||||||
|
sub_node,
|
||||||
|
"ethosn-asset_allocator") == 0) {
|
||||||
|
|
||||||
INFO("NPU core probed at address 0x%lx\n", core_addr);
|
if (dev_asset_alloc_count >=
|
||||||
ethosn_config.core[total_core_count].addr = core_addr;
|
ETHOSN_DEV_ASSET_ALLOCATOR_NUM_MAX) {
|
||||||
total_core_count++;
|
ERROR("FCONF: Reached max number of asset allocators for NPU %u\n",
|
||||||
device_core_count++;
|
dev_count);
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_reserved_memory) {
|
||||||
|
ERROR("FCONF: Asset allocator not supported when using reserved memory\n");
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_node_populate_asset_allocator(hw_conf_dtb,
|
||||||
|
sub_node,
|
||||||
|
&(dev->asset_allocators[dev_asset_alloc_count]));
|
||||||
|
if (err) {
|
||||||
|
ERROR("FCONF: Failed to parse asset allocator for NPU %u\n",
|
||||||
|
dev_count);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
++dev_asset_alloc_count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
|
if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
|
||||||
ERROR("FCONF: Failed to parse sub nodes\n");
|
ERROR("FCONF: Failed to parse sub nodes for NPU %u\n",
|
||||||
|
dev_count);
|
||||||
return -FDT_ERR_BADSTRUCTURE;
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device_core_count == 0U) {
|
if (dev_core_count == 0U) {
|
||||||
ERROR(
|
ERROR("FCONF: NPU %u must have at least one enabled core\n",
|
||||||
"FCONF: Enabled Arm Ethos-N NPU device must have at least one enabled core\n");
|
dev_count);
|
||||||
return -FDT_ERR_BADSTRUCTURE;
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!has_reserved_memory && dev_asset_alloc_count == 0U) {
|
||||||
|
ERROR("FCONF: NPU %u must have at least one asset allocator\n",
|
||||||
|
dev_count);
|
||||||
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (total_core_count == 0U) {
|
dev->num_cores = dev_core_count;
|
||||||
|
dev->num_allocators = dev_asset_alloc_count;
|
||||||
|
dev->has_reserved_memory = has_reserved_memory;
|
||||||
|
++dev_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev_count == 0U) {
|
||||||
ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n");
|
ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n");
|
||||||
return -FDT_ERR_BADSTRUCTURE;
|
return -FDT_ERR_BADSTRUCTURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ethosn_config.num_cores = total_core_count;
|
ethosn_config.num_devices = dev_count;
|
||||||
|
|
||||||
INFO("%d NPU core%s probed\n",
|
|
||||||
ethosn_config.num_cores,
|
|
||||||
ethosn_config.num_cores > 1 ? "s" : "");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue