soc_xilinx_zynqmp.c 7.7 KB

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