sysreset-uclass.c 2.5 KB

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