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