xref: /rk3399_ARM-atf/plat/xilinx/zynqmp/aarch64/zynqmp_common.c (revision 7a1b2794307bf18cdea975b8897f8cd7e0579fc9)
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 	unsigned int ver;
53 
54 	ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
55 	ver &= ZYNQMP_SILICON_VER_MASK;
56 	ver >>= ZYNQMP_SILICON_VER_SHIFT;
57 
58 	return ver;
59 }
60 
61 unsigned int zynqmp_get_uart_clk(void)
62 {
63 	unsigned int ver = zynqmp_get_silicon_ver();
64 
65 	switch (ver) {
66 	case ZYNQMP_CSU_VERSION_VELOCE:
67 		return 48000;
68 	case ZYNQMP_CSU_VERSION_EP108:
69 		return 25000000;
70 	case ZYNQMP_CSU_VERSION_QEMU:
71 		return 133000000;
72 	}
73 
74 	return 100000000;
75 }
76 
77 static unsigned int zynqmp_get_system_timer_freq(void)
78 {
79 	unsigned int ver = zynqmp_get_silicon_ver();
80 
81 	switch (ver) {
82 	case ZYNQMP_CSU_VERSION_VELOCE:
83 		return 10000;
84 	case ZYNQMP_CSU_VERSION_EP108:
85 		return 4000000;
86 	case ZYNQMP_CSU_VERSION_QEMU:
87 		return 50000000;
88 	}
89 
90 	return 100000000;
91 }
92 
93 unsigned int zynqmp_get_silicon_id(void)
94 {
95 	uint32_t id;
96 
97 	id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
98 
99 	id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK;
100 	id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
101 
102 	return id;
103 }
104 
105 #if LOG_LEVEL >= LOG_LEVEL_NOTICE
106 static const struct {
107 	unsigned int id;
108 	char *name;
109 } zynqmp_devices[] = {
110 	{
111 		.id = 0x10,
112 		.name = "3EG",
113 	},
114 	{
115 		.id = 0x11,
116 		.name = "2EG",
117 	},
118 	{
119 		.id = 0x20,
120 		.name = "5EV",
121 	},
122 	{
123 		.id = 0x21,
124 		.name = "4EV",
125 	},
126 	{
127 		.id = 0x30,
128 		.name = "7EV",
129 	},
130 	{
131 		.id = 0x38,
132 		.name = "9EG",
133 	},
134 	{
135 		.id = 0x39,
136 		.name = "6EG",
137 	},
138 	{
139 		.id = 0x40,
140 		.name = "11EG",
141 	},
142 	{
143 		.id = 0x50,
144 		.name = "15EG",
145 	},
146 	{
147 		.id = 0x58,
148 		.name = "19EG",
149 	},
150 	{
151 		.id = 0x59,
152 		.name = "17EG",
153 	},
154 };
155 
156 static char *zynqmp_get_silicon_idcode_name(void)
157 {
158 	unsigned int id;
159 
160 	id = zynqmp_get_silicon_id();
161 	for (size_t i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
162 		if (zynqmp_devices[i].id == id)
163 			return zynqmp_devices[i].name;
164 	}
165 	return "UNKN";
166 }
167 
168 static unsigned int zynqmp_get_rtl_ver(void)
169 {
170 	uint32_t ver;
171 
172 	ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
173 	ver &= ZYNQMP_RTL_VER_MASK;
174 	ver >>= ZYNQMP_RTL_VER_SHIFT;
175 
176 	return ver;
177 }
178 
179 static char *zynqmp_print_silicon_idcode(void)
180 {
181 	uint32_t id, maskid, tmp;
182 
183 	id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
184 
185 	tmp = id;
186 	tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK |
187 	       ZYNQMP_CSU_IDCODE_FAMILY_MASK;
188 	maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT |
189 		 ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT;
190 	if (tmp != maskid) {
191 		ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid);
192 		return "UNKN";
193 	}
194 	VERBOSE("Xilinx IDCODE 0x%x\n", id);
195 	return zynqmp_get_silicon_idcode_name();
196 }
197 
198 static unsigned int zynqmp_get_ps_ver(void)
199 {
200 	uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
201 
202 	ver &= ZYNQMP_PS_VER_MASK;
203 	ver >>= ZYNQMP_PS_VER_SHIFT;
204 
205 	return ver + 1;
206 }
207 
208 static void zynqmp_print_platform_name(void)
209 {
210 	unsigned int ver = zynqmp_get_silicon_ver();
211 	unsigned int rtl = zynqmp_get_rtl_ver();
212 	char *label = "Unknown";
213 
214 	switch (ver) {
215 	case ZYNQMP_CSU_VERSION_VELOCE:
216 		label = "VELOCE";
217 		break;
218 	case ZYNQMP_CSU_VERSION_EP108:
219 		label = "EP108";
220 		break;
221 	case ZYNQMP_CSU_VERSION_QEMU:
222 		label = "QEMU";
223 		break;
224 	case ZYNQMP_CSU_VERSION_SILICON:
225 		label = "silicon";
226 		break;
227 	}
228 
229 	NOTICE("ATF running on XCZU%s/%s v%d/RTL%d.%d at 0x%x%s\n",
230 	       zynqmp_print_silicon_idcode(), label, zynqmp_get_ps_ver(),
231 	       (rtl & 0xf0) >> 4, rtl & 0xf, BL31_BASE,
232 	       zynqmp_is_pmu_up() ? ", with PMU firmware" : "");
233 }
234 #else
235 static inline void zynqmp_print_platform_name(void) { }
236 #endif
237 
238 /*
239  * Indicator for PMUFW discovery:
240  *   0 = No FW found
241  *   non-zero = FW is present
242  */
243 static int zynqmp_pmufw_present;
244 
245 /*
246  * zynqmp_discover_pmufw - Discover presence of PMUFW
247  *
248  * Discover the presence of PMUFW and store it for later run-time queries
249  * through zynqmp_is_pmu_up.
250  * NOTE: This discovery method is fragile and will break if:
251  *  - setting FW_PRESENT is done by PMUFW itself and could be left out in PMUFW
252  *    (be it by error or intentionally)
253  *  - XPPU/XMPU may restrict ATF's access to the PMU address space
254  */
255 static int zynqmp_discover_pmufw(void)
256 {
257 	zynqmp_pmufw_present = mmio_read_32(PMU_GLOBAL_CNTRL);
258 	zynqmp_pmufw_present &= PMU_GLOBAL_CNTRL_FW_IS_PRESENT;
259 
260 	return !!zynqmp_pmufw_present;
261 }
262 
263 /*
264  * zynqmp_is_pmu_up - Find if PMU firmware is up and running
265  *
266  * Return 0 if firmware is not available, non 0 otherwise
267  */
268 int zynqmp_is_pmu_up(void)
269 {
270 	return zynqmp_pmufw_present;
271 }
272 
273 unsigned int zynqmp_get_bootmode(void)
274 {
275 	uint32_t r = mmio_read_32(CRL_APB_BOOT_MODE_USER);
276 
277 	return r & CRL_APB_BOOT_MODE_MASK;
278 }
279 
280 void zynqmp_config_setup(void)
281 {
282 	zynqmp_discover_pmufw();
283 	zynqmp_print_platform_name();
284 
285 	/* Global timer init - Program time stamp reference clk */
286 	uint32_t val = mmio_read_32(CRL_APB_TIMESTAMP_REF_CTRL);
287 	val |= CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT;
288 	mmio_write_32(CRL_APB_TIMESTAMP_REF_CTRL, val);
289 
290 	/* Program freq register in System counter and enable system counter. */
291 	mmio_write_32(IOU_SCNTRS_BASEFREQ, zynqmp_get_system_timer_freq());
292 	mmio_write_32(IOU_SCNTRS_CONTROL, IOU_SCNTRS_CONTROL_EN);
293 
294 	generic_delay_timer_init();
295 }
296 
297 unsigned int plat_get_syscnt_freq2(void)
298 {
299 	unsigned int counter_base_frequency;
300 
301 	/* FIXME: Read the frequency from Frequency modes table */
302 	counter_base_frequency = zynqmp_get_system_timer_freq();
303 
304 	return counter_base_frequency;
305 }
306