zynqmp_common.c 7.01 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
	},
	{
		.id = 0x50,
153
		.name = "XCZU15EG",
154
155
156
	},
	{
		.id = 0x58,
157
		.name = "XCZU19EG",
158
159
160
	},
	{
		.id = 0x59,
161
		.name = "XCZU17EG",
162
	},
163
164
	{
		.id = 0x60,
165
		.name = "XCZU28DR",
166
167
168
	},
	{
		.id = 0x61,
169
		.name = "XCZU21DR",
170
171
172
	},
	{
		.id = 0x62,
173
		.name = "XCZU29DR",
174
175
176
	},
	{
		.id = 0x63,
177
		.name = "XCZU23DR",
178
179
180
	},
	{
		.id = 0x64,
181
		.name = "XCZU27DR",
182
183
184
	},
	{
		.id = 0x65,
185
		.name = "XCZU25DR",
186
	},
187
188
	{
		.id = 0x66,
189
		.name = "XCZU39DR",
190
	},
191
192
	{
		.id = 0x7d,
193
		.name = "XCZU43DR",
194
195
196
	},
	{
		.id = 0x78,
197
		.name = "XCZU46DR",
198
199
200
	},
	{
		.id = 0x7f,
201
		.name = "XCZU47DR",
202
	},
203
204
	{
		.id = 0x7b,
205
		.name = "XCZU48DR",
206
207
208
	},
	{
		.id = 0x7e,
209
		.name = "XCZU49DR",
210
	},
211
212
};

213
214
215
216
#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)

217
218
#define SILICON_ID_XCK26       0x4724093

219
static char *zynqmp_get_silicon_idcode_name(void)
220
{
221
222
223
	uint32_t id, ver, chipid[2];
	size_t i, j, len;
	const char *name = "EG/EV";
224

225
226
227
228
229
230
231
232
233
234
235
#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)
236
		return "XCZUUNKN";
237
#endif
238

239
240
	id = chipid[0] & (ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK |
			  ZYNQMP_CSU_IDCODE_SVD_MASK);
241
	id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
242
	ver = chipid[1] >> ZYNQMP_EFUSE_IPDISABLE_SHIFT;
243

244
245
246
247
248
	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;
	}
249

250
251
252
253
254
255
256
	if (i >= ARRAY_SIZE(zynqmp_devices)) {
		if (chipid[0] == SILICON_ID_XCK26) {
			return "XCK26";
		} else {
			return "XCZUUNKN";
		}
	}
257

258
259
	if (!zynqmp_devices[i].evexists)
		return zynqmp_devices[i].name;
260

261
262
	if (ver & ZYNQMP_PL_STATUS_MASK)
		return zynqmp_devices[i].name;
263

264
265
266
267
	len = strlen(zynqmp_devices[i].name) - 2;
	for (j = 0; j < strlen(name); j++) {
		zynqmp_devices[i].name[len] = name[j];
		len++;
268
	}
269
270
271
	zynqmp_devices[i].name[len] = '\0';

	return zynqmp_devices[i].name;
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
}

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 |
293
	       ZYNQMP_CSU_IDCODE_FAMILY_MASK;
294
	maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT |
295
		 ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT;
296
297
298
299
300
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
	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;
327
328
329
	default:
		/* Do nothing in default case */
		break;
330
331
	}

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

341
342
unsigned int zynqmp_get_bootmode(void)
{
343
	uint32_t r;
344
345
346
	unsigned int ret;

	ret = pm_mmio_read(CRL_APB_BOOT_MODE_USER, &r);
347

348
	if (ret != PM_RET_SUCCESS)
349
		r = mmio_read_32(CRL_APB_BOOT_MODE_USER);
350
351
352
353

	return r & CRL_APB_BOOT_MODE_MASK;
}

354
355
void zynqmp_config_setup(void)
{
356
357
	uint64_t counter_freq;

358
359
360
	/* Configure IPI data for ZynqMP */
	zynqmp_ipi_config_table_init();

361
	zynqmp_print_platform_name();
362
363
364
365
366
367
368

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

369
	generic_delay_timer_init();
370
371
}

372
unsigned int plat_get_syscnt_freq2(void)
373
{
374
	unsigned int ver = zynqmp_get_silicon_ver();
375

376
	if (ver == ZYNQMP_CSU_VERSION_QEMU)
377
		return 65000000;
378
379
	else
		return mmio_read_32(IOU_SCNTRS_BASEFREQ);
380
}