xref: /rk3399_ARM-atf/drivers/arm/ethosn/ethosn_smc.c (revision 2a2e3e87706b56fd1b8e787d3a552cfc12725934)
176a21174SMikael Olsson /*
2fa37d308SJoshua Pimm  * Copyright (c) 2021-2023, Arm Limited. All rights reserved.
376a21174SMikael Olsson  *
476a21174SMikael Olsson  * SPDX-License-Identifier: BSD-3-Clause
576a21174SMikael Olsson  */
676a21174SMikael Olsson 
776a21174SMikael Olsson #include <stdint.h>
876a21174SMikael Olsson #include <stdbool.h>
976a21174SMikael Olsson 
1076a21174SMikael Olsson #include <common/debug.h>
1176a21174SMikael Olsson #include <common/runtime_svc.h>
1276a21174SMikael Olsson #include <drivers/arm/ethosn.h>
1376a21174SMikael Olsson #include <drivers/delay_timer.h>
1476a21174SMikael Olsson #include <lib/mmio.h>
15b139f1cfSMikael Olsson #include <lib/utils_def.h>
1676a21174SMikael Olsson #include <plat/arm/common/fconf_ethosn_getter.h>
1776a21174SMikael Olsson 
181c65989eSLaurent Carlier /*
19b139f1cfSMikael Olsson  * Number of Arm(R) Ethos(TM)-N NPU (NPU) devices available
201c65989eSLaurent Carlier  */
21b139f1cfSMikael Olsson #define ETHOSN_NUM_DEVICES \
22b139f1cfSMikael Olsson 	FCONF_GET_PROPERTY(hw_config, ethosn_config, num_devices)
2376a21174SMikael Olsson 
24b139f1cfSMikael Olsson #define ETHOSN_GET_DEVICE(dev_idx) \
25b139f1cfSMikael Olsson 	FCONF_GET_PROPERTY(hw_config, ethosn_device, dev_idx)
2676a21174SMikael Olsson 
2776a21174SMikael Olsson /* NPU core sec registry address */
2876a21174SMikael Olsson #define ETHOSN_CORE_SEC_REG(core_addr, reg_offset) \
2976a21174SMikael Olsson 	(core_addr + reg_offset)
3076a21174SMikael Olsson 
3176a21174SMikael Olsson /* Reset timeout in us */
3276a21174SMikael Olsson #define ETHOSN_RESET_TIMEOUT_US		U(10 * 1000 * 1000)
3376a21174SMikael Olsson #define ETHOSN_RESET_WAIT_US		U(1)
3476a21174SMikael Olsson 
3576a21174SMikael Olsson #define SEC_DEL_REG			U(0x0004)
3676a21174SMikael Olsson #define SEC_DEL_VAL			U(0x81C)
3776a21174SMikael Olsson #define SEC_DEL_EXCC_MASK		U(0x20)
3876a21174SMikael Olsson 
3976a21174SMikael Olsson #define SEC_SECCTLR_REG			U(0x0010)
4076a21174SMikael Olsson #define SEC_SECCTLR_VAL			U(0x3)
4176a21174SMikael Olsson 
4276a21174SMikael Olsson #define SEC_DEL_ADDR_EXT_REG		U(0x201C)
4376a21174SMikael Olsson #define SEC_DEL_ADDR_EXT_VAL		U(0x15)
4476a21174SMikael Olsson 
4576a21174SMikael Olsson #define SEC_SYSCTRL0_REG		U(0x0018)
46*2a2e3e87SMikael Olsson #define SEC_SYSCTRL0_SLEEPING		U(1U << 4)
4776a21174SMikael Olsson #define SEC_SYSCTRL0_SOFT_RESET		U(3U << 29)
4876a21174SMikael Olsson #define SEC_SYSCTRL0_HARD_RESET		U(1U << 31)
4976a21174SMikael Olsson 
50b139f1cfSMikael Olsson #define SEC_MMUSID_REG_BASE		U(0x3008)
51b139f1cfSMikael Olsson #define SEC_MMUSID_OFFSET		U(0x1000)
52b139f1cfSMikael Olsson 
53b139f1cfSMikael Olsson static bool ethosn_get_device_and_core(uintptr_t core_addr,
54b139f1cfSMikael Olsson 				       const struct ethosn_device_t **dev_match,
55b139f1cfSMikael Olsson 				       const struct ethosn_core_t **core_match)
561c65989eSLaurent Carlier {
57b139f1cfSMikael Olsson 	uint32_t dev_idx;
58b139f1cfSMikael Olsson 	uint32_t core_idx;
59b139f1cfSMikael Olsson 
60b139f1cfSMikael Olsson 	for (dev_idx = 0U; dev_idx < ETHOSN_NUM_DEVICES; ++dev_idx) {
61b139f1cfSMikael Olsson 		const struct ethosn_device_t *dev = ETHOSN_GET_DEVICE(dev_idx);
62b139f1cfSMikael Olsson 
63b139f1cfSMikael Olsson 		for (core_idx = 0U; core_idx < dev->num_cores; ++core_idx) {
64b139f1cfSMikael Olsson 			const struct ethosn_core_t *core = &(dev->cores[core_idx]);
65b139f1cfSMikael Olsson 
66b139f1cfSMikael Olsson 			if (core->addr == core_addr) {
67b139f1cfSMikael Olsson 				*dev_match = dev;
68b139f1cfSMikael Olsson 				*core_match = core;
691c65989eSLaurent Carlier 				return true;
701c65989eSLaurent Carlier 			}
711c65989eSLaurent Carlier 		}
72b139f1cfSMikael Olsson 	}
731c65989eSLaurent Carlier 
74b139f1cfSMikael Olsson 	WARN("ETHOSN: Unknown core address given to SMC call.\n");
751c65989eSLaurent Carlier 	return false;
761c65989eSLaurent Carlier }
771c65989eSLaurent Carlier 
78b139f1cfSMikael Olsson static void ethosn_configure_smmu_streams(const struct ethosn_device_t *device,
79b139f1cfSMikael Olsson 					  const struct ethosn_core_t *core,
80b139f1cfSMikael Olsson 					  uint32_t asset_alloc_idx)
81b139f1cfSMikael Olsson {
82b139f1cfSMikael Olsson 	const struct ethosn_main_allocator_t *main_alloc =
83b139f1cfSMikael Olsson 		&(core->main_allocator);
84b139f1cfSMikael Olsson 	const struct ethosn_asset_allocator_t *asset_alloc =
85b139f1cfSMikael Olsson 		&(device->asset_allocators[asset_alloc_idx]);
86b139f1cfSMikael Olsson 	const uint32_t streams[9] = {
87b139f1cfSMikael Olsson 		main_alloc->firmware.stream_id,
88b139f1cfSMikael Olsson 		main_alloc->working_data.stream_id,
89b139f1cfSMikael Olsson 		asset_alloc->command_stream.stream_id,
90b139f1cfSMikael Olsson 		0U, /* Not used*/
91b139f1cfSMikael Olsson 		main_alloc->firmware.stream_id,
92b139f1cfSMikael Olsson 		asset_alloc->weight_data.stream_id,
93b139f1cfSMikael Olsson 		asset_alloc->buffer_data.stream_id,
94b139f1cfSMikael Olsson 		asset_alloc->intermediate_data.stream_id,
95b139f1cfSMikael Olsson 		asset_alloc->buffer_data.stream_id
96b139f1cfSMikael Olsson 	};
97b139f1cfSMikael Olsson 	size_t i;
98b139f1cfSMikael Olsson 
99b139f1cfSMikael Olsson 	for (i = 0U; i < ARRAY_SIZE(streams); ++i) {
100b139f1cfSMikael Olsson 		const uintptr_t reg_addr = SEC_MMUSID_REG_BASE +
101b139f1cfSMikael Olsson 			(SEC_MMUSID_OFFSET * i);
102b139f1cfSMikael Olsson 		mmio_write_32(ETHOSN_CORE_SEC_REG(core->addr, reg_addr),
103b139f1cfSMikael Olsson 			      streams[i]);
104b139f1cfSMikael Olsson 	}
105b139f1cfSMikael Olsson }
106b139f1cfSMikael Olsson 
10776a21174SMikael Olsson static void ethosn_delegate_to_ns(uintptr_t core_addr)
10876a21174SMikael Olsson {
10976a21174SMikael Olsson 	mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SECCTLR_REG),
11076a21174SMikael Olsson 			SEC_SECCTLR_VAL);
11176a21174SMikael Olsson 
11276a21174SMikael Olsson 	mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG),
11376a21174SMikael Olsson 			SEC_DEL_VAL);
11476a21174SMikael Olsson 
11576a21174SMikael Olsson 	mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_ADDR_EXT_REG),
11676a21174SMikael Olsson 			SEC_DEL_ADDR_EXT_VAL);
11776a21174SMikael Olsson }
11876a21174SMikael Olsson 
1191c65989eSLaurent Carlier static int ethosn_is_sec(uintptr_t core_addr)
12076a21174SMikael Olsson {
1211c65989eSLaurent Carlier 	if ((mmio_read_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG))
12276a21174SMikael Olsson 		& SEC_DEL_EXCC_MASK) != 0U) {
12376a21174SMikael Olsson 		return 0;
12476a21174SMikael Olsson 	}
12576a21174SMikael Olsson 
12676a21174SMikael Olsson 	return 1;
12776a21174SMikael Olsson }
12876a21174SMikael Olsson 
129*2a2e3e87SMikael Olsson static int ethosn_core_is_sleeping(uintptr_t core_addr)
130*2a2e3e87SMikael Olsson {
131*2a2e3e87SMikael Olsson 	const uintptr_t sysctrl0_reg =
132*2a2e3e87SMikael Olsson 		ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG);
133*2a2e3e87SMikael Olsson 	const uint32_t sleeping_mask = SEC_SYSCTRL0_SLEEPING;
134*2a2e3e87SMikael Olsson 
135*2a2e3e87SMikael Olsson 	return ((mmio_read_32(sysctrl0_reg) & sleeping_mask) == sleeping_mask);
136*2a2e3e87SMikael Olsson }
137*2a2e3e87SMikael Olsson 
13876a21174SMikael Olsson static bool ethosn_reset(uintptr_t core_addr, int hard_reset)
13976a21174SMikael Olsson {
14076a21174SMikael Olsson 	unsigned int timeout;
14176a21174SMikael Olsson 	const uintptr_t sysctrl0_reg =
14276a21174SMikael Olsson 		ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG);
14376a21174SMikael Olsson 	const uint32_t reset_val = (hard_reset != 0) ? SEC_SYSCTRL0_HARD_RESET
14476a21174SMikael Olsson 						    : SEC_SYSCTRL0_SOFT_RESET;
14576a21174SMikael Olsson 
14676a21174SMikael Olsson 	mmio_write_32(sysctrl0_reg, reset_val);
14776a21174SMikael Olsson 
14876a21174SMikael Olsson 	/* Wait for reset to complete */
14976a21174SMikael Olsson 	for (timeout = 0U; timeout < ETHOSN_RESET_TIMEOUT_US;
15076a21174SMikael Olsson 			   timeout += ETHOSN_RESET_WAIT_US) {
15176a21174SMikael Olsson 
15276a21174SMikael Olsson 		if ((mmio_read_32(sysctrl0_reg) & reset_val) == 0U) {
15376a21174SMikael Olsson 			break;
15476a21174SMikael Olsson 		}
15576a21174SMikael Olsson 
15676a21174SMikael Olsson 		udelay(ETHOSN_RESET_WAIT_US);
15776a21174SMikael Olsson 	}
15876a21174SMikael Olsson 
15976a21174SMikael Olsson 	return timeout < ETHOSN_RESET_TIMEOUT_US;
16076a21174SMikael Olsson }
16176a21174SMikael Olsson 
16276a21174SMikael Olsson uintptr_t ethosn_smc_handler(uint32_t smc_fid,
1631c65989eSLaurent Carlier 			     u_register_t core_addr,
164b139f1cfSMikael Olsson 			     u_register_t asset_alloc_idx,
165fa37d308SJoshua Pimm 			     u_register_t reset_type,
16676a21174SMikael Olsson 			     u_register_t x4,
16776a21174SMikael Olsson 			     void *cookie,
16876a21174SMikael Olsson 			     void *handle,
16976a21174SMikael Olsson 			     u_register_t flags)
17076a21174SMikael Olsson {
17176a21174SMikael Olsson 	int hard_reset = 0;
172b139f1cfSMikael Olsson 	const struct ethosn_device_t *device = NULL;
173b139f1cfSMikael Olsson 	const struct ethosn_core_t *core = NULL;
1741c65989eSLaurent Carlier 	const uint32_t fid = smc_fid & FUNCID_NUM_MASK;
17576a21174SMikael Olsson 
17676a21174SMikael Olsson 	/* Only SiP fast calls are expected */
17776a21174SMikael Olsson 	if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
17876a21174SMikael Olsson 		(GET_SMC_OEN(smc_fid) != OEN_SIP_START)) {
17976a21174SMikael Olsson 		SMC_RET1(handle, SMC_UNK);
18076a21174SMikael Olsson 	}
18176a21174SMikael Olsson 
18276a21174SMikael Olsson 	/* Truncate parameters to 32-bits for SMC32 */
18376a21174SMikael Olsson 	if (GET_SMC_CC(smc_fid) == SMC_32) {
1841c65989eSLaurent Carlier 		core_addr &= 0xFFFFFFFF;
185b139f1cfSMikael Olsson 		asset_alloc_idx &= 0xFFFFFFFF;
186fa37d308SJoshua Pimm 		reset_type &= 0xFFFFFFFF;
18776a21174SMikael Olsson 		x4 &= 0xFFFFFFFF;
18876a21174SMikael Olsson 	}
18976a21174SMikael Olsson 
190*2a2e3e87SMikael Olsson 	if (!is_ethosn_fid(smc_fid) || (fid > ETHOSN_FNUM_IS_SLEEPING)) {
191b139f1cfSMikael Olsson 		WARN("ETHOSN: Unknown SMC call: 0x%x\n", smc_fid);
19276a21174SMikael Olsson 		SMC_RET1(handle, SMC_UNK);
19376a21174SMikael Olsson 	}
19476a21174SMikael Olsson 
1951c65989eSLaurent Carlier 	/* Commands that do not require a valid core address */
1961c65989eSLaurent Carlier 	switch (fid) {
19776a21174SMikael Olsson 	case ETHOSN_FNUM_VERSION:
19876a21174SMikael Olsson 		SMC_RET2(handle, ETHOSN_VERSION_MAJOR, ETHOSN_VERSION_MINOR);
1991c65989eSLaurent Carlier 	}
2001c65989eSLaurent Carlier 
201b139f1cfSMikael Olsson 	if (!ethosn_get_device_and_core(core_addr, &device, &core))  {
2021c65989eSLaurent Carlier 		SMC_RET1(handle, ETHOSN_UNKNOWN_CORE_ADDRESS);
2031c65989eSLaurent Carlier 	}
2041c65989eSLaurent Carlier 
205b139f1cfSMikael Olsson 	/* Commands that require a valid core address */
2061c65989eSLaurent Carlier 	switch (fid) {
20776a21174SMikael Olsson 	case ETHOSN_FNUM_IS_SEC:
208b139f1cfSMikael Olsson 		SMC_RET1(handle, ethosn_is_sec(core->addr));
209*2a2e3e87SMikael Olsson 	case ETHOSN_FNUM_IS_SLEEPING:
210*2a2e3e87SMikael Olsson 		SMC_RET1(handle, ethosn_core_is_sleeping(core->addr));
211b139f1cfSMikael Olsson 	}
212b139f1cfSMikael Olsson 
213b139f1cfSMikael Olsson 	if (!device->has_reserved_memory &&
214b139f1cfSMikael Olsson 	    asset_alloc_idx >= device->num_allocators) {
215b139f1cfSMikael Olsson 		WARN("ETHOSN: Unknown asset allocator index given to SMC call.\n");
216b139f1cfSMikael Olsson 		SMC_RET1(handle, ETHOSN_UNKNOWN_ALLOCATOR_IDX);
217b139f1cfSMikael Olsson 	}
218b139f1cfSMikael Olsson 
219fa37d308SJoshua Pimm 	if (reset_type > ETHOSN_RESET_TYPE_HALT) {
220fa37d308SJoshua Pimm 		WARN("ETHOSN: Invalid reset type given to SMC call.\n");
221fa37d308SJoshua Pimm 		SMC_RET1(handle, ETHOSN_INVALID_PARAMETER);
222fa37d308SJoshua Pimm 	}
223fa37d308SJoshua Pimm 
224fa37d308SJoshua Pimm 	/*
225fa37d308SJoshua Pimm 	 * Commands that require a valid device, reset type,
226fa37d308SJoshua Pimm 	 * core and asset allocator
227fa37d308SJoshua Pimm 	 */
228b139f1cfSMikael Olsson 	switch (fid) {
22976a21174SMikael Olsson 	case ETHOSN_FNUM_HARD_RESET:
23076a21174SMikael Olsson 		hard_reset = 1;
23176a21174SMikael Olsson 		/* Fallthrough */
23276a21174SMikael Olsson 	case ETHOSN_FNUM_SOFT_RESET:
233b139f1cfSMikael Olsson 		if (!ethosn_reset(core->addr, hard_reset)) {
23476a21174SMikael Olsson 			SMC_RET1(handle, ETHOSN_FAILURE);
23576a21174SMikael Olsson 		}
236b139f1cfSMikael Olsson 
237fa37d308SJoshua Pimm 		if (reset_type == ETHOSN_RESET_TYPE_FULL) {
238b139f1cfSMikael Olsson 			if (!device->has_reserved_memory) {
239b139f1cfSMikael Olsson 				ethosn_configure_smmu_streams(device, core,
240b139f1cfSMikael Olsson 							asset_alloc_idx);
241b139f1cfSMikael Olsson 			}
242b139f1cfSMikael Olsson 
243b139f1cfSMikael Olsson 			ethosn_delegate_to_ns(core->addr);
244fa37d308SJoshua Pimm 		}
24576a21174SMikael Olsson 		SMC_RET1(handle, ETHOSN_SUCCESS);
24676a21174SMikael Olsson 	default:
247b139f1cfSMikael Olsson 		WARN("ETHOSN: Unimplemented SMC call: 0x%x\n", fid);
24876a21174SMikael Olsson 		SMC_RET1(handle, SMC_UNK);
24976a21174SMikael Olsson 	}
25076a21174SMikael Olsson }
251