]> Git Repo - J-u-boot.git/blob - drivers/soc/soc_xilinx_zynqmp.c
Merge tag 'u-boot-imx-master-20250127' of https://gitlab.denx.de/u-boot/custodians...
[J-u-boot.git] / drivers / soc / soc_xilinx_zynqmp.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Xilinx ZynqMP SOC driver
4  *
5  * Copyright (C) 2021 Xilinx, Inc.
6  * Michal Simek <[email protected]>
7  *
8  * Copyright (C) 2022 Weidmüller Interface GmbH & Co. KG
9  * Stefan Herbrechtsmeier <[email protected]>
10  */
11
12 #include <dm.h>
13 #include <dm/device_compat.h>
14 #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  */
27 static const char zynqmp_family[] = "ZynqMP";
28
29 #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
37 #define ZYNQMP_VERSION_SIZE     10
38
39 enum {
40         ZYNQMP_VARIANT_EG = BIT(0),
41         ZYNQMP_VARIANT_EV = BIT(1),
42         ZYNQMP_VARIANT_CG = BIT(2),
43         ZYNQMP_VARIANT_DR = BIT(3),
44         ZYNQMP_VARIANT_DR_SE = BIT(4),
45         ZYNQMP_VARIANT_EG_SE = BIT(5),
46         ZYNQMP_VARIANT_TEG = BIT(6),
47         ZYNQMP_VARIANT_EG_LR = BIT(7),
48 };
49
50 struct zynqmp_device {
51         u32 id;
52         u8 device;
53         u8 variants;
54 };
55
56 struct soc_xilinx_zynqmp_priv {
57         const char *family;
58         char machine[ZYNQMP_VERSION_SIZE];
59         char revision;
60 };
61
62 static const struct zynqmp_device zynqmp_devices[] = {
63         {
64                 .id = 0x04688093,
65                 .device = 1,
66                 .variants = ZYNQMP_VARIANT_EG,
67         },
68         {
69                 .id = 0x04689093,
70                 .device = 1,
71                 .variants = ZYNQMP_VARIANT_EG_LR,
72         },
73         {
74                 .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         {
84                 .id = 0x04718093,
85                 .device = 3,
86                 .variants = ZYNQMP_VARIANT_TEG,
87         },
88         {
89                 .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         {
122                 .id = 0x04741093,
123                 .device = 11,
124                 .variants = ZYNQMP_VARIANT_EG_SE,
125         },
126         {
127                 .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         {
142                 .id = 0x0475C093,
143                 .device = 19,
144                 .variants = ZYNQMP_VARIANT_EG_SE,
145         },
146         {
147                 .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         {
197                 .id = 0x047FA093,
198                 .device = 47,
199                 .variants = ZYNQMP_VARIANT_DR_SE,
200         },
201         {
202                 .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         {
217                 .id = 0x046d7093,
218                 .device = 67,
219                 .variants = ZYNQMP_VARIANT_DR_SE,
220         },
221         {
222                 .id = 0x04712093,
223                 .device = 24,
224                 .variants = 0,
225         },
226         {
227                 .id = 0x04724093,
228                 .device = 26,
229                 .variants = 0,
230         },
231 };
232
233 static 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
245 static 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));
307         } else if (device->variants & ZYNQMP_VARIANT_EG_SE) {
308                 strlcat(priv->machine, "eg_SE", sizeof(priv->machine));
309         } else if (device->variants & ZYNQMP_VARIANT_EG_LR) {
310                 strlcat(priv->machine, "eg_LR", sizeof(priv->machine));
311         } else if (device->variants & ZYNQMP_VARIANT_DR) {
312                 strlcat(priv->machine, "dr", sizeof(priv->machine));
313         } else if (device->variants & ZYNQMP_VARIANT_DR_SE) {
314                 strlcat(priv->machine, "dr_SE", sizeof(priv->machine));
315         } else if (device->variants & ZYNQMP_VARIANT_TEG) {
316                 strlcat(priv->machine, "teg", sizeof(priv->machine));
317         }
318
319         return 0;
320 }
321
322 static 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
329 static int soc_xilinx_zynqmp_get_machine(struct udevice *dev, char *buf, int size)
330 {
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
340 static 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
347 static const struct soc_ops soc_xilinx_zynqmp_ops = {
348         .get_family = soc_xilinx_zynqmp_get_family,
349         .get_revision = soc_xilinx_zynqmp_get_revision,
350         .get_machine = soc_xilinx_zynqmp_get_machine,
351 };
352
353 static int soc_xilinx_zynqmp_probe(struct udevice *dev)
354 {
355         struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
356         u32 ret_payload[PAYLOAD_ARG_CNT];
357         int ret;
358
359         priv->family = zynqmp_family;
360
361         if (!IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE))
362                 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
371         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
391         return 0;
392 }
393
394 U_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 };
This page took 0.049342 seconds and 4 git commands to generate.