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