tegra_sip_calls.c 5.36 KB
Newer Older
1
/*
2
 * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
3
 *
dp-arm's avatar
dp-arm committed
4
 * SPDX-License-Identifier: BSD-3-Clause
5
6
7
8
 */

#include <assert.h>
#include <errno.h>
9
10
11
12
13
14
15
16

#include <arch.h>
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <lib/mmio.h>

17
#include <memctrl.h>
18
#include <tegra_platform.h>
19
#include <tegra_private.h>
20

21
/*******************************************************************************
22
 * Common Tegra SiP SMCs
23
 ******************************************************************************/
24
#define TEGRA_SIP_NEW_VIDEOMEM_REGION		0x82000003
25
26
#define TEGRA_SIP_FIQ_NS_ENTRYPOINT		0x82000005
#define TEGRA_SIP_FIQ_NS_GET_CONTEXT		0x82000006
27
28
29
30
31
32
33
#define TEGRA_SIP_ENABLE_FAKE_SYSTEM_SUSPEND	0xC2000007

/*******************************************************************************
 * Fake system suspend mode control var
 ******************************************************************************/
extern uint8_t tegra_fake_system_suspend;

34
35
36
37
/*******************************************************************************
 * SoC specific SiP handler
 ******************************************************************************/
#pragma weak plat_sip_handler
38
int32_t plat_sip_handler(uint32_t smc_fid,
39
40
41
42
		     uint64_t x1,
		     uint64_t x2,
		     uint64_t x3,
		     uint64_t x4,
43
		     const void *cookie,
44
45
46
		     void *handle,
		     uint64_t flags)
{
47
48
49
50
51
52
53
54
55
56
	/* unused parameters */
	(void)smc_fid;
	(void)x1;
	(void)x2;
	(void)x3;
	(void)x4;
	(void)cookie;
	(void)handle;
	(void)flags;

57
58
59
	return -ENOTSUP;
}

60
/*******************************************************************************
61
 * This function is responsible for handling all SiP calls
62
 ******************************************************************************/
63
64
65
66
67
68
69
70
uintptr_t tegra_sip_handler(uint32_t smc_fid,
			    u_register_t x1,
			    u_register_t x2,
			    u_register_t x3,
			    u_register_t x4,
			    void *cookie,
			    void *handle,
			    u_register_t flags)
71
{
72
	uint32_t regval, local_x2_32 = (uint32_t)x2;
73
	int32_t err;
74

75
76
	/* Check if this is a SoC specific SiP */
	err = plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
77
	if (err == 0) {
78

79
		SMC_RET1(handle, (uint64_t)err);
80

81
82
83
84
85
86
87
88
89
90
	} else {

		switch (smc_fid) {

		case TEGRA_SIP_NEW_VIDEOMEM_REGION:

			/*
			 * Check if Video Memory overlaps TZDRAM (contains bl31/bl32)
			 * or falls outside of the valid DRAM range
			*/
91
			err = bl31_check_ns_address(x1, local_x2_32);
92
93
94
95
96
97
98
			if (err != 0) {
				SMC_RET1(handle, (uint64_t)err);
			}

			/*
			 * Check if Video Memory is aligned to 1MB.
			 */
99
			if (((x1 & 0xFFFFFU) != 0U) || ((local_x2_32 & 0xFFFFFU) != 0U)) {
100
				ERROR("Unaligned Video Memory base address!\n");
101
				SMC_RET1(handle, (uint64_t)-ENOTSUP);
102
103
104
105
106
107
108
109
110
			}

			/*
			 * The GPU is the user of the Video Memory region. In order to
			 * transition to the new memory region smoothly, we program the
			 * new base/size ONLY if the GPU is in reset mode.
			 */
			regval = mmio_read_32(TEGRA_CAR_RESET_BASE +
					      TEGRA_GPU_RESET_REG_OFFSET);
111
			if ((regval & GPU_RESET_BIT) == 0U) {
112
				ERROR("GPU not in reset! Video Memory setup failed\n");
113
				SMC_RET1(handle, (uint64_t)-ENOTSUP);
114
115
116
			}

			/* new video memory carveout settings */
117
			tegra_memctrl_videomem_setup(x1, local_x2_32);
118

119
120
121
122
123
124
125
126
127
128
			/*
			 * Ensure again that GPU is still in reset after VPR resize
			 */
			regval = mmio_read_32(TEGRA_CAR_RESET_BASE +
					      TEGRA_GPU_RESET_REG_OFFSET);
			if ((regval & GPU_RESET_BIT) == 0U) {
				mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_GPU_SET_OFFSET,
									GPU_SET_BIT);
			}

129
			SMC_RET1(handle, 0);
130
131

		/*
132
133
134
135
		 * The NS world registers the address of its handler to be
		 * used for processing the FIQ. This is normally used by the
		 * NS FIQ debugger driver to detect system hangs by programming
		 * a watchdog timer to fire a FIQ interrupt.
136
		 */
137
		case TEGRA_SIP_FIQ_NS_ENTRYPOINT:
138

139
140
141
			if (x1 == 0U) {
				SMC_RET1(handle, SMC_UNK);
			}
142

143
144
145
			/*
			 * TODO: Check if x1 contains a valid DRAM address
			 */
146

147
148
			/* store the NS world's entrypoint */
			tegra_fiq_set_ns_entrypoint(x1);
149

150
151
152
			SMC_RET1(handle, 0);

		/*
153
154
155
156
		 * The NS world's FIQ handler issues this SMC to get the NS EL1/EL0
		 * CPU context when the FIQ interrupt was triggered. This allows the
		 * NS world to understand the CPU state when the watchdog interrupt
		 * triggered.
157
		 */
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
		case TEGRA_SIP_FIQ_NS_GET_CONTEXT:

			/* retrieve context registers when FIQ triggered */
			(void)tegra_fiq_get_intr_context();

			SMC_RET0(handle);

		case TEGRA_SIP_ENABLE_FAKE_SYSTEM_SUSPEND:
			/*
			 * System suspend fake mode is set if we are on VDK and we make
			 * a debug SIP call. This mode ensures that we excercise debug
			 * path instead of the regular code path to suit the pre-silicon
			 * platform needs. These include replacing the call to WFI by
			 * a warm reset request.
			 */
			if (tegra_platform_is_virt_dev_kit() != false) {

				tegra_fake_system_suspend = 1;
				SMC_RET1(handle, 0);
			}

			/*
			 * We return to the external world as if this SIP is not
			 * implemented in case, we are not running on VDK.
			 */
			break;

		default:
			ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
			break;
		}
189
190
191
192
193
194
195
	}

	SMC_RET1(handle, SMC_UNK);
}

/* Define a runtime service descriptor for fast SMC calls */
DECLARE_RT_SVC(
196
	tegra_sip_fast,
197

198
199
200
201
202
	(OEN_SIP_START),
	(OEN_SIP_END),
	(SMC_TYPE_FAST),
	(NULL),
	(tegra_sip_handler)
203
);