zynqmp_common.c 7.06 KB
Newer Older
1
/*
2
 * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
3
 *
dp-arm's avatar
dp-arm committed
4
 * SPDX-License-Identifier: BSD-3-Clause
5
6
 */

7
8
#include <stdbool.h>
#include <string.h>
9
10
11
12
13

#include <common/debug.h>
#include <drivers/generic_delay_timer.h>
#include <lib/mmio.h>
#include <lib/xlat_tables/xlat_tables.h>
14
#include <plat_ipi.h>
15
#include <plat_private.h>
16
17
#include <plat/common/platform.h>

18
#include "pm_api_sys.h"
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

/*
 * Table of regions to map using the MMU.
 * This doesn't include TZRAM as the 'mem_layout' argument passed to
 * configure_mmu_elx() will give the available subset of that,
 */
const mmap_region_t plat_arm_mmap[] = {
	{ DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
	{ DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
	{ CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
	{0}
};

static unsigned int zynqmp_get_silicon_ver(void)
{
34
	static unsigned int ver;
35

36
37
38
39
40
41
	if (!ver) {
		ver = mmio_read_32(ZYNQMP_CSU_BASEADDR +
				   ZYNQMP_CSU_VERSION_OFFSET);
		ver &= ZYNQMP_SILICON_VER_MASK;
		ver >>= ZYNQMP_SILICON_VER_SHIFT;
	}
42
43
44
45
46
47
48
49

	return ver;
}

unsigned int zynqmp_get_uart_clk(void)
{
	unsigned int ver = zynqmp_get_silicon_ver();

50
	if (ver == ZYNQMP_CSU_VERSION_QEMU)
51
		return 133000000;
52
53
	else
		return 100000000;
54
55
56
57
58
}

#if LOG_LEVEL >= LOG_LEVEL_NOTICE
static const struct {
	unsigned int id;
59
	unsigned int ver;
60
	char *name;
61
	bool evexists;
62
63
64
} zynqmp_devices[] = {
	{
		.id = 0x10,
65
		.name = "XCZU3EG",
66
	},
67
68
69
	{
		.id = 0x10,
		.ver = 0x2c,
70
		.name = "XCZU3CG",
71
	},
72
73
	{
		.id = 0x11,
74
		.name = "XCZU2EG",
75
	},
76
77
78
	{
		.id = 0x11,
		.ver = 0x2c,
79
		.name = "XCZU2CG",
80
	},
81
82
	{
		.id = 0x20,
83
		.name = "XCZU5EV",
84
		.evexists = true,
85
	},
86
87
88
	{
		.id = 0x20,
		.ver = 0x100,
89
		.name = "XCZU5EG",
90
		.evexists = true,
91
92
93
94
	},
	{
		.id = 0x20,
		.ver = 0x12c,
95
		.name = "XCZU5CG",
96
	},
97
98
	{
		.id = 0x21,
99
		.name = "XCZU4EV",
100
		.evexists = true,
101
	},
102
103
104
	{
		.id = 0x21,
		.ver = 0x100,
105
		.name = "XCZU4EG",
106
		.evexists = true,
107
108
109
110
	},
	{
		.id = 0x21,
		.ver = 0x12c,
111
		.name = "XCZU4CG",
112
	},
113
114
	{
		.id = 0x30,
115
		.name = "XCZU7EV",
116
		.evexists = true,
117
	},
118
119
120
	{
		.id = 0x30,
		.ver = 0x100,
121
		.name = "XCZU7EG",
122
		.evexists = true,
123
124
125
126
	},
	{
		.id = 0x30,
		.ver = 0x12c,
127
		.name = "XCZU7CG",
128
	},
129
130
	{
		.id = 0x38,
131
		.name = "XCZU9EG",
132
	},
133
134
135
	{
		.id = 0x38,
		.ver = 0x2c,
136
		.name = "XCZU9CG",
137
	},
138
139
	{
		.id = 0x39,
140
		.name = "XCZU6EG",
141
	},
142
143
144
	{
		.id = 0x39,
		.ver = 0x2c,
145
		.name = "XCZU6CG",
146
	},
147
148
	{
		.id = 0x40,
149
		.name = "XCZU11EG",
150
	},
151
152
153
	{ /* For testing purpose only */
		.id = 0x50,
		.ver = 0x2c,
154
		.name = "XCZU15CG",
155
	},
156
157
	{
		.id = 0x50,
158
		.name = "XCZU15EG",
159
160
161
	},
	{
		.id = 0x58,
162
		.name = "XCZU19EG",
163
164
165
	},
	{
		.id = 0x59,
166
		.name = "XCZU17EG",
167
	},
168
169
	{
		.id = 0x60,
170
		.name = "XCZU28DR",
171
172
173
	},
	{
		.id = 0x61,
174
		.name = "XCZU21DR",
175
176
177
	},
	{
		.id = 0x62,
178
		.name = "XCZU29DR",
179
180
181
	},
	{
		.id = 0x63,
182
		.name = "XCZU23DR",
183
184
185
	},
	{
		.id = 0x64,
186
		.name = "XCZU27DR",
187
188
189
	},
	{
		.id = 0x65,
190
		.name = "XCZU25DR",
191
	},
192
193
	{
		.id = 0x66,
194
		.name = "XCZU39DR",
195
	},
196
197
	{
		.id = 0x7d,
198
		.name = "XCZU43DR",
199
200
201
	},
	{
		.id = 0x78,
202
		.name = "XCZU46DR",
203
204
205
	},
	{
		.id = 0x7f,
206
		.name = "XCZU47DR",
207
	},
208
209
	{
		.id = 0x7b,
210
		.name = "XCZU48DR",
211
212
213
	},
	{
		.id = 0x7e,
214
		.name = "XCZU49DR",
215
	},
216
217
};

218
219
220
221
#define ZYNQMP_PL_STATUS_BIT	9
#define ZYNQMP_PL_STATUS_MASK	BIT(ZYNQMP_PL_STATUS_BIT)
#define ZYNQMP_CSU_VERSION_MASK	~(ZYNQMP_PL_STATUS_MASK)

222
223
#define SILICON_ID_XCK26       0x4724093

224
static char *zynqmp_get_silicon_idcode_name(void)
225
{
226
227
228
	uint32_t id, ver, chipid[2];
	size_t i, j, len;
	const char *name = "EG/EV";
229

230
231
232
233
234
235
236
237
238
239
240
#ifdef IMAGE_BL32
	/*
	 * For BL32, get the chip id info directly by reading corresponding
	 * registers instead of making pm call. This has limitation
	 * that these registers should be configured to have access
	 * from APU which is default case.
	 */
	chipid[0] = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
	chipid[1] = mmio_read_32(EFUSE_BASEADDR + EFUSE_IPDISABLE_OFFSET);
#else
	if (pm_get_chipid(chipid) != PM_RET_SUCCESS)
241
		return "XCZUUNKN";
242
#endif
243

244
245
	id = chipid[0] & (ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK |
			  ZYNQMP_CSU_IDCODE_SVD_MASK);
246
	id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
247
	ver = chipid[1] >> ZYNQMP_EFUSE_IPDISABLE_SHIFT;
248

249
250
251
252
253
	for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
		if (zynqmp_devices[i].id == id &&
		    zynqmp_devices[i].ver == (ver & ZYNQMP_CSU_VERSION_MASK))
			break;
	}
254

255
256
257
258
259
260
261
	if (i >= ARRAY_SIZE(zynqmp_devices)) {
		if (chipid[0] == SILICON_ID_XCK26) {
			return "XCK26";
		} else {
			return "XCZUUNKN";
		}
	}
262

263
264
	if (!zynqmp_devices[i].evexists)
		return zynqmp_devices[i].name;
265

266
267
	if (ver & ZYNQMP_PL_STATUS_MASK)
		return zynqmp_devices[i].name;
268

269
270
271
272
	len = strlen(zynqmp_devices[i].name) - 2;
	for (j = 0; j < strlen(name); j++) {
		zynqmp_devices[i].name[len] = name[j];
		len++;
273
	}
274
275
276
	zynqmp_devices[i].name[len] = '\0';

	return zynqmp_devices[i].name;
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
}

static unsigned int zynqmp_get_rtl_ver(void)
{
	uint32_t ver;

	ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
	ver &= ZYNQMP_RTL_VER_MASK;
	ver >>= ZYNQMP_RTL_VER_SHIFT;

	return ver;
}

static char *zynqmp_print_silicon_idcode(void)
{
	uint32_t id, maskid, tmp;

	id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);

	tmp = id;
	tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK |
298
	       ZYNQMP_CSU_IDCODE_FAMILY_MASK;
299
	maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT |
300
		 ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT;
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
	if (tmp != maskid) {
		ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid);
		return "UNKN";
	}
	VERBOSE("Xilinx IDCODE 0x%x\n", id);
	return zynqmp_get_silicon_idcode_name();
}

static unsigned int zynqmp_get_ps_ver(void)
{
	uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);

	ver &= ZYNQMP_PS_VER_MASK;
	ver >>= ZYNQMP_PS_VER_SHIFT;

	return ver + 1;
}

static void zynqmp_print_platform_name(void)
{
	unsigned int ver = zynqmp_get_silicon_ver();
	unsigned int rtl = zynqmp_get_rtl_ver();
	char *label = "Unknown";

	switch (ver) {
	case ZYNQMP_CSU_VERSION_QEMU:
		label = "QEMU";
		break;
	case ZYNQMP_CSU_VERSION_SILICON:
		label = "silicon";
		break;
332
333
334
	default:
		/* Do nothing in default case */
		break;
335
336
	}

337
	NOTICE("TF-A running on %s/%s v%d/RTL%d.%d at 0x%x\n",
338
	       zynqmp_print_silicon_idcode(), label, zynqmp_get_ps_ver(),
339
	       (rtl & 0xf0) >> 4, rtl & 0xf, BL31_BASE);
340
341
342
343
344
}
#else
static inline void zynqmp_print_platform_name(void) { }
#endif

345
346
unsigned int zynqmp_get_bootmode(void)
{
347
	uint32_t r;
348
349
350
	unsigned int ret;

	ret = pm_mmio_read(CRL_APB_BOOT_MODE_USER, &r);
351

352
	if (ret != PM_RET_SUCCESS)
353
		r = mmio_read_32(CRL_APB_BOOT_MODE_USER);
354
355
356
357

	return r & CRL_APB_BOOT_MODE_MASK;
}

358
359
void zynqmp_config_setup(void)
{
360
361
	uint64_t counter_freq;

362
363
364
	/* Configure IPI data for ZynqMP */
	zynqmp_ipi_config_table_init();

365
	zynqmp_print_platform_name();
366
367
368
369
370
371
372

	/* Configure counter frequency */
	counter_freq = read_cntfrq_el0();
	if (counter_freq == ZYNQMP_DEFAULT_COUNTER_FREQ) {
		write_cntfrq_el0(plat_get_syscnt_freq2());
	}

373
	generic_delay_timer_init();
374
375
}

376
unsigned int plat_get_syscnt_freq2(void)
377
{
378
	unsigned int ver = zynqmp_get_silicon_ver();
379

380
	if (ver == ZYNQMP_CSU_VERSION_QEMU)
381
		return 65000000;
382
383
	else
		return mmio_read_32(IOU_SCNTRS_BASEFREQ);
384
}