xref: /rk3399_ARM-atf/plat/xilinx/zynqmp/aarch64/zynqmp_common.c (revision 6331a31a66cdcf53421d3dccd3067f072c6da175)
1 /*
2  * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of ARM nor the names of its contributors may be used
15  * to endorse or promote products derived from this software without specific
16  * prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <arch_helpers.h>
32 #include <cci.h>
33 #include <debug.h>
34 #include <gicv2.h>
35 #include <mmio.h>
36 #include <plat_arm.h>
37 #include <platform.h>
38 #include <xlat_tables.h>
39 #include "../zynqmp_private.h"
40 
41 /*
42  * Table of regions to map using the MMU.
43  * This doesn't include TZRAM as the 'mem_layout' argument passed to
44  * configure_mmu_elx() will give the available subset of that,
45  */
46 const mmap_region_t plat_arm_mmap[] = {
47 	{ DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
48 	{ DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
49 	{ CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
50 	{0}
51 };
52 
53 static unsigned int zynqmp_get_silicon_ver(void)
54 {
55 	unsigned int ver;
56 
57 	ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
58 	ver &= ZYNQMP_SILICON_VER_MASK;
59 	ver >>= ZYNQMP_SILICON_VER_SHIFT;
60 
61 	return ver;
62 }
63 
64 unsigned int zynqmp_get_uart_clk(void)
65 {
66 	unsigned int ver = zynqmp_get_silicon_ver();
67 
68 	switch (ver) {
69 	case ZYNQMP_CSU_VERSION_VELOCE:
70 		return 48000;
71 	case ZYNQMP_CSU_VERSION_EP108:
72 		return 25000000;
73 	case ZYNQMP_CSU_VERSION_QEMU:
74 		return 133000000;
75 	}
76 
77 	return 100000000;
78 }
79 
80 static unsigned int zynqmp_get_system_timer_freq(void)
81 {
82 	unsigned int ver = zynqmp_get_silicon_ver();
83 
84 	switch (ver) {
85 	case ZYNQMP_CSU_VERSION_VELOCE:
86 		return 10000;
87 	case ZYNQMP_CSU_VERSION_EP108:
88 		return 4000000;
89 	case ZYNQMP_CSU_VERSION_QEMU:
90 		return 50000000;
91 	}
92 
93 	return 100000000;
94 }
95 
96 #if LOG_LEVEL >= LOG_LEVEL_NOTICE
97 static const struct {
98 	unsigned int id;
99 	char *name;
100 } zynqmp_devices[] = {
101 	{
102 		.id = 0x10,
103 		.name = "3EG",
104 	},
105 	{
106 		.id = 0x11,
107 		.name = "2EG",
108 	},
109 	{
110 		.id = 0x20,
111 		.name = "5EV",
112 	},
113 	{
114 		.id = 0x21,
115 		.name = "4EV",
116 	},
117 	{
118 		.id = 0x30,
119 		.name = "7EV",
120 	},
121 	{
122 		.id = 0x38,
123 		.name = "9EG",
124 	},
125 	{
126 		.id = 0x39,
127 		.name = "6EG",
128 	},
129 	{
130 		.id = 0x40,
131 		.name = "11EG",
132 	},
133 	{
134 		.id = 0x50,
135 		.name = "15EG",
136 	},
137 	{
138 		.id = 0x58,
139 		.name = "19EG",
140 	},
141 	{
142 		.id = 0x59,
143 		.name = "17EG",
144 	},
145 };
146 
147 static unsigned int zynqmp_get_silicon_id(void)
148 {
149 	uint32_t id;
150 
151 	id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
152 
153 	id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK;
154 	id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
155 
156 	return id;
157 }
158 
159 static char *zynqmp_get_silicon_idcode_name(void)
160 {
161 	unsigned int id;
162 
163 	id = zynqmp_get_silicon_id();
164 	for (size_t i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
165 		if (zynqmp_devices[i].id == id)
166 			return zynqmp_devices[i].name;
167 	}
168 	return "UNKN";
169 }
170 
171 static unsigned int zynqmp_get_rtl_ver(void)
172 {
173 	uint32_t ver;
174 
175 	ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
176 	ver &= ZYNQMP_RTL_VER_MASK;
177 	ver >>= ZYNQMP_RTL_VER_SHIFT;
178 
179 	return ver;
180 }
181 
182 static char *zynqmp_print_silicon_idcode(void)
183 {
184 	uint32_t id, maskid, tmp;
185 
186 	id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
187 
188 	tmp = id;
189 	tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK |
190 	       ZYNQMP_CSU_IDCODE_FAMILY_MASK |
191 	       ZYNQMP_CSU_IDCODE_REVISION_MASK;
192 	maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT |
193 		 ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT |
194 		 ZYNQMP_CSU_IDCODE_REVISION << ZYNQMP_CSU_IDCODE_REVISION_SHIFT;
195 	if (tmp != maskid) {
196 		ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid);
197 		return "UNKN";
198 	}
199 	VERBOSE("Xilinx IDCODE 0x%x\n", id);
200 	return zynqmp_get_silicon_idcode_name();
201 }
202 
203 static unsigned int zynqmp_get_ps_ver(void)
204 {
205 	uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
206 
207 	ver &= ZYNQMP_PS_VER_MASK;
208 	ver >>= ZYNQMP_PS_VER_SHIFT;
209 
210 	return ver + 1;
211 }
212 
213 static void zynqmp_print_platform_name(void)
214 {
215 	unsigned int ver = zynqmp_get_silicon_ver();
216 	unsigned int rtl = zynqmp_get_rtl_ver();
217 	char *label = "Unknown";
218 
219 	switch (ver) {
220 	case ZYNQMP_CSU_VERSION_VELOCE:
221 		label = "VELOCE";
222 		break;
223 	case ZYNQMP_CSU_VERSION_EP108:
224 		label = "EP108";
225 		break;
226 	case ZYNQMP_CSU_VERSION_QEMU:
227 		label = "QEMU";
228 		break;
229 	case ZYNQMP_CSU_VERSION_SILICON:
230 		label = "silicon";
231 		break;
232 	}
233 
234 	NOTICE("ATF running on XCZU%s/%s v%d/RTL%d.%d at 0x%x%s\n",
235 	       zynqmp_print_silicon_idcode(), label, zynqmp_get_ps_ver(),
236 	       (rtl & 0xf0) >> 4, rtl & 0xf, BL31_BASE,
237 	       zynqmp_is_pmu_up() ? ", with PMU firmware" : "");
238 }
239 #else
240 static inline void zynqmp_print_platform_name(void) { }
241 #endif
242 
243 /*
244  * Indicator for PMUFW discovery:
245  *   0 = No FW found
246  *   non-zero = FW is present
247  */
248 static int zynqmp_pmufw_present;
249 
250 /*
251  * zynqmp_discover_pmufw - Discover presence of PMUFW
252  *
253  * Discover the presence of PMUFW and store it for later run-time queries
254  * through zynqmp_is_pmu_up.
255  * NOTE: This discovery method is fragile and will break if:
256  *  - setting FW_PRESENT is done by PMUFW itself and could be left out in PMUFW
257  *    (be it by error or intentionally)
258  *  - XPPU/XMPU may restrict ATF's access to the PMU address space
259  */
260 static int zynqmp_discover_pmufw(void)
261 {
262 	zynqmp_pmufw_present = mmio_read_32(PMU_GLOBAL_CNTRL);
263 	zynqmp_pmufw_present &= PMU_GLOBAL_CNTRL_FW_IS_PRESENT;
264 
265 	return !!zynqmp_pmufw_present;
266 }
267 
268 /*
269  * zynqmp_is_pmu_up - Find if PMU firmware is up and running
270  *
271  * Return 0 if firmware is not available, non 0 otherwise
272  */
273 int zynqmp_is_pmu_up(void)
274 {
275 	return zynqmp_pmufw_present;
276 }
277 
278 /*
279  * A single boot loader stack is expected to work on both the Foundation ZYNQMP
280  * models and the two flavours of the Base ZYNQMP models (AEMv8 & Cortex). The
281  * SYS_ID register provides a mechanism for detecting the differences between
282  * these platforms. This information is stored in a per-BL array to allow the
283  * code to take the correct path.Per BL platform configuration.
284  */
285 void zynqmp_config_setup(void)
286 {
287 	zynqmp_discover_pmufw();
288 	zynqmp_print_platform_name();
289 
290 	/* Global timer init - Program time stamp reference clk */
291 	uint32_t val = mmio_read_32(CRL_APB_TIMESTAMP_REF_CTRL);
292 	val |= CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT;
293 	mmio_write_32(CRL_APB_TIMESTAMP_REF_CTRL, val);
294 
295 	/* Program freq register in System counter and enable system counter. */
296 	mmio_write_32(IOU_SCNTRS_BASEFREQ, zynqmp_get_system_timer_freq());
297 	mmio_write_32(IOU_SCNTRS_CONTROL, IOU_SCNTRS_CONTROL_EN);
298 }
299 
300 unsigned int plat_get_syscnt_freq2(void)
301 {
302 	unsigned int counter_base_frequency;
303 
304 	/* FIXME: Read the frequency from Frequency modes table */
305 	counter_base_frequency = zynqmp_get_system_timer_freq();
306 
307 	return counter_base_frequency;
308 }
309