xref: /rk3399_ARM-atf/drivers/arm/ethosn/ethosn_smc.c (revision b139f1cf975f9968eb8bd1182a173b976ecf06f9)
176a21174SMikael Olsson /*
2*b139f1cfSMikael Olsson  * Copyright (c) 2021-2022, 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>
15*b139f1cfSMikael Olsson #include <lib/utils_def.h>
1676a21174SMikael Olsson #include <plat/arm/common/fconf_ethosn_getter.h>
1776a21174SMikael Olsson 
181c65989eSLaurent Carlier /*
19*b139f1cfSMikael Olsson  * Number of Arm(R) Ethos(TM)-N NPU (NPU) devices available
201c65989eSLaurent Carlier  */
21*b139f1cfSMikael Olsson #define ETHOSN_NUM_DEVICES \
22*b139f1cfSMikael Olsson 	FCONF_GET_PROPERTY(hw_config, ethosn_config, num_devices)
2376a21174SMikael Olsson 
24*b139f1cfSMikael Olsson #define ETHOSN_GET_DEVICE(dev_idx) \
25*b139f1cfSMikael 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)
4676a21174SMikael Olsson #define SEC_SYSCTRL0_SOFT_RESET		U(3U << 29)
4776a21174SMikael Olsson #define SEC_SYSCTRL0_HARD_RESET		U(1U << 31)
4876a21174SMikael Olsson 
49*b139f1cfSMikael Olsson #define SEC_MMUSID_REG_BASE		U(0x3008)
50*b139f1cfSMikael Olsson #define SEC_MMUSID_OFFSET		U(0x1000)
51*b139f1cfSMikael Olsson 
52*b139f1cfSMikael Olsson static bool ethosn_get_device_and_core(uintptr_t core_addr,
53*b139f1cfSMikael Olsson 				       const struct ethosn_device_t **dev_match,
54*b139f1cfSMikael Olsson 				       const struct ethosn_core_t **core_match)
551c65989eSLaurent Carlier {
56*b139f1cfSMikael Olsson 	uint32_t dev_idx;
57*b139f1cfSMikael Olsson 	uint32_t core_idx;
58*b139f1cfSMikael Olsson 
59*b139f1cfSMikael Olsson 	for (dev_idx = 0U; dev_idx < ETHOSN_NUM_DEVICES; ++dev_idx) {
60*b139f1cfSMikael Olsson 		const struct ethosn_device_t *dev = ETHOSN_GET_DEVICE(dev_idx);
61*b139f1cfSMikael Olsson 
62*b139f1cfSMikael Olsson 		for (core_idx = 0U; core_idx < dev->num_cores; ++core_idx) {
63*b139f1cfSMikael Olsson 			const struct ethosn_core_t *core = &(dev->cores[core_idx]);
64*b139f1cfSMikael Olsson 
65*b139f1cfSMikael Olsson 			if (core->addr == core_addr) {
66*b139f1cfSMikael Olsson 				*dev_match = dev;
67*b139f1cfSMikael Olsson 				*core_match = core;
681c65989eSLaurent Carlier 				return true;
691c65989eSLaurent Carlier 			}
701c65989eSLaurent Carlier 		}
71*b139f1cfSMikael Olsson 	}
721c65989eSLaurent Carlier 
73*b139f1cfSMikael Olsson 	WARN("ETHOSN: Unknown core address given to SMC call.\n");
741c65989eSLaurent Carlier 	return false;
751c65989eSLaurent Carlier }
761c65989eSLaurent Carlier 
77*b139f1cfSMikael Olsson static void ethosn_configure_smmu_streams(const struct ethosn_device_t *device,
78*b139f1cfSMikael Olsson 					  const struct ethosn_core_t *core,
79*b139f1cfSMikael Olsson 					  uint32_t asset_alloc_idx)
80*b139f1cfSMikael Olsson {
81*b139f1cfSMikael Olsson 	const struct ethosn_main_allocator_t *main_alloc =
82*b139f1cfSMikael Olsson 		&(core->main_allocator);
83*b139f1cfSMikael Olsson 	const struct ethosn_asset_allocator_t *asset_alloc =
84*b139f1cfSMikael Olsson 		&(device->asset_allocators[asset_alloc_idx]);
85*b139f1cfSMikael Olsson 	const uint32_t streams[9] = {
86*b139f1cfSMikael Olsson 		main_alloc->firmware.stream_id,
87*b139f1cfSMikael Olsson 		main_alloc->working_data.stream_id,
88*b139f1cfSMikael Olsson 		asset_alloc->command_stream.stream_id,
89*b139f1cfSMikael Olsson 		0U, /* Not used*/
90*b139f1cfSMikael Olsson 		main_alloc->firmware.stream_id,
91*b139f1cfSMikael Olsson 		asset_alloc->weight_data.stream_id,
92*b139f1cfSMikael Olsson 		asset_alloc->buffer_data.stream_id,
93*b139f1cfSMikael Olsson 		asset_alloc->intermediate_data.stream_id,
94*b139f1cfSMikael Olsson 		asset_alloc->buffer_data.stream_id
95*b139f1cfSMikael Olsson 	};
96*b139f1cfSMikael Olsson 	size_t i;
97*b139f1cfSMikael Olsson 
98*b139f1cfSMikael Olsson 	for (i = 0U; i < ARRAY_SIZE(streams); ++i) {
99*b139f1cfSMikael Olsson 		const uintptr_t reg_addr = SEC_MMUSID_REG_BASE +
100*b139f1cfSMikael Olsson 			(SEC_MMUSID_OFFSET * i);
101*b139f1cfSMikael Olsson 		mmio_write_32(ETHOSN_CORE_SEC_REG(core->addr, reg_addr),
102*b139f1cfSMikael Olsson 			      streams[i]);
103*b139f1cfSMikael Olsson 	}
104*b139f1cfSMikael Olsson }
105*b139f1cfSMikael Olsson 
10676a21174SMikael Olsson static void ethosn_delegate_to_ns(uintptr_t core_addr)
10776a21174SMikael Olsson {
10876a21174SMikael Olsson 	mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_SECCTLR_REG),
10976a21174SMikael Olsson 			SEC_SECCTLR_VAL);
11076a21174SMikael Olsson 
11176a21174SMikael Olsson 	mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG),
11276a21174SMikael Olsson 			SEC_DEL_VAL);
11376a21174SMikael Olsson 
11476a21174SMikael Olsson 	mmio_setbits_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_ADDR_EXT_REG),
11576a21174SMikael Olsson 			SEC_DEL_ADDR_EXT_VAL);
11676a21174SMikael Olsson }
11776a21174SMikael Olsson 
1181c65989eSLaurent Carlier static int ethosn_is_sec(uintptr_t core_addr)
11976a21174SMikael Olsson {
1201c65989eSLaurent Carlier 	if ((mmio_read_32(ETHOSN_CORE_SEC_REG(core_addr, SEC_DEL_REG))
12176a21174SMikael Olsson 		& SEC_DEL_EXCC_MASK) != 0U) {
12276a21174SMikael Olsson 		return 0;
12376a21174SMikael Olsson 	}
12476a21174SMikael Olsson 
12576a21174SMikael Olsson 	return 1;
12676a21174SMikael Olsson }
12776a21174SMikael Olsson 
12876a21174SMikael Olsson static bool ethosn_reset(uintptr_t core_addr, int hard_reset)
12976a21174SMikael Olsson {
13076a21174SMikael Olsson 	unsigned int timeout;
13176a21174SMikael Olsson 	const uintptr_t sysctrl0_reg =
13276a21174SMikael Olsson 		ETHOSN_CORE_SEC_REG(core_addr, SEC_SYSCTRL0_REG);
13376a21174SMikael Olsson 	const uint32_t reset_val = (hard_reset != 0) ? SEC_SYSCTRL0_HARD_RESET
13476a21174SMikael Olsson 						    : SEC_SYSCTRL0_SOFT_RESET;
13576a21174SMikael Olsson 
13676a21174SMikael Olsson 	mmio_write_32(sysctrl0_reg, reset_val);
13776a21174SMikael Olsson 
13876a21174SMikael Olsson 	/* Wait for reset to complete */
13976a21174SMikael Olsson 	for (timeout = 0U; timeout < ETHOSN_RESET_TIMEOUT_US;
14076a21174SMikael Olsson 			   timeout += ETHOSN_RESET_WAIT_US) {
14176a21174SMikael Olsson 
14276a21174SMikael Olsson 		if ((mmio_read_32(sysctrl0_reg) & reset_val) == 0U) {
14376a21174SMikael Olsson 			break;
14476a21174SMikael Olsson 		}
14576a21174SMikael Olsson 
14676a21174SMikael Olsson 		udelay(ETHOSN_RESET_WAIT_US);
14776a21174SMikael Olsson 	}
14876a21174SMikael Olsson 
14976a21174SMikael Olsson 	return timeout < ETHOSN_RESET_TIMEOUT_US;
15076a21174SMikael Olsson }
15176a21174SMikael Olsson 
15276a21174SMikael Olsson uintptr_t ethosn_smc_handler(uint32_t smc_fid,
1531c65989eSLaurent Carlier 			     u_register_t core_addr,
154*b139f1cfSMikael Olsson 			     u_register_t asset_alloc_idx,
15576a21174SMikael Olsson 			     u_register_t x3,
15676a21174SMikael Olsson 			     u_register_t x4,
15776a21174SMikael Olsson 			     void *cookie,
15876a21174SMikael Olsson 			     void *handle,
15976a21174SMikael Olsson 			     u_register_t flags)
16076a21174SMikael Olsson {
16176a21174SMikael Olsson 	int hard_reset = 0;
162*b139f1cfSMikael Olsson 	const struct ethosn_device_t *device = NULL;
163*b139f1cfSMikael Olsson 	const struct ethosn_core_t *core = NULL;
1641c65989eSLaurent Carlier 	const uint32_t fid = smc_fid & FUNCID_NUM_MASK;
16576a21174SMikael Olsson 
16676a21174SMikael Olsson 	/* Only SiP fast calls are expected */
16776a21174SMikael Olsson 	if ((GET_SMC_TYPE(smc_fid) != SMC_TYPE_FAST) ||
16876a21174SMikael Olsson 		(GET_SMC_OEN(smc_fid) != OEN_SIP_START)) {
16976a21174SMikael Olsson 		SMC_RET1(handle, SMC_UNK);
17076a21174SMikael Olsson 	}
17176a21174SMikael Olsson 
17276a21174SMikael Olsson 	/* Truncate parameters to 32-bits for SMC32 */
17376a21174SMikael Olsson 	if (GET_SMC_CC(smc_fid) == SMC_32) {
1741c65989eSLaurent Carlier 		core_addr &= 0xFFFFFFFF;
175*b139f1cfSMikael Olsson 		asset_alloc_idx &= 0xFFFFFFFF;
17676a21174SMikael Olsson 		x3 &= 0xFFFFFFFF;
17776a21174SMikael Olsson 		x4 &= 0xFFFFFFFF;
17876a21174SMikael Olsson 	}
17976a21174SMikael Olsson 
180*b139f1cfSMikael Olsson 	if (!is_ethosn_fid(smc_fid) ||
181*b139f1cfSMikael Olsson 	    (fid < ETHOSN_FNUM_VERSION || fid > ETHOSN_FNUM_SOFT_RESET)) {
182*b139f1cfSMikael Olsson 		WARN("ETHOSN: Unknown SMC call: 0x%x\n", smc_fid);
18376a21174SMikael Olsson 		SMC_RET1(handle, SMC_UNK);
18476a21174SMikael Olsson 	}
18576a21174SMikael Olsson 
1861c65989eSLaurent Carlier 	/* Commands that do not require a valid core address */
1871c65989eSLaurent Carlier 	switch (fid) {
18876a21174SMikael Olsson 	case ETHOSN_FNUM_VERSION:
18976a21174SMikael Olsson 		SMC_RET2(handle, ETHOSN_VERSION_MAJOR, ETHOSN_VERSION_MINOR);
1901c65989eSLaurent Carlier 	}
1911c65989eSLaurent Carlier 
192*b139f1cfSMikael Olsson 	if (!ethosn_get_device_and_core(core_addr, &device, &core))  {
1931c65989eSLaurent Carlier 		SMC_RET1(handle, ETHOSN_UNKNOWN_CORE_ADDRESS);
1941c65989eSLaurent Carlier 	}
1951c65989eSLaurent Carlier 
196*b139f1cfSMikael Olsson 	/* Commands that require a valid core address */
1971c65989eSLaurent Carlier 	switch (fid) {
19876a21174SMikael Olsson 	case ETHOSN_FNUM_IS_SEC:
199*b139f1cfSMikael Olsson 		SMC_RET1(handle, ethosn_is_sec(core->addr));
200*b139f1cfSMikael Olsson 	}
201*b139f1cfSMikael Olsson 
202*b139f1cfSMikael Olsson 	if (!device->has_reserved_memory &&
203*b139f1cfSMikael Olsson 	    asset_alloc_idx >= device->num_allocators) {
204*b139f1cfSMikael Olsson 		WARN("ETHOSN: Unknown asset allocator index given to SMC call.\n");
205*b139f1cfSMikael Olsson 		SMC_RET1(handle, ETHOSN_UNKNOWN_ALLOCATOR_IDX);
206*b139f1cfSMikael Olsson 	}
207*b139f1cfSMikael Olsson 
208*b139f1cfSMikael Olsson 	/* Commands that require a valid device, core and asset allocator */
209*b139f1cfSMikael Olsson 	switch (fid) {
21076a21174SMikael Olsson 	case ETHOSN_FNUM_HARD_RESET:
21176a21174SMikael Olsson 		hard_reset = 1;
21276a21174SMikael Olsson 		/* Fallthrough */
21376a21174SMikael Olsson 	case ETHOSN_FNUM_SOFT_RESET:
214*b139f1cfSMikael Olsson 		if (!ethosn_reset(core->addr, hard_reset)) {
21576a21174SMikael Olsson 			SMC_RET1(handle, ETHOSN_FAILURE);
21676a21174SMikael Olsson 		}
217*b139f1cfSMikael Olsson 
218*b139f1cfSMikael Olsson 		if (!device->has_reserved_memory) {
219*b139f1cfSMikael Olsson 			ethosn_configure_smmu_streams(device, core,
220*b139f1cfSMikael Olsson 						      asset_alloc_idx);
221*b139f1cfSMikael Olsson 		}
222*b139f1cfSMikael Olsson 
223*b139f1cfSMikael Olsson 		ethosn_delegate_to_ns(core->addr);
22476a21174SMikael Olsson 		SMC_RET1(handle, ETHOSN_SUCCESS);
22576a21174SMikael Olsson 	default:
226*b139f1cfSMikael Olsson 		WARN("ETHOSN: Unimplemented SMC call: 0x%x\n", fid);
22776a21174SMikael Olsson 		SMC_RET1(handle, SMC_UNK);
22876a21174SMikael Olsson 	}
22976a21174SMikael Olsson }
230