blob: d8b4f172a39d27ed5fd01be4acd51ffbff7dd679 [file] [log] [blame]
T Karthik Reddy501c2062021-08-10 06:50:18 -06001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Xilinx ZynqMP SOC driver
4 *
5 * Copyright (C) 2021 Xilinx, Inc.
Michal Simeka8c94362023-07-10 14:35:49 +02006 * Michal Simek <michal.simek@amd.com>
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +02007 *
8 * Copyright (C) 2022 Weidmüller Interface GmbH & Co. KG
9 * Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
T Karthik Reddy501c2062021-08-10 06:50:18 -060010 */
11
12#include <common.h>
13#include <dm.h>
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020014#include <dm/device_compat.h>
T Karthik Reddy501c2062021-08-10 06:50:18 -060015#include <asm/cache.h>
16#include <soc.h>
17#include <zynqmp_firmware.h>
18#include <asm/arch/sys_proto.h>
19#include <asm/arch/hardware.h>
20
21/*
22 * Zynqmp has 4 silicon revisions
23 * v0 -> 0(XCZU9EG-ES1)
24 * v1 -> 1(XCZU3EG-ES1, XCZU15EG-ES1)
25 * v2 -> 2(XCZU7EV-ES1, XCZU9EG-ES2, XCZU19EG-ES1)
26 * v3 -> 3(Production Level)
27 */
28static const char zynqmp_family[] = "ZynqMP";
29
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020030#define EFUSE_VCU_DIS_SHIFT 8
31#define EFUSE_VCU_DIS_MASK BIT(EFUSE_VCU_DIS_SHIFT)
32#define EFUSE_GPU_DIS_SHIFT 5
33#define EFUSE_GPU_DIS_MASK BIT(EFUSE_GPU_DIS_SHIFT)
34#define IDCODE_DEV_TYPE_MASK GENMASK(27, 0)
35#define IDCODE2_PL_INIT_SHIFT 9
36#define IDCODE2_PL_INIT_MASK BIT(IDCODE2_PL_INIT_SHIFT)
37
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +053038#define ZYNQMP_VERSION_SIZE 10
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020039
40enum {
41 ZYNQMP_VARIANT_EG = BIT(0),
42 ZYNQMP_VARIANT_EV = BIT(1),
43 ZYNQMP_VARIANT_CG = BIT(2),
44 ZYNQMP_VARIANT_DR = BIT(3),
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +053045 ZYNQMP_VARIANT_DR_SE = BIT(4),
46 ZYNQMP_VARIANT_EG_SE = BIT(5),
Venkatesh Yadav Abbarapu2175b042024-04-02 19:53:14 +053047 ZYNQMP_VARIANT_TEG = BIT(6),
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020048};
49
50struct zynqmp_device {
51 u32 id;
52 u8 device;
53 u8 variants;
54};
55
T Karthik Reddy501c2062021-08-10 06:50:18 -060056struct soc_xilinx_zynqmp_priv {
57 const char *family;
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020058 char machine[ZYNQMP_VERSION_SIZE];
T Karthik Reddy501c2062021-08-10 06:50:18 -060059 char revision;
60};
61
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020062static const struct zynqmp_device zynqmp_devices[] = {
63 {
64 .id = 0x04688093,
65 .device = 1,
66 .variants = ZYNQMP_VARIANT_EG,
67 },
68 {
69 .id = 0x04711093,
70 .device = 2,
71 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
72 },
73 {
74 .id = 0x04710093,
75 .device = 3,
76 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
77 },
78 {
Venkatesh Yadav Abbarapu2175b042024-04-02 19:53:14 +053079 .id = 0x04718093,
80 .device = 3,
81 .variants = ZYNQMP_VARIANT_TEG,
82 },
83 {
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020084 .id = 0x04721093,
85 .device = 4,
86 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
87 ZYNQMP_VARIANT_EV,
88 },
89 {
90 .id = 0x04720093,
91 .device = 5,
92 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
93 ZYNQMP_VARIANT_EV,
94 },
95 {
96 .id = 0x04739093,
97 .device = 6,
98 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
99 },
100 {
101 .id = 0x04730093,
102 .device = 7,
103 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
104 ZYNQMP_VARIANT_EV,
105 },
106 {
107 .id = 0x04738093,
108 .device = 9,
109 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
110 },
111 {
112 .id = 0x04740093,
113 .device = 11,
114 .variants = ZYNQMP_VARIANT_EG,
115 },
116 {
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530117 .id = 0x04741093,
118 .device = 11,
119 .variants = ZYNQMP_VARIANT_EG_SE,
120 },
121 {
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200122 .id = 0x04750093,
123 .device = 15,
124 .variants = ZYNQMP_VARIANT_EG,
125 },
126 {
127 .id = 0x04759093,
128 .device = 17,
129 .variants = ZYNQMP_VARIANT_EG,
130 },
131 {
132 .id = 0x04758093,
133 .device = 19,
134 .variants = ZYNQMP_VARIANT_EG,
135 },
136 {
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530137 .id = 0x0475C093,
138 .device = 19,
139 .variants = ZYNQMP_VARIANT_EG_SE,
140 },
141 {
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200142 .id = 0x047E1093,
143 .device = 21,
144 .variants = ZYNQMP_VARIANT_DR,
145 },
146 {
147 .id = 0x047E3093,
148 .device = 23,
149 .variants = ZYNQMP_VARIANT_DR,
150 },
151 {
152 .id = 0x047E5093,
153 .device = 25,
154 .variants = ZYNQMP_VARIANT_DR,
155 },
156 {
157 .id = 0x047E4093,
158 .device = 27,
159 .variants = ZYNQMP_VARIANT_DR,
160 },
161 {
162 .id = 0x047E0093,
163 .device = 28,
164 .variants = ZYNQMP_VARIANT_DR,
165 },
166 {
167 .id = 0x047E2093,
168 .device = 29,
169 .variants = ZYNQMP_VARIANT_DR,
170 },
171 {
172 .id = 0x047E6093,
173 .device = 39,
174 .variants = ZYNQMP_VARIANT_DR,
175 },
176 {
177 .id = 0x047FD093,
178 .device = 43,
179 .variants = ZYNQMP_VARIANT_DR,
180 },
181 {
182 .id = 0x047F8093,
183 .device = 46,
184 .variants = ZYNQMP_VARIANT_DR,
185 },
186 {
187 .id = 0x047FF093,
188 .device = 47,
189 .variants = ZYNQMP_VARIANT_DR,
190 },
191 {
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530192 .id = 0x047FA093,
193 .device = 47,
194 .variants = ZYNQMP_VARIANT_DR_SE,
195 },
196 {
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200197 .id = 0x047FB093,
198 .device = 48,
199 .variants = ZYNQMP_VARIANT_DR,
200 },
201 {
202 .id = 0x047FE093,
203 .device = 49,
204 .variants = ZYNQMP_VARIANT_DR,
205 },
206 {
207 .id = 0x046d0093,
208 .device = 67,
209 .variants = ZYNQMP_VARIANT_DR,
210 },
211 {
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530212 .id = 0x046d7093,
213 .device = 67,
214 .variants = ZYNQMP_VARIANT_DR_SE,
215 },
216 {
Michal Simek67a5efa2023-01-18 09:25:26 +0100217 .id = 0x04712093,
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200218 .device = 24,
219 .variants = 0,
220 },
221 {
222 .id = 0x04724093,
223 .device = 26,
224 .variants = 0,
225 },
226};
227
228static const struct zynqmp_device *zynqmp_get_device(u32 idcode)
229{
230 idcode &= IDCODE_DEV_TYPE_MASK;
231
232 for (int i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
233 if (zynqmp_devices[i].id == idcode)
234 return &zynqmp_devices[i];
235 }
236
237 return NULL;
238}
239
240static int soc_xilinx_zynqmp_detect_machine(struct udevice *dev, u32 idcode,
241 u32 idcode2)
242{
243 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
244 const struct zynqmp_device *device;
245 int ret;
246
247 device = zynqmp_get_device(idcode);
248 if (!device)
249 return 0;
250
251 /* Add device prefix to the name */
252 ret = snprintf(priv->machine, sizeof(priv->machine), "%s%d",
253 device->variants ? "zu" : "xck", device->device);
254 if (ret < 0)
255 return ret;
256
257 if (device->variants & ZYNQMP_VARIANT_EV) {
258 /* Devices with EV variant might be EG/CG/EV family */
259 if (idcode2 & IDCODE2_PL_INIT_MASK) {
260 u32 family = ((idcode2 & EFUSE_VCU_DIS_MASK) >>
261 EFUSE_VCU_DIS_SHIFT) << 1 |
262 ((idcode2 & EFUSE_GPU_DIS_MASK) >>
263 EFUSE_GPU_DIS_SHIFT);
264
265 /*
266 * Get family name based on extended idcode values as
267 * determined on UG1087, EXTENDED_IDCODE register
268 * description
269 */
270 switch (family) {
271 case 0x00:
272 strlcat(priv->machine, "ev",
273 sizeof(priv->machine));
274 break;
275 case 0x10:
276 strlcat(priv->machine, "eg",
277 sizeof(priv->machine));
278 break;
279 case 0x11:
280 strlcat(priv->machine, "cg",
281 sizeof(priv->machine));
282 break;
283 default:
284 /* Do not append family name*/
285 break;
286 }
287 } else {
288 /*
289 * When PL powered down the VCU Disable efuse cannot be
290 * read. So, ignore the bit and just findout if it is CG
291 * or EG/EV variant.
292 */
293 strlcat(priv->machine, (idcode2 & EFUSE_GPU_DIS_MASK) ?
294 "cg" : "e", sizeof(priv->machine));
295 }
296 } else if (device->variants & ZYNQMP_VARIANT_CG) {
297 /* Devices with CG variant might be EG or CG family */
298 strlcat(priv->machine, (idcode2 & EFUSE_GPU_DIS_MASK) ?
299 "cg" : "eg", sizeof(priv->machine));
300 } else if (device->variants & ZYNQMP_VARIANT_EG) {
301 strlcat(priv->machine, "eg", sizeof(priv->machine));
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530302 } else if (device->variants & ZYNQMP_VARIANT_EG_SE) {
303 strlcat(priv->machine, "eg_SE", sizeof(priv->machine));
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200304 } else if (device->variants & ZYNQMP_VARIANT_DR) {
305 strlcat(priv->machine, "dr", sizeof(priv->machine));
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530306 } else if (device->variants & ZYNQMP_VARIANT_DR_SE) {
307 strlcat(priv->machine, "dr_SE", sizeof(priv->machine));
Venkatesh Yadav Abbarapu2175b042024-04-02 19:53:14 +0530308 } else if (device->variants & ZYNQMP_VARIANT_TEG) {
309 strlcat(priv->machine, "teg", sizeof(priv->machine));
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200310 }
311
312 return 0;
313}
314
T Karthik Reddy501c2062021-08-10 06:50:18 -0600315static int soc_xilinx_zynqmp_get_family(struct udevice *dev, char *buf, int size)
316{
317 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
318
319 return snprintf(buf, size, "%s", priv->family);
320}
321
Venkatesh Yadav Abbarapuf35f9572022-10-04 11:22:01 +0530322static int soc_xilinx_zynqmp_get_machine(struct udevice *dev, char *buf, int size)
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200323{
324 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
325 const char *machine = priv->machine;
326
327 if (!machine[0])
328 machine = "unknown";
329
330 return snprintf(buf, size, "%s", machine);
331}
332
T Karthik Reddy501c2062021-08-10 06:50:18 -0600333static int soc_xilinx_zynqmp_get_revision(struct udevice *dev, char *buf, int size)
334{
335 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
336
337 return snprintf(buf, size, "v%d", priv->revision);
338}
339
340static const struct soc_ops soc_xilinx_zynqmp_ops = {
341 .get_family = soc_xilinx_zynqmp_get_family,
342 .get_revision = soc_xilinx_zynqmp_get_revision,
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200343 .get_machine = soc_xilinx_zynqmp_get_machine,
T Karthik Reddy501c2062021-08-10 06:50:18 -0600344};
345
346static int soc_xilinx_zynqmp_probe(struct udevice *dev)
347{
348 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
Michal Simekab51e372022-04-20 09:39:04 +0200349 u32 ret_payload[PAYLOAD_ARG_CNT];
T Karthik Reddy501c2062021-08-10 06:50:18 -0600350 int ret;
351
352 priv->family = zynqmp_family;
353
Stefan Herbrechtsmeier4f2aeb42022-06-20 18:36:42 +0200354 if (!IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE))
T Karthik Reddy501c2062021-08-10 06:50:18 -0600355 ret = zynqmp_mmio_read(ZYNQMP_PS_VERSION, &ret_payload[2]);
356 else
357 ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0,
358 ret_payload);
359 if (ret < 0)
360 return ret;
361
362 priv->revision = ret_payload[2] & ZYNQMP_PS_VER_MASK;
363
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200364 if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) {
365 /*
366 * Firmware returns:
367 * payload[0][31:0] = status of the operation
368 * payload[1] = IDCODE
369 * payload[2][19:0] = Version
370 * payload[2][28:20] = EXTENDED_IDCODE
371 * payload[2][29] = PL_INIT
372 */
373 u32 idcode = ret_payload[1];
374 u32 idcode2 = ret_payload[2] >>
375 ZYNQMP_CSU_VERSION_EMPTY_SHIFT;
376 dev_dbg(dev, "IDCODE: 0x%0x, IDCODE2: 0x%0x\n", idcode,
377 idcode2);
378
379 ret = soc_xilinx_zynqmp_detect_machine(dev, idcode, idcode2);
380 if (ret)
381 return ret;
382 }
383
T Karthik Reddy501c2062021-08-10 06:50:18 -0600384 return 0;
385}
386
387U_BOOT_DRIVER(soc_xilinx_zynqmp) = {
388 .name = "soc_xilinx_zynqmp",
389 .id = UCLASS_SOC,
390 .ops = &soc_xilinx_zynqmp_ops,
391 .probe = soc_xilinx_zynqmp_probe,
392 .priv_auto = sizeof(struct soc_xilinx_zynqmp_priv),
393 .flags = DM_FLAG_PRE_RELOC,
394};