1 /*
2 * Copyright (c) 2021-2022, 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 <lib/utils_def.h>
16 #include <plat/arm/common/fconf_ethosn_getter.h>
17
18 /*
19 * Number of Arm(R) Ethos(TM)-N NPU (NPU) devices available
20 */
21 #define ETHOSN_NUM_DEVICES \
22 FCONF_GET_PROPERTY(hw_config, ethosn_config, num_devices)
23
24 #define ETHOSN_GET_DEVICE(dev_idx) \
25 FCONF_GET_PROPERTY(hw_config, ethosn_device, dev_idx)
26
27 /* NPU core sec registry address */
28 #define ETHOSN_CORE_SEC_REG(core_addr, reg_offset) \
29 (core_addr + reg_offset)
30
31 /* Reset timeout in us */
32 #define ETHOSN_RESET_TIMEOUT_US U(10 * 1000 * 1000)
33 #define ETHOSN_RESET_WAIT_US U(1)
34
35 #define SEC_DEL_REG U(0x0004)
36 #define SEC_DEL_VAL U(0x81C)
37 #define SEC_DEL_EXCC_MASK U(0x20)
38
39 #define SEC_SECCTLR_REG U(0x0010)
40 #define SEC_SECCTLR_VAL U(0x3)
41
42 #define SEC_DEL_ADDR_EXT_REG U(0x201C)
43 #define SEC_DEL_ADDR_EXT_VAL U(0x15)
44
45 #define SEC_SYSCTRL0_REG U(0x0018)
46 #define SEC_SYSCTRL0_SOFT_RESET U(3U << 29)
47 #define SEC_SYSCTRL0_HARD_RESET U(1U << 31)
48
49 #define SEC_MMUSID_REG_BASE U(0x3008)
50 #define SEC_MMUSID_OFFSET U(0x1000)
51
ethosn_get_device_and_core(uintptr_t core_addr,const struct ethosn_device_t ** dev_match,const struct ethosn_core_t ** core_match)52 static bool ethosn_get_device_and_core(uintptr_t core_addr,
53 const struct ethosn_device_t **dev_match,
54 const struct ethosn_core_t **core_match)
55 {
56 uint32_t dev_idx;
57 uint32_t core_idx;
58
59 for (dev_idx = 0U; dev_idx < ETHOSN_NUM_DEVICES; ++dev_idx) {
60 const struct ethosn_device_t *dev = ETHOSN_GET_DEVICE(dev_idx);
61
62 for (core_idx = 0U; core_idx < dev->num_cores; ++core_idx) {
63 const struct ethosn_core_t *core = &(dev->cores[core_idx]);
64
65 if (core->addr == core_addr) {
66 *dev_match = dev;
67 *core_match = core;
68 return true;
69 }
70 }
71 }
72
73 WARN("ETHOSN: Unknown core address given to SMC call.\n");
74 return false;
75 }
76
ethosn_configure_smmu_streams(const struct ethosn_device_t * device,const struct ethosn_core_t * core,uint32_t asset_alloc_idx)77 static void ethosn_configure_smmu_streams(const struct ethosn_device_t *device,
78 const struct ethosn_core_t *core,
79 uint32_t asset_alloc_idx)
80 {
81 const struct ethosn_main_allocator_t *main_alloc =
82 &(core->main_allocator);
83 const struct ethosn_asset_allocator_t *asset_alloc =
84 &(device->asset_allocators[asset_alloc_idx]);
85 const uint32_t streams[9] = {
86 main_alloc->firmware.stream_id,
87 main_alloc->working_data.stream_id,
88 asset_alloc->command_stream.stream_id,
89 0U, /* Not used*/
90 main_alloc->firmware.stream_id,
91 asset_alloc->weight_data.stream_id,
92 asset_alloc->buffer_data.stream_id,
93 asset_alloc->intermediate_data.stream_id,
94 asset_alloc->buffer_data.stream_id
95 };
96 size_t i;
97
98 for (i = 0U; i < ARRAY_SIZE(streams); ++i) {
99 const uintptr_t reg_addr = SEC_MMUSID_REG_BASE +
100 (SEC_MMUSID_OFFSET * i);
101 mmio_write_32(ETHOSN_CORE_SEC_REG(core->addr, reg_addr),
102 streams[i]);
103 }
104 }
105
ethosn_delegate_to_ns(uintptr_t core_addr)106 static void ethosn_delegate_to_ns(uintptr_t core_addr)
107 {
108 mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SECCTLR_REG),
109 SEC_SECCTLR_VAL);
110
111 mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG),
112 SEC_DEL_VAL);
113
114 mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_ADDR_EXT_REG),
115 SEC_DEL_ADDR_EXT_VAL);
116 }
117
ethosn_is_sec(uintptr_t core_addr)118 static int ethosn_is_sec(uintptr_t core_addr)
119 {
120 if ((mmio_read_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG))
121 & SEC_DEL_EXCC_MASK) != 0U) {
122 return 0;
123 }
124
125 return 1;
126 }
127
ethosn_reset(uintptr_t core_addr,int hard_reset)128 static bool ethosn_reset(uintptr_t core_addr, int hard_reset)
129 {
130 unsigned int timeout;
131 const uintptr_t sysctrl0_reg =
132 ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG);
133 const uint32_t reset_val = (hard_reset != 0) ? SEC_SYSCTRL0_HARD_RESET
134 : SEC_SYSCTRL0_SOFT_RESET;
135
136 mmio_write_32(sysctrl0_reg, reset_val);
137
138 /* Wait for reset to complete */
139 for (timeout = 0U; timeout < ETHOSN_RESET_TIMEOUT_US;
140 timeout += ETHOSN_RESET_WAIT_US) {
141
142 if ((mmio_read_32(sysctrl0_reg) & reset_val) == 0U) {
143 break;
144 }
145
146 udelay(ETHOSN_RESET_WAIT_US);
147 }
148
149 return timeout < ETHOSN_RESET_TIMEOUT_US;
150 }
151
ethosn_smc_handler(uint32_t smc_fid,u_register_t core_addr,u_register_t asset_alloc_idx,u_register_t x3,u_register_t x4,void * cookie,void * handle,u_register_t flags)152 uintptr_t ethosn_smc_handler(uint32_t smc_fid,
153 u_register_t core_addr,
154 u_register_t asset_alloc_idx,
155 u_register_t x3,
156 u_register_t x4,
157 void *cookie,
158 void *handle,
159 u_register_t flags)
160 {
161 int hard_reset = 0;
162 const struct ethosn_device_t *device = NULL;
163 const struct ethosn_core_t *core = NULL;
164 const uint32_t fid = smc_fid & FUNCID_NUM_MASK;
165
166 /* Only SiP fast calls are expected */
167 if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
168 (GET_SMC_OEN(smc_fid) != OEN_SIP_START)) {
169 SMC_RET1(handle, SMC_UNK);
170 }
171
172 /* Truncate parameters to 32-bits for SMC32 */
173 if (GET_SMC_CC(smc_fid) == SMC_32) {
174 core_addr &= 0xFFFFFFFF;
175 asset_alloc_idx &= 0xFFFFFFFF;
176 x3 &= 0xFFFFFFFF;
177 x4 &= 0xFFFFFFFF;
178 }
179
180 if (!is_ethosn_fid(smc_fid) ||
181 (fid < ETHOSN_FNUM_VERSION || fid > ETHOSN_FNUM_SOFT_RESET)) {
182 WARN("ETHOSN: Unknown SMC call: 0x%x\n", smc_fid);
183 SMC_RET1(handle, SMC_UNK);
184 }
185
186 /* Commands that do not require a valid core address */
187 switch (fid) {
188 case ETHOSN_FNUM_VERSION:
189 SMC_RET2(handle, ETHOSN_VERSION_MAJOR, ETHOSN_VERSION_MINOR);
190 }
191
192 if (!ethosn_get_device_and_core(core_addr, &device, &core)) {
193 SMC_RET1(handle, ETHOSN_UNKNOWN_CORE_ADDRESS);
194 }
195
196 /* Commands that require a valid core address */
197 switch (fid) {
198 case ETHOSN_FNUM_IS_SEC:
199 SMC_RET1(handle, ethosn_is_sec(core->addr));
200 }
201
202 if (!device->has_reserved_memory &&
203 asset_alloc_idx >= device->num_allocators) {
204 WARN("ETHOSN: Unknown asset allocator index given to SMC call.\n");
205 SMC_RET1(handle, ETHOSN_UNKNOWN_ALLOCATOR_IDX);
206 }
207
208 /* Commands that require a valid device, core and asset allocator */
209 switch (fid) {
210 case ETHOSN_FNUM_HARD_RESET:
211 hard_reset = 1;
212 /* Fallthrough */
213 case ETHOSN_FNUM_SOFT_RESET:
214 if (!ethosn_reset(core->addr, hard_reset)) {
215 SMC_RET1(handle, ETHOSN_FAILURE);
216 }
217
218 if (!device->has_reserved_memory) {
219 ethosn_configure_smmu_streams(device, core,
220 asset_alloc_idx);
221 }
222
223 ethosn_delegate_to_ns(core->addr);
224 SMC_RET1(handle, ETHOSN_SUCCESS);
225 default:
226 WARN("ETHOSN: Unimplemented SMC call: 0x%x\n", fid);
227 SMC_RET1(handle, SMC_UNK);
228 }
229 }
230