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