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