firmware-zynqmp.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Xilinx Zynq MPSoC Firmware driver
  4. *
  5. * Copyright (C) 2018-2019 Xilinx, Inc.
  6. */
  7. #include <common.h>
  8. #include <dm.h>
  9. #include <log.h>
  10. #include <zynqmp_firmware.h>
  11. #include <asm/cache.h>
  12. #include <asm/ptrace.h>
  13. #if defined(CONFIG_ZYNQMP_IPI)
  14. #include <mailbox.h>
  15. #include <asm/arch/sys_proto.h>
  16. #define PMUFW_PAYLOAD_ARG_CNT 8
  17. struct zynqmp_power {
  18. struct mbox_chan tx_chan;
  19. struct mbox_chan rx_chan;
  20. } zynqmp_power;
  21. static int ipi_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen)
  22. {
  23. struct zynqmp_ipi_msg msg;
  24. int ret;
  25. if (req_len > PMUFW_PAYLOAD_ARG_CNT ||
  26. res_maxlen > PMUFW_PAYLOAD_ARG_CNT)
  27. return -EINVAL;
  28. if (!(zynqmp_power.tx_chan.dev) || !(&zynqmp_power.rx_chan.dev))
  29. return -EINVAL;
  30. msg.buf = (u32 *)req;
  31. msg.len = req_len;
  32. ret = mbox_send(&zynqmp_power.tx_chan, &msg);
  33. if (ret) {
  34. debug("%s: Sending message failed\n", __func__);
  35. return ret;
  36. }
  37. msg.buf = res;
  38. msg.len = res_maxlen;
  39. ret = mbox_recv(&zynqmp_power.rx_chan, &msg, 100);
  40. if (ret)
  41. debug("%s: Receiving message failed\n", __func__);
  42. return ret;
  43. }
  44. static int send_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen)
  45. {
  46. if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3)
  47. return ipi_req(req, req_len, res, res_maxlen);
  48. return xilinx_pm_request(req[0], 0, 0, 0, 0, res);
  49. }
  50. unsigned int zynqmp_firmware_version(void)
  51. {
  52. int ret;
  53. u32 ret_payload[PAYLOAD_ARG_CNT];
  54. static u32 pm_api_version = ZYNQMP_PM_VERSION_INVALID;
  55. /*
  56. * Get PMU version only once and later
  57. * just return stored values instead of
  58. * asking PMUFW again.
  59. **/
  60. if (pm_api_version == ZYNQMP_PM_VERSION_INVALID) {
  61. const u32 request[] = { PM_GET_API_VERSION };
  62. ret = send_req(request, ARRAY_SIZE(request), ret_payload, 2);
  63. if (ret)
  64. panic("PMUFW is not found - Please load it!\n");
  65. pm_api_version = ret_payload[1];
  66. if (pm_api_version < ZYNQMP_PM_VERSION)
  67. panic("PMUFW version error. Expected: v%d.%d\n",
  68. ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR);
  69. }
  70. return pm_api_version;
  71. };
  72. /**
  73. * Send a configuration object to the PMU firmware.
  74. *
  75. * @cfg_obj: Pointer to the configuration object
  76. * @size: Size of @cfg_obj in bytes
  77. */
  78. void zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size)
  79. {
  80. const u32 request[] = {
  81. PM_SET_CONFIGURATION,
  82. (u32)((u64)cfg_obj)
  83. };
  84. u32 response;
  85. int err;
  86. printf("Loading new PMUFW cfg obj (%ld bytes)\n", size);
  87. err = send_req(request, ARRAY_SIZE(request), &response, 1);
  88. if (err)
  89. panic("Cannot load PMUFW configuration object (%d)\n", err);
  90. if (response != 0)
  91. panic("PMUFW returned 0x%08x status!\n", response);
  92. }
  93. static int zynqmp_power_probe(struct udevice *dev)
  94. {
  95. int ret;
  96. debug("%s, (dev=%p)\n", __func__, dev);
  97. ret = mbox_get_by_name(dev, "tx", &zynqmp_power.tx_chan);
  98. if (ret) {
  99. debug("%s: Cannot find tx mailbox\n", __func__);
  100. return ret;
  101. }
  102. ret = mbox_get_by_name(dev, "rx", &zynqmp_power.rx_chan);
  103. if (ret) {
  104. debug("%s: Cannot find rx mailbox\n", __func__);
  105. return ret;
  106. }
  107. ret = zynqmp_firmware_version();
  108. printf("PMUFW:\tv%d.%d\n",
  109. ret >> ZYNQMP_PM_VERSION_MAJOR_SHIFT,
  110. ret & ZYNQMP_PM_VERSION_MINOR_MASK);
  111. return 0;
  112. };
  113. static const struct udevice_id zynqmp_power_ids[] = {
  114. { .compatible = "xlnx,zynqmp-power" },
  115. { }
  116. };
  117. U_BOOT_DRIVER(zynqmp_power) = {
  118. .name = "zynqmp_power",
  119. .id = UCLASS_FIRMWARE,
  120. .of_match = zynqmp_power_ids,
  121. .probe = zynqmp_power_probe,
  122. };
  123. #endif
  124. int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
  125. u32 arg3, u32 *ret_payload)
  126. {
  127. /*
  128. * Added SIP service call Function Identifier
  129. * Make sure to stay in x0 register
  130. */
  131. struct pt_regs regs;
  132. if (current_el() == 3) {
  133. printf("%s: Can't call SMC from EL3 context\n", __func__);
  134. return -EPERM;
  135. }
  136. regs.regs[0] = PM_SIP_SVC | api_id;
  137. regs.regs[1] = ((u64)arg1 << 32) | arg0;
  138. regs.regs[2] = ((u64)arg3 << 32) | arg2;
  139. smc_call(&regs);
  140. if (ret_payload) {
  141. ret_payload[0] = (u32)regs.regs[0];
  142. ret_payload[1] = upper_32_bits(regs.regs[0]);
  143. ret_payload[2] = (u32)regs.regs[1];
  144. ret_payload[3] = upper_32_bits(regs.regs[1]);
  145. ret_payload[4] = (u32)regs.regs[2];
  146. }
  147. return regs.regs[0];
  148. }
  149. static const struct udevice_id zynqmp_firmware_ids[] = {
  150. { .compatible = "xlnx,zynqmp-firmware" },
  151. { .compatible = "xlnx,versal-firmware"},
  152. { }
  153. };
  154. U_BOOT_DRIVER(zynqmp_firmware) = {
  155. .id = UCLASS_FIRMWARE,
  156. .name = "zynqmp-firmware",
  157. .of_match = zynqmp_firmware_ids,
  158. };