Add SiP service to configure Arm Ethos-N NPU

By default the Arm Ethos-N NPU will boot up in secure mode. In this mode
the non-secure world cannot access the registers needed to use the NPU.
To still allow the non-secure world to use the NPU, a SiP service has
been added that can delegate non-secure access to the registers needed
to use it.

Only the HW_CONFIG for the Arm Juno platform has been updated to include
the device tree for the NPU and the platform currently only loads the
HW_CONFIG in AArch64 builds.

Signed-off-by: Mikael Olsson <mikael.olsson@arm.com>
Change-Id: I65dfd864042ed43faae0a259dcf319cbadb5f3d2
This commit is contained in:
Mikael Olsson 2021-02-12 17:30:22 +01:00 committed by Manish Pandey
parent 5d5fb10f9c
commit 76a21174d2
10 changed files with 452 additions and 7 deletions

View File

@ -91,6 +91,12 @@ Arm Platform Build Options
platforms. If this option is specified, then the path to the CryptoCell platforms. If this option is specified, then the path to the CryptoCell
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
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
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.
- ``ARM_SPMC_MANIFEST_DTS`` : path to an alternate manifest file used as the - ``ARM_SPMC_MANIFEST_DTS`` : path to an alternate manifest file used as the
SPMC Core manifest. Valid when ``SPD=spmd`` is selected. SPMC Core manifest. Valid when ``SPD=spmd`` is selected.
@ -128,4 +134,4 @@ Arm CSS Platform-Specific Build Options
-------------- --------------
*Copyright (c) 2019-2020, Arm Limited. All rights reserved.* *Copyright (c) 2019-2021, Arm Limited. All rights reserved.*

View File

@ -0,0 +1,164 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <stdbool.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <drivers/arm/ethosn.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <plat/arm/common/fconf_ethosn_getter.h>
/* Arm Ethos-N NPU (NPU) status */
#define ETHOSN_STATUS \
FCONF_GET_PROPERTY(hw_config, ethosn_config, status)
/* Number of NPU cores available */
#define ETHOSN_NUM_CORES \
FCONF_GET_PROPERTY(hw_config, ethosn_config, num_cores)
/* Address to an NPU core */
#define ETHOSN_CORE_ADDR(core_idx) \
FCONF_GET_PROPERTY(hw_config, ethosn_core_addr, core_idx)
/* NPU core sec registry address */
#define ETHOSN_CORE_SEC_REG(core_addr, reg_offset) \
(core_addr + reg_offset)
/* Reset timeout in us */
#define ETHOSN_RESET_TIMEOUT_US U(10 * 1000 * 1000)
#define ETHOSN_RESET_WAIT_US U(1)
#define SEC_DEL_REG U(0x0004)
#define SEC_DEL_VAL U(0x81C)
#define SEC_DEL_EXCC_MASK U(0x20)
#define SEC_SECCTLR_REG U(0x0010)
#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_VAL U(0x15)
#define SEC_SYSCTRL0_REG U(0x0018)
#define SEC_SYSCTRL0_SOFT_RESET U(3U << 29)
#define SEC_SYSCTRL0_HARD_RESET U(1U << 31)
static void ethosn_delegate_to_ns(uintptr_t core_addr)
{
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SECCTLR_REG),
SEC_SECCTLR_VAL);
mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG),
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),
SEC_DEL_ADDR_EXT_VAL);
}
static int ethosn_is_sec(void)
{
if ((mmio_read_32(ETHOSN_CORE_SEC_REG(ETHOSN_CORE_ADDR(0), SEC_DEL_REG))
& SEC_DEL_EXCC_MASK) != 0U) {
return 0;
}
return 1;
}
static bool ethosn_reset(uintptr_t core_addr, int hard_reset)
{
unsigned int timeout;
const uintptr_t sysctrl0_reg =
ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG);
const uint32_t reset_val = (hard_reset != 0) ? SEC_SYSCTRL0_HARD_RESET
: SEC_SYSCTRL0_SOFT_RESET;
mmio_write_32(sysctrl0_reg, reset_val);
/* Wait for reset to complete */
for (timeout = 0U; timeout < ETHOSN_RESET_TIMEOUT_US;
timeout += ETHOSN_RESET_WAIT_US) {
if ((mmio_read_32(sysctrl0_reg) & reset_val) == 0U) {
break;
}
udelay(ETHOSN_RESET_WAIT_US);
}
return timeout < ETHOSN_RESET_TIMEOUT_US;
}
uintptr_t ethosn_smc_handler(uint32_t smc_fid,
u_register_t core_idx,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags)
{
uintptr_t core_addr;
int hard_reset = 0;
/* Only SiP fast calls are expected */
if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
(GET_SMC_OEN(smc_fid) != OEN_SIP_START)) {
SMC_RET1(handle, SMC_UNK);
}
/* Truncate parameters to 32-bits for SMC32 */
if (GET_SMC_CC(smc_fid) == SMC_32) {
core_idx &= 0xFFFFFFFF;
x2 &= 0xFFFFFFFF;
x3 &= 0xFFFFFFFF;
x4 &= 0xFFFFFFFF;
}
if (!is_ethosn_fid(smc_fid)) {
SMC_RET1(handle, SMC_UNK);
}
if (ETHOSN_STATUS == ETHOSN_STATUS_DISABLED) {
WARN("ETHOSN: Arm Ethos-N NPU not available\n");
SMC_RET1(handle, ETHOSN_NOT_SUPPORTED);
}
switch (smc_fid & FUNCID_NUM_MASK) {
case ETHOSN_FNUM_VERSION:
SMC_RET2(handle, ETHOSN_VERSION_MAJOR, ETHOSN_VERSION_MINOR);
case ETHOSN_FNUM_IS_SEC:
SMC_RET1(handle, ethosn_is_sec());
case ETHOSN_FNUM_HARD_RESET:
hard_reset = 1;
/* Fallthrough */
case ETHOSN_FNUM_SOFT_RESET:
if (core_idx >= ETHOSN_NUM_CORES) {
WARN("ETHOSN: core index out of range\n");
SMC_RET1(handle, ETHOSN_CORE_IDX_OUT_OF_RANGE);
}
core_addr = ETHOSN_CORE_ADDR(core_idx);
if (!ethosn_reset(core_addr, hard_reset)) {
SMC_RET1(handle, ETHOSN_FAILURE);
}
ethosn_delegate_to_ns(core_addr);
SMC_RET1(handle, ETHOSN_SUCCESS);
default:
SMC_RET1(handle, SMC_UNK);
}
}

25
fdts/juno-ethosn.dtsi Normal file
View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/ {
#address-cells = <2>;
#size-cells = <2>;
ethosn: ethosn@6f300000 {
compatible = "ethosn";
reg = <0 0x6f300000 0 0x00100000>;
status = "okay";
/*
* Single-core NPU. For multi-core NPU, additional core nodes
* and reg values must be added.
*/
core0 {
compatible = "ethosn-core";
status = "okay";
};
};
};

View File

@ -9,3 +9,7 @@
/ { / {
}; };
#if ARM_ETHOSN_NPU_DRIVER
#include "juno-ethosn.dtsi"
#endif

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef ETHOSN_H
#define ETHOSN_H
#include <lib/smccc.h>
/* Function numbers */
#define ETHOSN_FNUM_VERSION U(0x50)
#define ETHOSN_FNUM_IS_SEC U(0x51)
#define ETHOSN_FNUM_HARD_RESET U(0x52)
#define ETHOSN_FNUM_SOFT_RESET U(0x53)
/* 0x54-0x5F reserved for future use */
/* SMC64 function IDs */
#define ETHOSN_FID_64(func_num) U(0xC2000000 | func_num)
#define ETHOSN_FID_VERSION_64 ETHOSN_FID_64(ETHOSN_FNUM_VERSION)
#define ETHOSN_FID_IS_SEC_64 ETHOSN_FID_64(ETHOSN_FNUM_IS_SEC)
#define ETHOSN_FID_HARD_RESET_64 ETHOSN_FID_64(ETHOSN_FNUM_HARD_RESET)
#define ETHOSN_FID_SOFT_RESET_64 ETHOSN_FID_64(ETHOSN_FNUM_SOFT_RESET)
/* SMC32 function IDs */
#define ETHOSN_FID_32(func_num) U(0x82000000 | func_num)
#define ETHOSN_FID_VERSION_32 ETHOSN_FID_32(ETHOSN_FNUM_VERSION)
#define ETHOSN_FID_IS_SEC_32 ETHOSN_FID_32(ETHOSN_FNUM_IS_SEC)
#define ETHOSN_FID_HARD_RESET_32 ETHOSN_FID_32(ETHOSN_FNUM_HARD_RESET)
#define ETHOSN_FID_SOFT_RESET_32 ETHOSN_FID_32(ETHOSN_FNUM_SOFT_RESET)
#define ETHOSN_NUM_SMC_CALLS 8
/* Macro to identify function calls */
#define ETHOSN_FID_MASK U(0xFFF0)
#define ETHOSN_FID_VALUE U(0x50)
#define is_ethosn_fid(_fid) (((_fid) & ETHOSN_FID_MASK) == ETHOSN_FID_VALUE)
/* Service version */
#define ETHOSN_VERSION_MAJOR U(0)
#define ETHOSN_VERSION_MINOR U(1)
/* Return codes for function calls */
#define ETHOSN_SUCCESS 0
#define ETHOSN_NOT_SUPPORTED -1
/* -2 Reserved for NOT_REQUIRED */
/* -3 Reserved for INVALID_PARAMETER */
#define ETHOSN_FAILURE -4
#define ETHOSN_CORE_IDX_OUT_OF_RANGE -5
uintptr_t ethosn_smc_handler(uint32_t smc_fid,
u_register_t core_idx,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags);
#endif /* ETHOSN_H */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2016-2019,2021, ARM Limited and Contributors. All rights reserved.
* *
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
@ -25,6 +25,12 @@
/* DEBUGFS_SMC_32 0x82000030U */ /* DEBUGFS_SMC_32 0x82000030U */
/* DEBUGFS_SMC_64 0xC2000030U */ /* DEBUGFS_SMC_64 0xC2000030U */
/*
* Arm Ethos-N NPU SiP SMC function IDs
* 0xC2000050-0xC200005F
* 0x82000050-0x8200005F
*/
/* ARM SiP Service Calls version numbers */ /* ARM SiP Service Calls version numbers */
#define ARM_SIP_SVC_VERSION_MAJOR U(0x0) #define ARM_SIP_SVC_VERSION_MAJOR U(0x0)
#define ARM_SIP_SVC_VERSION_MINOR U(0x2) #define ARM_SIP_SVC_VERSION_MINOR U(0x2)

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef FCONF_ETHOSN_GETTER_H
#define FCONF_ETHOSN_GETTER_H
#include <assert.h>
#include <lib/fconf/fconf.h>
#define hw_config__ethosn_config_getter(prop) ethosn_config.prop
#define hw_config__ethosn_core_addr_getter(idx) __extension__ ({ \
assert(idx < ethosn_config.num_cores); \
ethosn_config.core_addr[idx]; \
})
#define ETHOSN_STATUS_DISABLED U(0)
#define ETHOSN_STATUS_ENABLED U(1)
#define ETHOSN_CORE_NUM_MAX U(64)
struct ethosn_config_t {
uint8_t status;
uint32_t num_cores;
uint64_t core_addr[ETHOSN_CORE_NUM_MAX];
};
int fconf_populate_arm_ethosn(uintptr_t config);
extern struct ethosn_config_t ethosn_config;
#endif /* FCONF_ETHOSN_GETTER_H */

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. # Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
# #
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
# #
@ -100,6 +100,11 @@ ifeq (${ARM_LINUX_KERNEL_AS_BL33},1)
$(eval $(call add_define,ARM_PRELOADED_DTB_BASE)) $(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
endif endif
# Arm Ethos-N NPU SiP service
ARM_ETHOSN_NPU_DRIVER := 0
$(eval $(call assert_boolean,ARM_ETHOSN_NPU_DRIVER))
$(eval $(call add_define,ARM_ETHOSN_NPU_DRIVER))
# Use an implementation of SHA-256 with a smaller memory footprint but reduced # Use an implementation of SHA-256 with a smaller memory footprint but reduced
# speed. # speed.
$(eval $(call add_define,MBEDTLS_SHA256_SMALLER)) $(eval $(call add_define,MBEDTLS_SHA256_SMALLER))
@ -248,14 +253,26 @@ BL31_SOURCES += plat/arm/common/arm_bl31_setup.c \
plat/arm/common/arm_topology.c \ plat/arm/common/arm_topology.c \
plat/common/plat_psci_common.c plat/common/plat_psci_common.c
ifeq (${ENABLE_PMF}, 1) ifneq ($(filter 1,${ENABLE_PMF} ${ARM_ETHOSN_NPU_DRIVER}),)
ARM_SVC_HANDLER_SRCS :=
ifeq (${ENABLE_PMF},1)
ARM_SVC_HANDLER_SRCS += lib/pmf/pmf_smc.c
endif
ifeq (${ARM_ETHOSN_NPU_DRIVER},1)
ARM_SVC_HANDLER_SRCS += plat/arm/common/fconf/fconf_ethosn_getter.c \
drivers/delay_timer/delay_timer.c \
drivers/arm/ethosn/ethosn_smc.c
endif
ifeq (${ARCH}, aarch64) ifeq (${ARCH}, aarch64)
BL31_SOURCES += plat/arm/common/aarch64/execution_state_switch.c\ BL31_SOURCES += plat/arm/common/aarch64/execution_state_switch.c\
plat/arm/common/arm_sip_svc.c \ plat/arm/common/arm_sip_svc.c \
lib/pmf/pmf_smc.c ${ARM_SVC_HANDLER_SRCS}
else else
BL32_SOURCES += plat/arm/common/arm_sip_svc.c \ BL32_SOURCES += plat/arm/common/arm_sip_svc.c \
lib/pmf/pmf_smc.c ${ARM_SVC_HANDLER_SRCS}
endif endif
endif endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2016-2019,2021, ARM Limited and Contributors. All rights reserved.
* *
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*/ */
@ -8,6 +8,7 @@
#include <common/debug.h> #include <common/debug.h>
#include <common/runtime_svc.h> #include <common/runtime_svc.h>
#include <drivers/arm/ethosn.h>
#include <lib/debugfs.h> #include <lib/debugfs.h>
#include <lib/pmf/pmf.h> #include <lib/pmf/pmf.h>
#include <plat/arm/common/arm_sip_svc.h> #include <plat/arm/common/arm_sip_svc.h>
@ -50,6 +51,8 @@ static uintptr_t arm_sip_handler(unsigned int smc_fid,
{ {
int call_count = 0; int call_count = 0;
#if ENABLE_PMF
/* /*
* Dispatch PMF calls to PMF SMC handler and return its return * Dispatch PMF calls to PMF SMC handler and return its return
* value * value
@ -59,6 +62,8 @@ static uintptr_t arm_sip_handler(unsigned int smc_fid,
handle, flags); handle, flags);
} }
#endif /* ENABLE_PMF */
#if USE_DEBUGFS #if USE_DEBUGFS
if (is_debugfs_fid(smc_fid)) { if (is_debugfs_fid(smc_fid)) {
@ -68,6 +73,15 @@ static uintptr_t arm_sip_handler(unsigned int smc_fid,
#endif /* USE_DEBUGFS */ #endif /* USE_DEBUGFS */
#if ARM_ETHOSN_NPU_DRIVER
if (is_ethosn_fid(smc_fid)) {
return ethosn_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
handle, flags);
}
#endif /* ARM_ETHOSN_NPU_DRIVER */
switch (smc_fid) { switch (smc_fid) {
case ARM_SIP_SVC_EXE_STATE_SWITCH: { case ARM_SIP_SVC_EXE_STATE_SWITCH: {
/* Execution state can be switched only if EL3 is AArch64 */ /* Execution state can be switched only if EL3 is AArch64 */
@ -92,6 +106,11 @@ static uintptr_t arm_sip_handler(unsigned int smc_fid,
/* PMF calls */ /* PMF calls */
call_count += PMF_NUM_SMC_CALLS; call_count += PMF_NUM_SMC_CALLS;
#if ARM_ETHOSN_NPU_DRIVER
/* ETHOSN calls */
call_count += ETHOSN_NUM_SMC_CALLS;
#endif /* ARM_ETHOSN_NPU_DRIVER */
/* State switch call */ /* State switch call */
call_count += 1; call_count += 1;

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include <common/debug.h>
#include <common/fdt_wrappers.h>
#include <libfdt.h>
#include <plat/arm/common/fconf_ethosn_getter.h>
struct ethosn_config_t ethosn_config;
static uint8_t fdt_node_get_status(const void *fdt, int node)
{
int len;
uint8_t status = ETHOSN_STATUS_DISABLED;
const char *node_status;
node_status = fdt_getprop(fdt, node, "status", &len);
if (node_status == NULL ||
(len == 5 && /* Includes null character */
strncmp(node_status, "okay", 4U) == 0)) {
status = ETHOSN_STATUS_ENABLED;
}
return status;
}
int fconf_populate_ethosn_config(uintptr_t config)
{
int ethosn_node;
int sub_node;
uint8_t ethosn_status;
uint32_t core_count = 0U;
uint32_t core_addr_idx = 0U;
const void *hw_conf_dtb = (const void *)config;
/* Find offset to node with 'ethosn' compatible property */
ethosn_node = fdt_node_offset_by_compatible(hw_conf_dtb, -1, "ethosn");
if (ethosn_node < 0) {
ERROR("FCONF: Can't find 'ethosn' compatible node in dtb\n");
return ethosn_node;
}
/* If the Arm Ethos-N NPU is disabled the core check can be skipped */
ethosn_status = fdt_node_get_status(hw_conf_dtb, ethosn_node);
if (ethosn_status == ETHOSN_STATUS_DISABLED) {
return 0;
}
fdt_for_each_subnode(sub_node, hw_conf_dtb, ethosn_node) {
int err;
uintptr_t addr;
uint8_t status;
/* Check that the sub node is "ethosn-core" compatible */
if (fdt_node_check_compatible(hw_conf_dtb, sub_node,
"ethosn-core") != 0) {
/* Ignore incompatible sub node */
continue;
}
/* Including disabled cores */
if (core_addr_idx >= ETHOSN_CORE_NUM_MAX) {
ERROR("FCONF: Reached max number of Arm Ethos-N NPU cores\n");
return -1;
}
status = fdt_node_get_status(hw_conf_dtb, ethosn_node);
if (status == ETHOSN_STATUS_DISABLED) {
++core_addr_idx;
continue;
}
err = fdt_get_reg_props_by_index(hw_conf_dtb, ethosn_node,
core_addr_idx, &addr, NULL);
if (err < 0) {
ERROR("FCONF: Failed to read reg property for Arm Ethos-N NPU core %u\n",
core_addr_idx);
return err;
}
ethosn_config.core_addr[core_count++] = addr;
++core_addr_idx;
}
if ((sub_node < 0) && (sub_node != -FDT_ERR_NOTFOUND)) {
ERROR("FCONF: Failed to parse sub nodes\n");
return sub_node;
}
/* The Arm Ethos-N NPU can't be used if no cores were found */
if (core_count == 0) {
ERROR("FCONF: No Arm Ethos-N NPU cores found\n");
return -1;
}
ethosn_config.num_cores = core_count;
ethosn_config.status = ethosn_status;
return 0;
}
FCONF_REGISTER_POPULATOR(HW_CONFIG, ethosn_config, fconf_populate_ethosn_config);