]> git.baikalelectronics.ru Git - arm-tf.git/commitdiff
feat(ethos-n)!: add protected NPU firmware setup
authorMikael Olsson <mikael.olsson@arm.com>
Fri, 10 Feb 2023 15:59:23 +0000 (16:59 +0100)
committerJoanna Farley <joanna.farley@arm.com>
Tue, 4 Apr 2023 09:37:49 +0000 (11:37 +0200)
When the Arm(R) Ethos(TM)-N NPU driver is built with TZMP1 support, the
NPU should use the firmware that has been loaded into the protected
memory by BL2. The Linux Kernel NPU driver in the non-secure world is
not allowed to configure the NPU to do this in a TZMP1 build so the SiP
service will now configure the NPU to boot with the firmware in the
protected memory.

BREAKING CHANGE: The Linux Kernel NPU driver can no longer directly
configure and boot the NPU in a TZMP1 build. The API version has
therefore been given a major version bump with this change.

Signed-off-by: Mikael Olsson <mikael.olsson@arm.com>
Change-Id: I65d00f54b3ade3665d7941e270da7a3dec02281a

drivers/arm/ethosn/ethosn_smc.c
include/drivers/arm/ethosn.h

index d1b21e0451efb23e6c9d8e94e62b160bb63bc445..65585669691c72534cd28d7d7f91cc5e1c6d1bf4 100644 (file)
 #define SEC_AUXCTLR_STASHING_VAL       U(0xA5000000)
 
 #define SEC_DEL_REG                    U(0x0004)
+#if ARM_ETHOSN_NPU_TZMP1
+#define SEC_DEL_VAL                    U(0x808)
+#else
 #define SEC_DEL_VAL                    U(0x80C)
+#endif
 #define SEC_DEL_EXCC_MASK              U(0x20)
 
 #define SEC_SECCTLR_REG                        U(0x0010)
@@ -62,7 +66,9 @@
 #define SEC_DEL_ADDR_EXT_VAL            U(0x1)
 
 #define SEC_SYSCTRL0_REG               U(0x0018)
+#define SEC_SYSCTRL0_CPU_WAIT          U(1)
 #define SEC_SYSCTRL0_SLEEPING          U(1U << 4)
+#define SEC_SYSCTRL0_INITVTOR_MASK     U(0x1FFFFF80)
 #define SEC_SYSCTRL0_SOFT_RESET                U(3U << 29)
 #define SEC_SYSCTRL0_HARD_RESET                U(1U << 31)
 
@@ -88,6 +94,8 @@
 #define SEC_NPU_ID_REG                 U(0xF000)
 #define SEC_NPU_ID_ARCH_VER_SHIFT      U(0X10)
 
+#define FIRMWARE_STREAM_INDEX           U(0x0)
+#define PLE_STREAM_INDEX               U(0x4)
 #define INPUT_STREAM_INDEX              U(0x6)
 #define INTERMEDIATE_STREAM_INDEX       U(0x7)
 #define OUTPUT_STREAM_INDEX             U(0x8)
 #if ARM_ETHOSN_NPU_TZMP1
 CASSERT(ARM_ETHOSN_NPU_FW_IMAGE_BASE > 0U, assert_ethosn_invalid_fw_image_base);
 static const struct ethosn_big_fw *big_fw;
+
+#define FW_INITVTOR_ADDR(big_fw) \
+       ((ETHOSN_FW_VA_BASE + big_fw->vector_table_offset) & \
+        SEC_SYSCTRL0_INITVTOR_MASK)
+
+#define SYSCTRL0_INITVTOR_ADDR(value) \
+       (value & SEC_SYSCTRL0_INITVTOR_MASK)
+
 #endif
 
 static bool ethosn_get_device_and_core(uintptr_t core_addr,
@@ -140,6 +156,9 @@ static void ethosn_configure_stream_nsaid(const struct ethosn_core_t *core,
        size_t i;
        uint32_t streams[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
 
+       streams[FIRMWARE_STREAM_INDEX] = ARM_ETHOSN_NPU_PROT_FW_NSAID;
+       streams[PLE_STREAM_INDEX] = ARM_ETHOSN_NPU_PROT_FW_NSAID;
+
        if (is_protected) {
                streams[INPUT_STREAM_INDEX] = ARM_ETHOSN_NPU_PROT_DATA_NSAID;
                streams[INTERMEDIATE_STREAM_INDEX] =
@@ -154,6 +173,13 @@ static void ethosn_configure_stream_nsaid(const struct ethosn_core_t *core,
                              streams[i]);
        }
 }
+
+static void ethosn_configure_vector_table(uintptr_t core_addr)
+{
+       mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG),
+                       FW_INITVTOR_ADDR(big_fw));
+}
+
 #endif
 
 static void ethosn_configure_events(uintptr_t core_addr)
@@ -307,6 +333,31 @@ static bool ethosn_core_reset(uintptr_t core_addr, bool hard_reset)
        return timeout < ETHOSN_RESET_TIMEOUT_US;
 }
 
+static int ethosn_core_boot_fw(uintptr_t core_addr)
+{
+#if ARM_ETHOSN_NPU_TZMP1
+       const uintptr_t sysctrl0_reg = ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG);
+       const uint32_t sysctrl0_val = mmio_read_32(sysctrl0_reg);
+       const bool waiting = (sysctrl0_val & SEC_SYSCTRL0_CPU_WAIT);
+
+       if (!waiting) {
+               WARN("ETHOSN: Firmware is already running.\n");
+               return ETHOSN_INVALID_STATE;
+       }
+
+       if (SYSCTRL0_INITVTOR_ADDR(sysctrl0_val) != FW_INITVTOR_ADDR(big_fw)) {
+               WARN("ETHOSN: Unknown vector table won't boot firmware.\n");
+               return ETHOSN_INVALID_CONFIGURATION;
+       }
+
+       mmio_clrbits_32(sysctrl0_reg, SEC_SYSCTRL0_CPU_WAIT);
+
+       return ETHOSN_SUCCESS;
+#else
+       return ETHOSN_NOT_SUPPORTED;
+#endif
+}
+
 static int ethosn_core_full_reset(const struct ethosn_device_t *device,
                                  const struct ethosn_core_t *core,
                                  bool hard_reset,
@@ -341,6 +392,10 @@ static int ethosn_core_full_reset(const struct ethosn_device_t *device,
        ethosn_configure_stream_addr_extends(device, core->addr);
        ethosn_configure_stream_attr_ctlr(core->addr);
 
+#if ARM_ETHOSN_NPU_TZMP1
+       ethosn_configure_vector_table(core->addr);
+#endif
+
        ethosn_delegate_to_ns(core->addr);
 
        return ETHOSN_SUCCESS;
@@ -407,6 +462,8 @@ static uintptr_t ethosn_smc_core_handler(uint32_t fid,
                                                     is_protected,
                                                     aux_features,
                                                     handle);
+       case ETHOSN_FNUM_BOOT_FW:
+               SMC_RET1(handle, ethosn_core_boot_fw(core->addr));
        default:
                WARN("ETHOSN: Unimplemented SMC call: 0x%x\n", fid);
                SMC_RET1(handle, SMC_UNK);
@@ -470,7 +527,7 @@ uintptr_t ethosn_smc_handler(uint32_t smc_fid,
                x4 &= 0xFFFFFFFF;
        }
 
-       if (!is_ethosn_fid(smc_fid) || (fid > ETHOSN_FNUM_GET_FW_PROP)) {
+       if (!is_ethosn_fid(smc_fid) || (fid > ETHOSN_FNUM_BOOT_FW)) {
                WARN("ETHOSN: Unknown SMC call: 0x%x\n", smc_fid);
                SMC_RET1(handle, SMC_UNK);
        }
@@ -509,6 +566,11 @@ int ethosn_smc_setup(void)
        }
 
        dev = ETHOSN_GET_DEVICE(0U);
+       if (dev->has_reserved_memory) {
+               ERROR("ETHOSN: TZMP1 doesn't support using reserved memory\n");
+               return ETHOSN_FAILURE;
+       }
+
        arch_ver = ethosn_core_read_arch_version(dev->cores[0U].addr);
        big_fw = (struct ethosn_big_fw *)ARM_ETHOSN_NPU_FW_IMAGE_BASE;
 
index b43e8dd1717a37fbe914ef598f40a435364c863c..993dd122b601b29be018442c0fcc1f2c8ba25930 100644 (file)
@@ -16,7 +16,8 @@
 #define ETHOSN_FNUM_SOFT_RESET         U(0x53)
 #define ETHOSN_FNUM_IS_SLEEPING                U(0x54)
 #define ETHOSN_FNUM_GET_FW_PROP                U(0x55)
-/* 0x56-0x5F reserved for future use */
+#define ETHOSN_FNUM_BOOT_FW            U(0x56)
+/* 0x57-0x5F reserved for future use */
 
 /* Properties for ETHOSN_FNUM_TZMP_GET_FW_PROP */
 #define ETHOSN_FW_PROP_VERSION         U(0xF00)
@@ -46,8 +47,8 @@
 #define is_ethosn_fid(_fid) (((_fid) & ETHOSN_FID_MASK) == ETHOSN_FID_VALUE)
 
 /* Service version  */
-#define ETHOSN_VERSION_MAJOR U(2)
-#define ETHOSN_VERSION_MINOR U(6)
+#define ETHOSN_VERSION_MAJOR U(3)
+#define ETHOSN_VERSION_MINOR U(0)
 
 /* Return codes for function calls */
 #define ETHOSN_SUCCESS                  0
@@ -58,6 +59,7 @@
 #define ETHOSN_UNKNOWN_CORE_ADDRESS    -5
 #define ETHOSN_UNKNOWN_ALLOCATOR_IDX   -6
 #define ETHOSN_INVALID_CONFIGURATION    -7
+#define ETHOSN_INVALID_STATE           -8
 
 /*
  * Argument types for soft and hard resets to indicate whether to reset