blob: 0c45c781fef40510a00b8c95b682a3392219f19c [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
T Karthik Reddy501c2062021-08-10 06:50:18 -060012#include <dm.h>
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020013#include <dm/device_compat.h>
T Karthik Reddy501c2062021-08-10 06:50:18 -060014#include <asm/cache.h>
15#include <soc.h>
16#include <zynqmp_firmware.h>
17#include <asm/arch/sys_proto.h>
18#include <asm/arch/hardware.h>
19
20/*
21 * Zynqmp has 4 silicon revisions
22 * v0 -> 0(XCZU9EG-ES1)
23 * v1 -> 1(XCZU3EG-ES1, XCZU15EG-ES1)
24 * v2 -> 2(XCZU7EV-ES1, XCZU9EG-ES2, XCZU19EG-ES1)
25 * v3 -> 3(Production Level)
26 */
27static const char zynqmp_family[] = "ZynqMP";
28
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020029#define EFUSE_VCU_DIS_SHIFT 8
30#define EFUSE_VCU_DIS_MASK BIT(EFUSE_VCU_DIS_SHIFT)
31#define EFUSE_GPU_DIS_SHIFT 5
32#define EFUSE_GPU_DIS_MASK BIT(EFUSE_GPU_DIS_SHIFT)
33#define IDCODE_DEV_TYPE_MASK GENMASK(27, 0)
34#define IDCODE2_PL_INIT_SHIFT 9
35#define IDCODE2_PL_INIT_MASK BIT(IDCODE2_PL_INIT_SHIFT)
36
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +053037#define ZYNQMP_VERSION_SIZE 10
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020038
39enum {
40 ZYNQMP_VARIANT_EG = BIT(0),
41 ZYNQMP_VARIANT_EV = BIT(1),
42 ZYNQMP_VARIANT_CG = BIT(2),
43 ZYNQMP_VARIANT_DR = BIT(3),
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +053044 ZYNQMP_VARIANT_DR_SE = BIT(4),
45 ZYNQMP_VARIANT_EG_SE = BIT(5),
Venkatesh Yadav Abbarapu2175b042024-04-02 19:53:14 +053046 ZYNQMP_VARIANT_TEG = BIT(6),
Michal Simekb7ec65e2024-07-30 16:53:23 +020047 ZYNQMP_VARIANT_EG_LR = BIT(7),
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 {
Michal Simekb7ec65e2024-07-30 16:53:23 +020069 .id = 0x04689093,
70 .device = 1,
71 .variants = ZYNQMP_VARIANT_EG_LR,
72 },
73 {
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020074 .id = 0x04711093,
75 .device = 2,
76 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
77 },
78 {
79 .id = 0x04710093,
80 .device = 3,
81 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
82 },
83 {
Venkatesh Yadav Abbarapu2175b042024-04-02 19:53:14 +053084 .id = 0x04718093,
85 .device = 3,
86 .variants = ZYNQMP_VARIANT_TEG,
87 },
88 {
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020089 .id = 0x04721093,
90 .device = 4,
91 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
92 ZYNQMP_VARIANT_EV,
93 },
94 {
95 .id = 0x04720093,
96 .device = 5,
97 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
98 ZYNQMP_VARIANT_EV,
99 },
100 {
101 .id = 0x04739093,
102 .device = 6,
103 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
104 },
105 {
106 .id = 0x04730093,
107 .device = 7,
108 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
109 ZYNQMP_VARIANT_EV,
110 },
111 {
112 .id = 0x04738093,
113 .device = 9,
114 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
115 },
116 {
117 .id = 0x04740093,
118 .device = 11,
119 .variants = ZYNQMP_VARIANT_EG,
120 },
121 {
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530122 .id = 0x04741093,
123 .device = 11,
124 .variants = ZYNQMP_VARIANT_EG_SE,
125 },
126 {
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200127 .id = 0x04750093,
128 .device = 15,
129 .variants = ZYNQMP_VARIANT_EG,
130 },
131 {
132 .id = 0x04759093,
133 .device = 17,
134 .variants = ZYNQMP_VARIANT_EG,
135 },
136 {
137 .id = 0x04758093,
138 .device = 19,
139 .variants = ZYNQMP_VARIANT_EG,
140 },
141 {
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530142 .id = 0x0475C093,
143 .device = 19,
144 .variants = ZYNQMP_VARIANT_EG_SE,
145 },
146 {
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200147 .id = 0x047E1093,
148 .device = 21,
149 .variants = ZYNQMP_VARIANT_DR,
150 },
151 {
152 .id = 0x047E3093,
153 .device = 23,
154 .variants = ZYNQMP_VARIANT_DR,
155 },
156 {
157 .id = 0x047E5093,
158 .device = 25,
159 .variants = ZYNQMP_VARIANT_DR,
160 },
161 {
162 .id = 0x047E4093,
163 .device = 27,
164 .variants = ZYNQMP_VARIANT_DR,
165 },
166 {
167 .id = 0x047E0093,
168 .device = 28,
169 .variants = ZYNQMP_VARIANT_DR,
170 },
171 {
172 .id = 0x047E2093,
173 .device = 29,
174 .variants = ZYNQMP_VARIANT_DR,
175 },
176 {
177 .id = 0x047E6093,
178 .device = 39,
179 .variants = ZYNQMP_VARIANT_DR,
180 },
181 {
182 .id = 0x047FD093,
183 .device = 43,
184 .variants = ZYNQMP_VARIANT_DR,
185 },
186 {
187 .id = 0x047F8093,
188 .device = 46,
189 .variants = ZYNQMP_VARIANT_DR,
190 },
191 {
192 .id = 0x047FF093,
193 .device = 47,
194 .variants = ZYNQMP_VARIANT_DR,
195 },
196 {
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530197 .id = 0x047FA093,
198 .device = 47,
199 .variants = ZYNQMP_VARIANT_DR_SE,
200 },
201 {
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200202 .id = 0x047FB093,
203 .device = 48,
204 .variants = ZYNQMP_VARIANT_DR,
205 },
206 {
207 .id = 0x047FE093,
208 .device = 49,
209 .variants = ZYNQMP_VARIANT_DR,
210 },
211 {
212 .id = 0x046d0093,
213 .device = 67,
214 .variants = ZYNQMP_VARIANT_DR,
215 },
216 {
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530217 .id = 0x046d7093,
218 .device = 67,
219 .variants = ZYNQMP_VARIANT_DR_SE,
220 },
221 {
Michal Simek67a5efa2023-01-18 09:25:26 +0100222 .id = 0x04712093,
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200223 .device = 24,
224 .variants = 0,
225 },
226 {
227 .id = 0x04724093,
228 .device = 26,
229 .variants = 0,
230 },
231};
232
233static const struct zynqmp_device *zynqmp_get_device(u32 idcode)
234{
235 idcode &= IDCODE_DEV_TYPE_MASK;
236
237 for (int i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
238 if (zynqmp_devices[i].id == idcode)
239 return &zynqmp_devices[i];
240 }
241
242 return NULL;
243}
244
245static int soc_xilinx_zynqmp_detect_machine(struct udevice *dev, u32 idcode,
246 u32 idcode2)
247{
248 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
249 const struct zynqmp_device *device;
250 int ret;
251
252 device = zynqmp_get_device(idcode);
253 if (!device)
254 return 0;
255
256 /* Add device prefix to the name */
257 ret = snprintf(priv->machine, sizeof(priv->machine), "%s%d",
258 device->variants ? "zu" : "xck", device->device);
259 if (ret < 0)
260 return ret;
261
262 if (device->variants & ZYNQMP_VARIANT_EV) {
263 /* Devices with EV variant might be EG/CG/EV family */
264 if (idcode2 & IDCODE2_PL_INIT_MASK) {
265 u32 family = ((idcode2 & EFUSE_VCU_DIS_MASK) >>
266 EFUSE_VCU_DIS_SHIFT) << 1 |
267 ((idcode2 & EFUSE_GPU_DIS_MASK) >>
268 EFUSE_GPU_DIS_SHIFT);
269
270 /*
271 * Get family name based on extended idcode values as
272 * determined on UG1087, EXTENDED_IDCODE register
273 * description
274 */
275 switch (family) {
276 case 0x00:
277 strlcat(priv->machine, "ev",
278 sizeof(priv->machine));
279 break;
280 case 0x10:
281 strlcat(priv->machine, "eg",
282 sizeof(priv->machine));
283 break;
284 case 0x11:
285 strlcat(priv->machine, "cg",
286 sizeof(priv->machine));
287 break;
288 default:
289 /* Do not append family name*/
290 break;
291 }
292 } else {
293 /*
294 * When PL powered down the VCU Disable efuse cannot be
295 * read. So, ignore the bit and just findout if it is CG
296 * or EG/EV variant.
297 */
298 strlcat(priv->machine, (idcode2 & EFUSE_GPU_DIS_MASK) ?
299 "cg" : "e", sizeof(priv->machine));
300 }
301 } else if (device->variants & ZYNQMP_VARIANT_CG) {
302 /* Devices with CG variant might be EG or CG family */
303 strlcat(priv->machine, (idcode2 & EFUSE_GPU_DIS_MASK) ?
304 "cg" : "eg", sizeof(priv->machine));
305 } else if (device->variants & ZYNQMP_VARIANT_EG) {
306 strlcat(priv->machine, "eg", sizeof(priv->machine));
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530307 } else if (device->variants & ZYNQMP_VARIANT_EG_SE) {
308 strlcat(priv->machine, "eg_SE", sizeof(priv->machine));
Michal Simekb7ec65e2024-07-30 16:53:23 +0200309 } else if (device->variants & ZYNQMP_VARIANT_EG_LR) {
310 strlcat(priv->machine, "eg_LR", sizeof(priv->machine));
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200311 } else if (device->variants & ZYNQMP_VARIANT_DR) {
312 strlcat(priv->machine, "dr", sizeof(priv->machine));
Venkatesh Yadav Abbarapu55136382024-01-23 10:27:15 +0530313 } else if (device->variants & ZYNQMP_VARIANT_DR_SE) {
314 strlcat(priv->machine, "dr_SE", sizeof(priv->machine));
Venkatesh Yadav Abbarapu2175b042024-04-02 19:53:14 +0530315 } else if (device->variants & ZYNQMP_VARIANT_TEG) {
316 strlcat(priv->machine, "teg", sizeof(priv->machine));
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200317 }
318
319 return 0;
320}
321
T Karthik Reddy501c2062021-08-10 06:50:18 -0600322static int soc_xilinx_zynqmp_get_family(struct udevice *dev, char *buf, int size)
323{
324 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
325
326 return snprintf(buf, size, "%s", priv->family);
327}
328
Venkatesh Yadav Abbarapuf35f9572022-10-04 11:22:01 +0530329static int soc_xilinx_zynqmp_get_machine(struct udevice *dev, char *buf, int size)
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200330{
331 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
332 const char *machine = priv->machine;
333
334 if (!machine[0])
335 machine = "unknown";
336
337 return snprintf(buf, size, "%s", machine);
338}
339
T Karthik Reddy501c2062021-08-10 06:50:18 -0600340static int soc_xilinx_zynqmp_get_revision(struct udevice *dev, char *buf, int size)
341{
342 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
343
344 return snprintf(buf, size, "v%d", priv->revision);
345}
346
347static const struct soc_ops soc_xilinx_zynqmp_ops = {
348 .get_family = soc_xilinx_zynqmp_get_family,
349 .get_revision = soc_xilinx_zynqmp_get_revision,
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200350 .get_machine = soc_xilinx_zynqmp_get_machine,
T Karthik Reddy501c2062021-08-10 06:50:18 -0600351};
352
353static int soc_xilinx_zynqmp_probe(struct udevice *dev)
354{
355 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
Michal Simekab51e372022-04-20 09:39:04 +0200356 u32 ret_payload[PAYLOAD_ARG_CNT];
T Karthik Reddy501c2062021-08-10 06:50:18 -0600357 int ret;
358
359 priv->family = zynqmp_family;
360
Stefan Herbrechtsmeier4f2aeb42022-06-20 18:36:42 +0200361 if (!IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE))
T Karthik Reddy501c2062021-08-10 06:50:18 -0600362 ret = zynqmp_mmio_read(ZYNQMP_PS_VERSION, &ret_payload[2]);
363 else
364 ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0,
365 ret_payload);
366 if (ret < 0)
367 return ret;
368
369 priv->revision = ret_payload[2] & ZYNQMP_PS_VER_MASK;
370
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200371 if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) {
372 /*
373 * Firmware returns:
374 * payload[0][31:0] = status of the operation
375 * payload[1] = IDCODE
376 * payload[2][19:0] = Version
377 * payload[2][28:20] = EXTENDED_IDCODE
378 * payload[2][29] = PL_INIT
379 */
380 u32 idcode = ret_payload[1];
381 u32 idcode2 = ret_payload[2] >>
382 ZYNQMP_CSU_VERSION_EMPTY_SHIFT;
383 dev_dbg(dev, "IDCODE: 0x%0x, IDCODE2: 0x%0x\n", idcode,
384 idcode2);
385
386 ret = soc_xilinx_zynqmp_detect_machine(dev, idcode, idcode2);
387 if (ret)
388 return ret;
389 }
390
T Karthik Reddy501c2062021-08-10 06:50:18 -0600391 return 0;
392}
393
394U_BOOT_DRIVER(soc_xilinx_zynqmp) = {
395 .name = "soc_xilinx_zynqmp",
396 .id = UCLASS_SOC,
397 .ops = &soc_xilinx_zynqmp_ops,
398 .probe = soc_xilinx_zynqmp_probe,
399 .priv_auto = sizeof(struct soc_xilinx_zynqmp_priv),
400 .flags = DM_FLAG_PRE_RELOC,
401};