feat(drivers/arm/ethosn)!: multi-device support

Add support for Arm Ethos-N NPU multi-device.

The device tree parsing currently only supports one NPU device with
multiple cores. To be able to support multi-device NPU configurations
this patch adds support for having multiple NPU devices in the device
tree.

To be able to support multiple NPU devices in the SMC API, it has been
changed in an incompatible way so the API version has been bumped.

Signed-off-by: Laurent Carlier <laurent.carlier@arm.com>
Change-Id: Ide279ce949bd06e8939268b9601c267e45f3edc3
diff --git a/drivers/arm/ethosn/ethosn_smc.c b/drivers/arm/ethosn/ethosn_smc.c
index 299d07c..60364cd 100644
--- a/drivers/arm/ethosn/ethosn_smc.c
+++ b/drivers/arm/ethosn/ethosn_smc.c
@@ -14,11 +14,10 @@
 #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 */
+/*
+ * Number of Arm Ethos-N NPU (NPU) cores available for a
+ * particular parent device
+ */
 #define ETHOSN_NUM_CORES \
 	FCONF_GET_PROPERTY(hw_config, ethosn_config, num_cores)
 
@@ -51,6 +50,17 @@
 #define SEC_SYSCTRL0_SOFT_RESET		U(3U << 29)
 #define SEC_SYSCTRL0_HARD_RESET		U(1U << 31)
 
+static bool ethosn_is_core_addr_valid(uintptr_t core_addr)
+{
+	for (uint32_t core_idx = 0U; core_idx < ETHOSN_NUM_CORES; core_idx++) {
+		if (ETHOSN_CORE_ADDR(core_idx) == core_addr) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
 static void ethosn_delegate_to_ns(uintptr_t core_addr)
 {
 	mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SECCTLR_REG),
@@ -66,9 +76,9 @@
 			SEC_DEL_ADDR_EXT_VAL);
 }
 
-static int ethosn_is_sec(void)
+static int ethosn_is_sec(uintptr_t core_addr)
 {
-	if ((mmio_read_32(ETHOSN_CORE_SEC_REG(ETHOSN_CORE_ADDR(0), SEC_DEL_REG))
+	if ((mmio_read_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG))
 		& SEC_DEL_EXCC_MASK) != 0U) {
 		return 0;
 	}
@@ -101,7 +111,7 @@
 }
 
 uintptr_t ethosn_smc_handler(uint32_t smc_fid,
-			     u_register_t core_idx,
+			     u_register_t core_addr,
 			     u_register_t x2,
 			     u_register_t x3,
 			     u_register_t x4,
@@ -109,8 +119,8 @@
 			     void *handle,
 			     u_register_t flags)
 {
-	uintptr_t core_addr;
 	int hard_reset = 0;
+	const uint32_t fid = smc_fid & FUNCID_NUM_MASK;
 
 	/* Only SiP fast calls are expected */
 	if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
@@ -120,7 +130,7 @@
 
 	/* Truncate parameters to 32-bits for SMC32 */
 	if (GET_SMC_CC(smc_fid) == SMC_32) {
-		core_idx &= 0xFFFFFFFF;
+		core_addr &= 0xFFFFFFFF;
 		x2 &= 0xFFFFFFFF;
 		x3 &= 0xFFFFFFFF;
 		x4 &= 0xFFFFFFFF;
@@ -130,33 +140,29 @@
 		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) {
+	/* Commands that do not require a valid core address */
+	switch (fid) {
 	case ETHOSN_FNUM_VERSION:
 		SMC_RET2(handle, ETHOSN_VERSION_MAJOR, ETHOSN_VERSION_MINOR);
+	}
+
+	if (!ethosn_is_core_addr_valid(core_addr)) {
+		WARN("ETHOSN: Unknown core address given to SMC call.\n");
+		SMC_RET1(handle, ETHOSN_UNKNOWN_CORE_ADDRESS);
+	}
+
+	/* Commands that require a valid addr */
+	switch (fid) {
 	case ETHOSN_FNUM_IS_SEC:
-		SMC_RET1(handle, ethosn_is_sec());
+		SMC_RET1(handle, ethosn_is_sec(core_addr));
 	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);