blob: a51bcdb478fb8df5147826504145bdfc98af875c [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.
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +02006 * Michal Simek <michal.simek@xilinx.com>
7 *
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
38#define ZYNQMP_VERSION_SIZE 7
39
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),
45};
46
47struct zynqmp_device {
48 u32 id;
49 u8 device;
50 u8 variants;
51};
52
T Karthik Reddy501c2062021-08-10 06:50:18 -060053struct soc_xilinx_zynqmp_priv {
54 const char *family;
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020055 char machine[ZYNQMP_VERSION_SIZE];
T Karthik Reddy501c2062021-08-10 06:50:18 -060056 char revision;
57};
58
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +020059static const struct zynqmp_device zynqmp_devices[] = {
60 {
61 .id = 0x04688093,
62 .device = 1,
63 .variants = ZYNQMP_VARIANT_EG,
64 },
65 {
66 .id = 0x04711093,
67 .device = 2,
68 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
69 },
70 {
71 .id = 0x04710093,
72 .device = 3,
73 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
74 },
75 {
76 .id = 0x04721093,
77 .device = 4,
78 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
79 ZYNQMP_VARIANT_EV,
80 },
81 {
82 .id = 0x04720093,
83 .device = 5,
84 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
85 ZYNQMP_VARIANT_EV,
86 },
87 {
88 .id = 0x04739093,
89 .device = 6,
90 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
91 },
92 {
93 .id = 0x04730093,
94 .device = 7,
95 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG |
96 ZYNQMP_VARIANT_EV,
97 },
98 {
99 .id = 0x04738093,
100 .device = 9,
101 .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG,
102 },
103 {
104 .id = 0x04740093,
105 .device = 11,
106 .variants = ZYNQMP_VARIANT_EG,
107 },
108 {
109 .id = 0x04750093,
110 .device = 15,
111 .variants = ZYNQMP_VARIANT_EG,
112 },
113 {
114 .id = 0x04759093,
115 .device = 17,
116 .variants = ZYNQMP_VARIANT_EG,
117 },
118 {
119 .id = 0x04758093,
120 .device = 19,
121 .variants = ZYNQMP_VARIANT_EG,
122 },
123 {
124 .id = 0x047E1093,
125 .device = 21,
126 .variants = ZYNQMP_VARIANT_DR,
127 },
128 {
129 .id = 0x047E3093,
130 .device = 23,
131 .variants = ZYNQMP_VARIANT_DR,
132 },
133 {
134 .id = 0x047E5093,
135 .device = 25,
136 .variants = ZYNQMP_VARIANT_DR,
137 },
138 {
139 .id = 0x047E4093,
140 .device = 27,
141 .variants = ZYNQMP_VARIANT_DR,
142 },
143 {
144 .id = 0x047E0093,
145 .device = 28,
146 .variants = ZYNQMP_VARIANT_DR,
147 },
148 {
149 .id = 0x047E2093,
150 .device = 29,
151 .variants = ZYNQMP_VARIANT_DR,
152 },
153 {
154 .id = 0x047E6093,
155 .device = 39,
156 .variants = ZYNQMP_VARIANT_DR,
157 },
158 {
159 .id = 0x047FD093,
160 .device = 43,
161 .variants = ZYNQMP_VARIANT_DR,
162 },
163 {
164 .id = 0x047F8093,
165 .device = 46,
166 .variants = ZYNQMP_VARIANT_DR,
167 },
168 {
169 .id = 0x047FF093,
170 .device = 47,
171 .variants = ZYNQMP_VARIANT_DR,
172 },
173 {
174 .id = 0x047FB093,
175 .device = 48,
176 .variants = ZYNQMP_VARIANT_DR,
177 },
178 {
179 .id = 0x047FE093,
180 .device = 49,
181 .variants = ZYNQMP_VARIANT_DR,
182 },
183 {
184 .id = 0x046d0093,
185 .device = 67,
186 .variants = ZYNQMP_VARIANT_DR,
187 },
188 {
189 .id = 0x04714093,
190 .device = 24,
191 .variants = 0,
192 },
193 {
194 .id = 0x04724093,
195 .device = 26,
196 .variants = 0,
197 },
198};
199
200static const struct zynqmp_device *zynqmp_get_device(u32 idcode)
201{
202 idcode &= IDCODE_DEV_TYPE_MASK;
203
204 for (int i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
205 if (zynqmp_devices[i].id == idcode)
206 return &zynqmp_devices[i];
207 }
208
209 return NULL;
210}
211
212static int soc_xilinx_zynqmp_detect_machine(struct udevice *dev, u32 idcode,
213 u32 idcode2)
214{
215 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
216 const struct zynqmp_device *device;
217 int ret;
218
219 device = zynqmp_get_device(idcode);
220 if (!device)
221 return 0;
222
223 /* Add device prefix to the name */
224 ret = snprintf(priv->machine, sizeof(priv->machine), "%s%d",
225 device->variants ? "zu" : "xck", device->device);
226 if (ret < 0)
227 return ret;
228
229 if (device->variants & ZYNQMP_VARIANT_EV) {
230 /* Devices with EV variant might be EG/CG/EV family */
231 if (idcode2 & IDCODE2_PL_INIT_MASK) {
232 u32 family = ((idcode2 & EFUSE_VCU_DIS_MASK) >>
233 EFUSE_VCU_DIS_SHIFT) << 1 |
234 ((idcode2 & EFUSE_GPU_DIS_MASK) >>
235 EFUSE_GPU_DIS_SHIFT);
236
237 /*
238 * Get family name based on extended idcode values as
239 * determined on UG1087, EXTENDED_IDCODE register
240 * description
241 */
242 switch (family) {
243 case 0x00:
244 strlcat(priv->machine, "ev",
245 sizeof(priv->machine));
246 break;
247 case 0x10:
248 strlcat(priv->machine, "eg",
249 sizeof(priv->machine));
250 break;
251 case 0x11:
252 strlcat(priv->machine, "cg",
253 sizeof(priv->machine));
254 break;
255 default:
256 /* Do not append family name*/
257 break;
258 }
259 } else {
260 /*
261 * When PL powered down the VCU Disable efuse cannot be
262 * read. So, ignore the bit and just findout if it is CG
263 * or EG/EV variant.
264 */
265 strlcat(priv->machine, (idcode2 & EFUSE_GPU_DIS_MASK) ?
266 "cg" : "e", sizeof(priv->machine));
267 }
268 } else if (device->variants & ZYNQMP_VARIANT_CG) {
269 /* Devices with CG variant might be EG or CG family */
270 strlcat(priv->machine, (idcode2 & EFUSE_GPU_DIS_MASK) ?
271 "cg" : "eg", sizeof(priv->machine));
272 } else if (device->variants & ZYNQMP_VARIANT_EG) {
273 strlcat(priv->machine, "eg", sizeof(priv->machine));
274 } else if (device->variants & ZYNQMP_VARIANT_DR) {
275 strlcat(priv->machine, "dr", sizeof(priv->machine));
276 }
277
278 return 0;
279}
280
T Karthik Reddy501c2062021-08-10 06:50:18 -0600281static int soc_xilinx_zynqmp_get_family(struct udevice *dev, char *buf, int size)
282{
283 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
284
285 return snprintf(buf, size, "%s", priv->family);
286}
287
Venkatesh Yadav Abbarapuf35f9572022-10-04 11:22:01 +0530288static int soc_xilinx_zynqmp_get_machine(struct udevice *dev, char *buf, int size)
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200289{
290 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
291 const char *machine = priv->machine;
292
293 if (!machine[0])
294 machine = "unknown";
295
296 return snprintf(buf, size, "%s", machine);
297}
298
T Karthik Reddy501c2062021-08-10 06:50:18 -0600299static int soc_xilinx_zynqmp_get_revision(struct udevice *dev, char *buf, int size)
300{
301 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
302
303 return snprintf(buf, size, "v%d", priv->revision);
304}
305
306static const struct soc_ops soc_xilinx_zynqmp_ops = {
307 .get_family = soc_xilinx_zynqmp_get_family,
308 .get_revision = soc_xilinx_zynqmp_get_revision,
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200309 .get_machine = soc_xilinx_zynqmp_get_machine,
T Karthik Reddy501c2062021-08-10 06:50:18 -0600310};
311
312static int soc_xilinx_zynqmp_probe(struct udevice *dev)
313{
314 struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
Michal Simekab51e372022-04-20 09:39:04 +0200315 u32 ret_payload[PAYLOAD_ARG_CNT];
T Karthik Reddy501c2062021-08-10 06:50:18 -0600316 int ret;
317
318 priv->family = zynqmp_family;
319
Stefan Herbrechtsmeier4f2aeb42022-06-20 18:36:42 +0200320 if (!IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE))
T Karthik Reddy501c2062021-08-10 06:50:18 -0600321 ret = zynqmp_mmio_read(ZYNQMP_PS_VERSION, &ret_payload[2]);
322 else
323 ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0,
324 ret_payload);
325 if (ret < 0)
326 return ret;
327
328 priv->revision = ret_payload[2] & ZYNQMP_PS_VER_MASK;
329
Stefan Herbrechtsmeier3ff3bd42022-06-20 18:36:43 +0200330 if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) {
331 /*
332 * Firmware returns:
333 * payload[0][31:0] = status of the operation
334 * payload[1] = IDCODE
335 * payload[2][19:0] = Version
336 * payload[2][28:20] = EXTENDED_IDCODE
337 * payload[2][29] = PL_INIT
338 */
339 u32 idcode = ret_payload[1];
340 u32 idcode2 = ret_payload[2] >>
341 ZYNQMP_CSU_VERSION_EMPTY_SHIFT;
342 dev_dbg(dev, "IDCODE: 0x%0x, IDCODE2: 0x%0x\n", idcode,
343 idcode2);
344
345 ret = soc_xilinx_zynqmp_detect_machine(dev, idcode, idcode2);
346 if (ret)
347 return ret;
348 }
349
T Karthik Reddy501c2062021-08-10 06:50:18 -0600350 return 0;
351}
352
353U_BOOT_DRIVER(soc_xilinx_zynqmp) = {
354 .name = "soc_xilinx_zynqmp",
355 .id = UCLASS_SOC,
356 .ops = &soc_xilinx_zynqmp_ops,
357 .probe = soc_xilinx_zynqmp_probe,
358 .priv_auto = sizeof(struct soc_xilinx_zynqmp_priv),
359 .flags = DM_FLAG_PRE_RELOC,
360};