xref: /rk3399_ARM-atf/plat/nvidia/tegra/common/tegra_sip_calls.c (revision 82cb2c1ad9897473743f08437d0a3995bed561b9)
1 /*
2  * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <arch.h>
8 #include <arch_helpers.h>
9 #include <assert.h>
10 #include <bl_common.h>
11 #include <debug.h>
12 #include <errno.h>
13 #include <memctrl.h>
14 #include <runtime_svc.h>
15 #include <tegra_private.h>
16 #include <tegra_platform.h>
17 
18 /*******************************************************************************
19  * Common Tegra SiP SMCs
20  ******************************************************************************/
21 #define TEGRA_SIP_NEW_VIDEOMEM_REGION		0x82000003
22 #define TEGRA_SIP_FIQ_NS_ENTRYPOINT		0x82000005
23 #define TEGRA_SIP_FIQ_NS_GET_CONTEXT		0x82000006
24 #define TEGRA_SIP_ENABLE_FAKE_SYSTEM_SUSPEND	0xC2000007
25 
26 /*******************************************************************************
27  * Fake system suspend mode control var
28  ******************************************************************************/
29 extern uint8_t tegra_fake_system_suspend;
30 
31 
32 /*******************************************************************************
33  * SoC specific SiP handler
34  ******************************************************************************/
35 #pragma weak plat_sip_handler
36 int plat_sip_handler(uint32_t smc_fid,
37 		     uint64_t x1,
38 		     uint64_t x2,
39 		     uint64_t x3,
40 		     uint64_t x4,
41 		     void *cookie,
42 		     void *handle,
43 		     uint64_t flags)
44 {
45 	return -ENOTSUP;
46 }
47 
48 /*******************************************************************************
49  * This function is responsible for handling all SiP calls
50  ******************************************************************************/
51 uint64_t tegra_sip_handler(uint32_t smc_fid,
52 			   uint64_t x1,
53 			   uint64_t x2,
54 			   uint64_t x3,
55 			   uint64_t x4,
56 			   void *cookie,
57 			   void *handle,
58 			   uint64_t flags)
59 {
60 	int err;
61 
62 	/* Check if this is a SoC specific SiP */
63 	err = plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
64 	if (err == 0)
65 		SMC_RET1(handle, (uint64_t)err);
66 
67 	switch (smc_fid) {
68 
69 	case TEGRA_SIP_NEW_VIDEOMEM_REGION:
70 
71 		/* clean up the high bits */
72 		x2 = (uint32_t)x2;
73 
74 		/*
75 		 * Check if Video Memory overlaps TZDRAM (contains bl31/bl32)
76 		 * or falls outside of the valid DRAM range
77 		 */
78 		err = bl31_check_ns_address(x1, x2);
79 		if (err)
80 			SMC_RET1(handle, err);
81 
82 		/*
83 		 * Check if Video Memory is aligned to 1MB.
84 		 */
85 		if ((x1 & 0xFFFFF) || (x2 & 0xFFFFF)) {
86 			ERROR("Unaligned Video Memory base address!\n");
87 			SMC_RET1(handle, -ENOTSUP);
88 		}
89 
90 		/* new video memory carveout settings */
91 		tegra_memctrl_videomem_setup(x1, x2);
92 
93 		SMC_RET1(handle, 0);
94 		break;
95 
96 	/*
97 	 * The NS world registers the address of its handler to be
98 	 * used for processing the FIQ. This is normally used by the
99 	 * NS FIQ debugger driver to detect system hangs by programming
100 	 * a watchdog timer to fire a FIQ interrupt.
101 	 */
102 	case TEGRA_SIP_FIQ_NS_ENTRYPOINT:
103 
104 		if (!x1)
105 			SMC_RET1(handle, SMC_UNK);
106 
107 		/*
108 		 * TODO: Check if x1 contains a valid DRAM address
109 		 */
110 
111 		/* store the NS world's entrypoint */
112 		tegra_fiq_set_ns_entrypoint(x1);
113 
114 		SMC_RET1(handle, 0);
115 		break;
116 
117 	/*
118 	 * The NS world's FIQ handler issues this SMC to get the NS EL1/EL0
119 	 * CPU context when the FIQ interrupt was triggered. This allows the
120 	 * NS world to understand the CPU state when the watchdog interrupt
121 	 * triggered.
122 	 */
123 	case TEGRA_SIP_FIQ_NS_GET_CONTEXT:
124 
125 		/* retrieve context registers when FIQ triggered */
126 		tegra_fiq_get_intr_context();
127 
128 		SMC_RET0(handle);
129 		break;
130 
131 	case TEGRA_SIP_ENABLE_FAKE_SYSTEM_SUSPEND:
132 		/*
133 		 * System suspend fake mode is set if we are on VDK and we make
134 		 * a debug SIP call. This mode ensures that we excercise debug
135 		 * path instead of the regular code path to suit the pre-silicon
136 		 * platform needs. These include replacing the call to WFI by
137 		 * a warm reset request.
138 		 */
139 		if (tegra_platform_is_emulation() != 0U) {
140 
141 			tegra_fake_system_suspend = 1;
142 			SMC_RET1(handle, 0);
143 		}
144 
145 		/*
146 		 * We return to the external world as if this SIP is not
147 		 * implemented in case, we are not running on VDK.
148 		 */
149 		break;
150 
151 	default:
152 		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
153 		break;
154 	}
155 
156 	SMC_RET1(handle, SMC_UNK);
157 }
158 
159 /* Define a runtime service descriptor for fast SMC calls */
160 DECLARE_RT_SVC(
161 	tegra_sip_fast,
162 
163 	OEN_SIP_START,
164 	OEN_SIP_END,
165 	SMC_TYPE_FAST,
166 	NULL,
167 	tegra_sip_handler
168 );
169