psci.c 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /*
  2. * Copyright (C) 2017 Masahiro Yamada <yamada.masahiro@socionext.com>
  3. *
  4. * Based on drivers/firmware/psci.c from Linux:
  5. * Copyright (C) 2015 ARM Limited
  6. *
  7. * SPDX-License-Identifier: GPL-2.0+
  8. */
  9. #include <common.h>
  10. #include <dm.h>
  11. #include <dm/lists.h>
  12. #include <libfdt.h>
  13. #include <linux/arm-smccc.h>
  14. #include <linux/errno.h>
  15. #include <linux/printk.h>
  16. #include <linux/psci.h>
  17. psci_fn *invoke_psci_fn;
  18. static unsigned long __invoke_psci_fn_hvc(unsigned long function_id,
  19. unsigned long arg0, unsigned long arg1,
  20. unsigned long arg2)
  21. {
  22. struct arm_smccc_res res;
  23. arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
  24. return res.a0;
  25. }
  26. static unsigned long __invoke_psci_fn_smc(unsigned long function_id,
  27. unsigned long arg0, unsigned long arg1,
  28. unsigned long arg2)
  29. {
  30. struct arm_smccc_res res;
  31. arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
  32. return res.a0;
  33. }
  34. static int psci_bind(struct udevice *dev)
  35. {
  36. /* No SYSTEM_RESET support for PSCI 0.1 */
  37. if (device_is_compatible(dev, "arm,psci-0.2") ||
  38. device_is_compatible(dev, "arm,psci-1.0")) {
  39. int ret;
  40. /* bind psci-sysreset optionally */
  41. ret = device_bind_driver(dev, "psci-sysreset", "psci-sysreset",
  42. NULL);
  43. if (ret)
  44. pr_debug("PSCI System Reset was not bound.\n");
  45. }
  46. return 0;
  47. }
  48. static int psci_probe(struct udevice *dev)
  49. {
  50. DECLARE_GLOBAL_DATA_PTR;
  51. const char *method;
  52. method = fdt_stringlist_get(gd->fdt_blob, dev_of_offset(dev), "method",
  53. 0, NULL);
  54. if (!method) {
  55. pr_warn("missing \"method\" property\n");
  56. return -ENXIO;
  57. }
  58. if (!strcmp("hvc", method)) {
  59. invoke_psci_fn = __invoke_psci_fn_hvc;
  60. } else if (!strcmp("smc", method)) {
  61. invoke_psci_fn = __invoke_psci_fn_smc;
  62. } else {
  63. pr_warn("invalid \"method\" property: %s\n", method);
  64. return -EINVAL;
  65. }
  66. return 0;
  67. }
  68. static const struct udevice_id psci_of_match[] = {
  69. { .compatible = "arm,psci" },
  70. { .compatible = "arm,psci-0.2" },
  71. { .compatible = "arm,psci-1.0" },
  72. {},
  73. };
  74. U_BOOT_DRIVER(psci) = {
  75. .name = "psci",
  76. .id = UCLASS_FIRMWARE,
  77. .of_match = psci_of_match,
  78. .bind = psci_bind,
  79. .probe = psci_probe,
  80. };