1 /*
2 * Copyright (c) 2021, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdint.h>
8 #include <stdbool.h>
9
10 #include <common/debug.h>
11 #include <common/runtime_svc.h>
12 #include <drivers/arm/ethosn.h>
13 #include <drivers/delay_timer.h>
14 #include <lib/mmio.h>
15 #include <plat/arm/common/fconf_ethosn_getter.h>
16
17 /*
18 * Number of Arm Ethos-N NPU (NPU) cores available for a
19 * particular parent device
20 */
21 #define ETHOSN_NUM_CORES \
22 FCONF_GET_PROPERTY(hw_config, ethosn_config, num_cores)
23
24 /* Address to an NPU core */
25 #define ETHOSN_CORE_ADDR(core_idx) \
26 FCONF_GET_PROPERTY(hw_config, ethosn_core_addr, core_idx)
27
28 /* NPU core sec registry address */
29 #define ETHOSN_CORE_SEC_REG(core_addr, reg_offset) \
30 (core_addr + reg_offset)
31
32 /* Reset timeout in us */
33 #define ETHOSN_RESET_TIMEOUT_US U(10 * 1000 * 1000)
34 #define ETHOSN_RESET_WAIT_US U(1)
35
36 #define SEC_DEL_REG U(0x0004)
37 #define SEC_DEL_VAL U(0x81C)
38 #define SEC_DEL_EXCC_MASK U(0x20)
39
40 #define SEC_SECCTLR_REG U(0x0010)
41 #define SEC_SECCTLR_VAL U(0x3)
42
43 #define SEC_DEL_MMUSID_REG U(0x2008)
44 #define SEC_DEL_MMUSID_VAL U(0x3FFFF)
45
46 #define SEC_DEL_ADDR_EXT_REG U(0x201C)
47 #define SEC_DEL_ADDR_EXT_VAL U(0x15)
48
49 #define SEC_SYSCTRL0_REG U(0x0018)
50 #define SEC_SYSCTRL0_SOFT_RESET U(3U << 29)
51 #define SEC_SYSCTRL0_HARD_RESET U(1U << 31)
52
ethosn_is_core_addr_valid(uintptr_t core_addr)53 static bool ethosn_is_core_addr_valid(uintptr_t core_addr)
54 {
55 for (uint32_t core_idx = 0U; core_idx < ETHOSN_NUM_CORES; core_idx++) {
56 if (ETHOSN_CORE_ADDR(core_idx) == core_addr) {
57 return true;
58 }
59 }
60
61 return false;
62 }
63
ethosn_delegate_to_ns(uintptr_t core_addr)64 static void ethosn_delegate_to_ns(uintptr_t core_addr)
65 {
66 mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SECCTLR_REG),
67 SEC_SECCTLR_VAL);
68
69 mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG),
70 SEC_DEL_VAL);
71
72 mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_MMUSID_REG),
73 SEC_DEL_MMUSID_VAL);
74
75 mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_ADDR_EXT_REG),
76 SEC_DEL_ADDR_EXT_VAL);
77 }
78
ethosn_is_sec(uintptr_t core_addr)79 static int ethosn_is_sec(uintptr_t core_addr)
80 {
81 if ((mmio_read_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG))
82 & SEC_DEL_EXCC_MASK) != 0U) {
83 return 0;
84 }
85
86 return 1;
87 }
88
ethosn_reset(uintptr_t core_addr,int hard_reset)89 static bool ethosn_reset(uintptr_t core_addr, int hard_reset)
90 {
91 unsigned int timeout;
92 const uintptr_t sysctrl0_reg =
93 ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG);
94 const uint32_t reset_val = (hard_reset != 0) ? SEC_SYSCTRL0_HARD_RESET
95 : SEC_SYSCTRL0_SOFT_RESET;
96
97 mmio_write_32(sysctrl0_reg, reset_val);
98
99 /* Wait for reset to complete */
100 for (timeout = 0U; timeout < ETHOSN_RESET_TIMEOUT_US;
101 timeout += ETHOSN_RESET_WAIT_US) {
102
103 if ((mmio_read_32(sysctrl0_reg) & reset_val) == 0U) {
104 break;
105 }
106
107 udelay(ETHOSN_RESET_WAIT_US);
108 }
109
110 return timeout < ETHOSN_RESET_TIMEOUT_US;
111 }
112
ethosn_smc_handler(uint32_t smc_fid,u_register_t core_addr,u_register_t x2,u_register_t x3,u_register_t x4,void * cookie,void * handle,u_register_t flags)113 uintptr_t ethosn_smc_handler(uint32_t smc_fid,
114 u_register_t core_addr,
115 u_register_t x2,
116 u_register_t x3,
117 u_register_t x4,
118 void *cookie,
119 void *handle,
120 u_register_t flags)
121 {
122 int hard_reset = 0;
123 const uint32_t fid = smc_fid & FUNCID_NUM_MASK;
124
125 /* Only SiP fast calls are expected */
126 if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
127 (GET_SMC_OEN(smc_fid) != OEN_SIP_START)) {
128 SMC_RET1(handle, SMC_UNK);
129 }
130
131 /* Truncate parameters to 32-bits for SMC32 */
132 if (GET_SMC_CC(smc_fid) == SMC_32) {
133 core_addr &= 0xFFFFFFFF;
134 x2 &= 0xFFFFFFFF;
135 x3 &= 0xFFFFFFFF;
136 x4 &= 0xFFFFFFFF;
137 }
138
139 if (!is_ethosn_fid(smc_fid)) {
140 SMC_RET1(handle, SMC_UNK);
141 }
142
143 /* Commands that do not require a valid core address */
144 switch (fid) {
145 case ETHOSN_FNUM_VERSION:
146 SMC_RET2(handle, ETHOSN_VERSION_MAJOR, ETHOSN_VERSION_MINOR);
147 }
148
149 if (!ethosn_is_core_addr_valid(core_addr)) {
150 WARN("ETHOSN: Unknown core address given to SMC call.\n");
151 SMC_RET1(handle, ETHOSN_UNKNOWN_CORE_ADDRESS);
152 }
153
154 /* Commands that require a valid addr */
155 switch (fid) {
156 case ETHOSN_FNUM_IS_SEC:
157 SMC_RET1(handle, ethosn_is_sec(core_addr));
158 case ETHOSN_FNUM_HARD_RESET:
159 hard_reset = 1;
160 /* Fallthrough */
161 case ETHOSN_FNUM_SOFT_RESET:
162 if (!ethosn_reset(core_addr, hard_reset)) {
163 SMC_RET1(handle, ETHOSN_FAILURE);
164 }
165 ethosn_delegate_to_ns(core_addr);
166 SMC_RET1(handle, ETHOSN_SUCCESS);
167 default:
168 SMC_RET1(handle, SMC_UNK);
169 }
170 }
171