sysreset-uclass.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2015 Google, Inc
  4. * Written by Simon Glass <sjg@chromium.org>
  5. */
  6. #define LOG_CATEGORY UCLASS_SYSRESET
  7. #include <common.h>
  8. #include <cpu_func.h>
  9. #include <hang.h>
  10. #include <sysreset.h>
  11. #include <dm.h>
  12. #include <errno.h>
  13. #include <regmap.h>
  14. #include <dm/device-internal.h>
  15. #include <dm/lists.h>
  16. #include <dm/root.h>
  17. #include <linux/err.h>
  18. int sysreset_request(struct udevice *dev, enum sysreset_t type)
  19. {
  20. struct sysreset_ops *ops = sysreset_get_ops(dev);
  21. if (!ops->request)
  22. return -ENOSYS;
  23. return ops->request(dev, type);
  24. }
  25. int sysreset_get_status(struct udevice *dev, char *buf, int size)
  26. {
  27. struct sysreset_ops *ops = sysreset_get_ops(dev);
  28. if (!ops->get_status)
  29. return -ENOSYS;
  30. return ops->get_status(dev, buf, size);
  31. }
  32. int sysreset_get_last(struct udevice *dev)
  33. {
  34. struct sysreset_ops *ops = sysreset_get_ops(dev);
  35. if (!ops->get_last)
  36. return -ENOSYS;
  37. return ops->get_last(dev);
  38. }
  39. int sysreset_walk(enum sysreset_t type)
  40. {
  41. struct udevice *dev;
  42. int ret = -ENOSYS;
  43. while (ret != -EINPROGRESS && type < SYSRESET_COUNT) {
  44. for (uclass_first_device(UCLASS_SYSRESET, &dev);
  45. dev;
  46. uclass_next_device(&dev)) {
  47. ret = sysreset_request(dev, type);
  48. if (ret == -EINPROGRESS)
  49. break;
  50. }
  51. type++;
  52. }
  53. return ret;
  54. }
  55. int sysreset_get_last_walk(void)
  56. {
  57. struct udevice *dev;
  58. int value = -ENOENT;
  59. for (uclass_first_device(UCLASS_SYSRESET, &dev);
  60. dev;
  61. uclass_next_device(&dev)) {
  62. int ret;
  63. ret = sysreset_get_last(dev);
  64. if (ret >= 0) {
  65. value = ret;
  66. break;
  67. }
  68. }
  69. return value;
  70. }
  71. void sysreset_walk_halt(enum sysreset_t type)
  72. {
  73. int ret;
  74. ret = sysreset_walk(type);
  75. /* Wait for the reset to take effect */
  76. if (ret == -EINPROGRESS)
  77. mdelay(100);
  78. /* Still no reset? Give up */
  79. log_err("System reset not supported on this platform\n");
  80. hang();
  81. }
  82. /**
  83. * reset_cpu() - calls sysreset_walk(SYSRESET_WARM)
  84. */
  85. void reset_cpu(ulong addr)
  86. {
  87. sysreset_walk_halt(SYSRESET_WARM);
  88. }
  89. int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  90. {
  91. printf("resetting ...\n");
  92. sysreset_walk_halt(SYSRESET_COLD);
  93. return 0;
  94. }
  95. #if IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF)
  96. int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  97. {
  98. int ret;
  99. puts("poweroff ...\n");
  100. mdelay(100);
  101. ret = sysreset_walk(SYSRESET_POWER_OFF);
  102. if (ret == -EINPROGRESS)
  103. mdelay(1000);
  104. /*NOTREACHED when power off*/
  105. return CMD_RET_FAILURE;
  106. }
  107. #endif
  108. static int sysreset_post_bind(struct udevice *dev)
  109. {
  110. #if defined(CONFIG_NEEDS_MANUAL_RELOC)
  111. struct sysreset_ops *ops = sysreset_get_ops(dev);
  112. static int reloc_done;
  113. if (!reloc_done) {
  114. if (ops->request)
  115. ops->request += gd->reloc_off;
  116. reloc_done++;
  117. }
  118. #endif
  119. return 0;
  120. }
  121. UCLASS_DRIVER(sysreset) = {
  122. .id = UCLASS_SYSRESET,
  123. .name = "sysreset",
  124. .post_bind = sysreset_post_bind,
  125. };