video: ivybridge: Use mtrr_set_next_var() for graphics memory
[platform/kernel/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 <michal.simek@amd.com>
7  *
8  * Copyright (C) 2022 Weidmüller Interface GmbH & Co. KG
9  * Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com>
10  */
11
12 #include <common.h>
13 #include <dm.h>
14 #include <dm/device_compat.h>
15 #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  */
28 static const char zynqmp_family[] = "ZynqMP";
29
30 #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
40 enum {
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
47 struct zynqmp_device {
48         u32 id;
49         u8 device;
50         u8 variants;
51 };
52
53 struct soc_xilinx_zynqmp_priv {
54         const char *family;
55         char machine[ZYNQMP_VERSION_SIZE];
56         char revision;
57 };
58
59 static 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 = 0x04712093,
190                 .device = 24,
191                 .variants = 0,
192         },
193         {
194                 .id = 0x04724093,
195                 .device = 26,
196                 .variants = 0,
197         },
198 };
199
200 static 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
212 static 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
281 static 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
288 static int soc_xilinx_zynqmp_get_machine(struct udevice *dev, char *buf, int size)
289 {
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
299 static 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
306 static const struct soc_ops soc_xilinx_zynqmp_ops = {
307         .get_family = soc_xilinx_zynqmp_get_family,
308         .get_revision = soc_xilinx_zynqmp_get_revision,
309         .get_machine = soc_xilinx_zynqmp_get_machine,
310 };
311
312 static int soc_xilinx_zynqmp_probe(struct udevice *dev)
313 {
314         struct soc_xilinx_zynqmp_priv *priv = dev_get_priv(dev);
315         u32 ret_payload[PAYLOAD_ARG_CNT];
316         int ret;
317
318         priv->family = zynqmp_family;
319
320         if (!IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE))
321                 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
330         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
350         return 0;
351 }
352
353 U_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 };