sysreset-uclass.c 2.9 KB

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