xref: /rk3399_ARM-atf/plat/xilinx/zynqmp/aarch64/zynqmp_common.c (revision 51faada71a219a8b94cd8d8e423f0f22e9da4d8f)
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 <debug.h>
32 #include <generic_delay_timer.h>
33 #include <mmio.h>
34 #include <platform.h>
35 #include <xlat_tables.h>
36 #include "../zynqmp_private.h"
37 
38 /*
39  * Table of regions to map using the MMU.
40  * This doesn't include TZRAM as the 'mem_layout' argument passed to
41  * configure_mmu_elx() will give the available subset of that,
42  */
43 const mmap_region_t plat_arm_mmap[] = {
44 	{ DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
45 	{ DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
46 	{ CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
47 	{0}
48 };
49 
50 static unsigned int zynqmp_get_silicon_ver(void)
51 {
52 	static unsigned int ver;
53 
54 	if (!ver) {
55 		ver = mmio_read_32(ZYNQMP_CSU_BASEADDR +
56 				   ZYNQMP_CSU_VERSION_OFFSET);
57 		ver &= ZYNQMP_SILICON_VER_MASK;
58 		ver >>= ZYNQMP_SILICON_VER_SHIFT;
59 	}
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 #if LOG_LEVEL >= LOG_LEVEL_NOTICE
81 static const struct {
82 	unsigned int id;
83 	char *name;
84 } zynqmp_devices[] = {
85 	{
86 		.id = 0x10,
87 		.name = "3EG",
88 	},
89 	{
90 		.id = 0x11,
91 		.name = "2EG",
92 	},
93 	{
94 		.id = 0x20,
95 		.name = "5EV",
96 	},
97 	{
98 		.id = 0x21,
99 		.name = "4EV",
100 	},
101 	{
102 		.id = 0x30,
103 		.name = "7EV",
104 	},
105 	{
106 		.id = 0x38,
107 		.name = "9EG",
108 	},
109 	{
110 		.id = 0x39,
111 		.name = "6EG",
112 	},
113 	{
114 		.id = 0x40,
115 		.name = "11EG",
116 	},
117 	{
118 		.id = 0x50,
119 		.name = "15EG",
120 	},
121 	{
122 		.id = 0x58,
123 		.name = "19EG",
124 	},
125 	{
126 		.id = 0x59,
127 		.name = "17EG",
128 	},
129 };
130 
131 static unsigned int zynqmp_get_silicon_id(void)
132 {
133 	uint32_t id;
134 
135 	id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
136 
137 	id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK;
138 	id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
139 
140 	return id;
141 }
142 
143 static char *zynqmp_get_silicon_idcode_name(void)
144 {
145 	unsigned int id;
146 
147 	id = zynqmp_get_silicon_id();
148 	for (size_t i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
149 		if (zynqmp_devices[i].id == id)
150 			return zynqmp_devices[i].name;
151 	}
152 	return "UNKN";
153 }
154 
155 static unsigned int zynqmp_get_rtl_ver(void)
156 {
157 	uint32_t ver;
158 
159 	ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
160 	ver &= ZYNQMP_RTL_VER_MASK;
161 	ver >>= ZYNQMP_RTL_VER_SHIFT;
162 
163 	return ver;
164 }
165 
166 static char *zynqmp_print_silicon_idcode(void)
167 {
168 	uint32_t id, maskid, tmp;
169 
170 	id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
171 
172 	tmp = id;
173 	tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK |
174 	       ZYNQMP_CSU_IDCODE_FAMILY_MASK;
175 	maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT |
176 		 ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT;
177 	if (tmp != maskid) {
178 		ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid);
179 		return "UNKN";
180 	}
181 	VERBOSE("Xilinx IDCODE 0x%x\n", id);
182 	return zynqmp_get_silicon_idcode_name();
183 }
184 
185 static unsigned int zynqmp_get_ps_ver(void)
186 {
187 	uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
188 
189 	ver &= ZYNQMP_PS_VER_MASK;
190 	ver >>= ZYNQMP_PS_VER_SHIFT;
191 
192 	return ver + 1;
193 }
194 
195 static void zynqmp_print_platform_name(void)
196 {
197 	unsigned int ver = zynqmp_get_silicon_ver();
198 	unsigned int rtl = zynqmp_get_rtl_ver();
199 	char *label = "Unknown";
200 
201 	switch (ver) {
202 	case ZYNQMP_CSU_VERSION_VELOCE:
203 		label = "VELOCE";
204 		break;
205 	case ZYNQMP_CSU_VERSION_EP108:
206 		label = "EP108";
207 		break;
208 	case ZYNQMP_CSU_VERSION_QEMU:
209 		label = "QEMU";
210 		break;
211 	case ZYNQMP_CSU_VERSION_SILICON:
212 		label = "silicon";
213 		break;
214 	}
215 
216 	NOTICE("ATF running on XCZU%s/%s v%d/RTL%d.%d at 0x%x%s\n",
217 	       zynqmp_print_silicon_idcode(), label, zynqmp_get_ps_ver(),
218 	       (rtl & 0xf0) >> 4, rtl & 0xf, BL31_BASE,
219 	       zynqmp_is_pmu_up() ? ", with PMU firmware" : "");
220 }
221 #else
222 static inline void zynqmp_print_platform_name(void) { }
223 #endif
224 
225 /*
226  * Indicator for PMUFW discovery:
227  *   0 = No FW found
228  *   non-zero = FW is present
229  */
230 static int zynqmp_pmufw_present;
231 
232 /*
233  * zynqmp_discover_pmufw - Discover presence of PMUFW
234  *
235  * Discover the presence of PMUFW and store it for later run-time queries
236  * through zynqmp_is_pmu_up.
237  * NOTE: This discovery method is fragile and will break if:
238  *  - setting FW_PRESENT is done by PMUFW itself and could be left out in PMUFW
239  *    (be it by error or intentionally)
240  *  - XPPU/XMPU may restrict ATF's access to the PMU address space
241  */
242 static int zynqmp_discover_pmufw(void)
243 {
244 	zynqmp_pmufw_present = mmio_read_32(PMU_GLOBAL_CNTRL);
245 	zynqmp_pmufw_present &= PMU_GLOBAL_CNTRL_FW_IS_PRESENT;
246 
247 	return !!zynqmp_pmufw_present;
248 }
249 
250 /*
251  * zynqmp_is_pmu_up - Find if PMU firmware is up and running
252  *
253  * Return 0 if firmware is not available, non 0 otherwise
254  */
255 int zynqmp_is_pmu_up(void)
256 {
257 	return zynqmp_pmufw_present;
258 }
259 
260 unsigned int zynqmp_get_bootmode(void)
261 {
262 	uint32_t r = mmio_read_32(CRL_APB_BOOT_MODE_USER);
263 
264 	return r & CRL_APB_BOOT_MODE_MASK;
265 }
266 
267 void zynqmp_config_setup(void)
268 {
269 	zynqmp_discover_pmufw();
270 	zynqmp_print_platform_name();
271 	generic_delay_timer_init();
272 }
273 
274 unsigned int plat_get_syscnt_freq2(void)
275 {
276 	unsigned int ver = zynqmp_get_silicon_ver();
277 
278 	switch (ver) {
279 	case ZYNQMP_CSU_VERSION_VELOCE:
280 		return 10000;
281 	case ZYNQMP_CSU_VERSION_EP108:
282 		return 4000000;
283 	case ZYNQMP_CSU_VERSION_QEMU:
284 		return 50000000;
285 	}
286 
287 	return mmio_read_32(IOU_SCNTRS_BASEFREQ);
288 }
289