blob: 60a16058f0ec09fdd2ce57a4c093656fca1578f4 [file] [log] [blame]
Soren Brinkmann76fcae32016-03-06 20:16:27 -08001/*
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
Soren Brinkmann76fcae32016-03-06 20:16:27 -080031#include <debug.h>
Soren Brinkmanne5bdcaa2016-06-22 09:02:56 -070032#include <generic_delay_timer.h>
Soren Brinkmann76fcae32016-03-06 20:16:27 -080033#include <mmio.h>
Soren Brinkmann76fcae32016-03-06 20:16:27 -080034#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 */
43const 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
50static 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
61unsigned 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
77static 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
Siva Durga Prasad Paladugu16427d12016-08-24 11:45:47 +053093unsigned 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
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800105#if LOG_LEVEL >= LOG_LEVEL_NOTICE
106static 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
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800156static 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
168static 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
179static 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 |
Soren Brinkmann31114132016-05-20 07:05:00 -0700187 ZYNQMP_CSU_IDCODE_FAMILY_MASK;
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800188 maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT |
Soren Brinkmann31114132016-05-20 07:05:00 -0700189 ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT;
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800190 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
198static 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
208static 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
235static 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 */
243static 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 */
255static 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 */
268int zynqmp_is_pmu_up(void)
269{
270 return zynqmp_pmufw_present;
271}
272
Soren Brinkmannb43d9432016-04-18 11:49:42 -0700273unsigned 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
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800280void 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);
Soren Brinkmanne5bdcaa2016-06-22 09:02:56 -0700293
294 generic_delay_timer_init();
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800295}
296
Antonio Nino Diaze82e29c2016-05-19 10:00:28 +0100297unsigned int plat_get_syscnt_freq2(void)
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800298{
Antonio Nino Diaze82e29c2016-05-19 10:00:28 +0100299 unsigned int counter_base_frequency;
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800300
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}