fdt_reset_gpio.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2021 SiFive
  5. * Copyright (c) 2021 Western Digital Corporation or its affiliates.
  6. *
  7. * Authors:
  8. * Green Wan <green.wan@sifive.com>
  9. * Anup Patel <anup.patel@wdc.com>
  10. */
  11. #include <libfdt.h>
  12. #include <sbi/sbi_console.h>
  13. #include <sbi/sbi_ecall_interface.h>
  14. #include <sbi/sbi_hart.h>
  15. #include <sbi/sbi_system.h>
  16. #include <sbi_utils/fdt/fdt_helper.h>
  17. #include <sbi_utils/gpio/fdt_gpio.h>
  18. #include <sbi_utils/reset/fdt_reset.h>
  19. struct gpio_reset {
  20. struct gpio_pin pin;
  21. u32 active_delay;
  22. u32 inactive_delay;
  23. };
  24. static struct gpio_reset poweroff = {
  25. .active_delay = 100,
  26. .inactive_delay = 100
  27. };
  28. static struct gpio_reset restart = {
  29. .active_delay = 100,
  30. .inactive_delay = 100
  31. };
  32. /* Custom mdelay function until we have a generic mdelay() API */
  33. static void gpio_mdelay(unsigned long msecs)
  34. {
  35. volatile int i;
  36. while (msecs--)
  37. for (i = 0; i < 100000; i++) ;
  38. }
  39. static int gpio_system_reset_check(u32 type, u32 reason)
  40. {
  41. switch (type) {
  42. case SBI_SRST_RESET_TYPE_SHUTDOWN:
  43. case SBI_SRST_RESET_TYPE_COLD_REBOOT:
  44. case SBI_SRST_RESET_TYPE_WARM_REBOOT:
  45. return 1;
  46. }
  47. return 0;
  48. }
  49. static void gpio_system_reset(u32 type, u32 reason)
  50. {
  51. struct gpio_reset *reset = NULL;
  52. switch (type) {
  53. case SBI_SRST_RESET_TYPE_SHUTDOWN:
  54. reset = &poweroff;
  55. break;
  56. case SBI_SRST_RESET_TYPE_COLD_REBOOT:
  57. case SBI_SRST_RESET_TYPE_WARM_REBOOT:
  58. reset = &restart;
  59. break;
  60. }
  61. if (reset) {
  62. if (!reset->pin.chip) {
  63. sbi_printf("%s: gpio pin not available\n", __func__);
  64. goto skip_reset;
  65. }
  66. /* drive it active, also inactive->active edge */
  67. gpio_direction_output(&reset->pin, 1);
  68. gpio_mdelay(reset->active_delay);
  69. /* drive inactive, also active->inactive edge */
  70. gpio_set(&reset->pin, 0);
  71. gpio_mdelay(reset->inactive_delay);
  72. /* drive it active, also inactive->active edge */
  73. gpio_set(&reset->pin, 1);
  74. skip_reset:
  75. /* hang !!! */
  76. sbi_hart_hang();
  77. }
  78. }
  79. static struct sbi_system_reset_device gpio_reset = {
  80. .name = "gpio-reset",
  81. .system_reset_check = gpio_system_reset_check,
  82. .system_reset = gpio_system_reset
  83. };
  84. static int gpio_reset_init(void *fdt, int nodeoff,
  85. const struct fdt_match *match)
  86. {
  87. int rc, len;
  88. const fdt32_t *val;
  89. bool is_restart = (ulong)match->data;
  90. const char *dir_prop = (is_restart) ? "open-source" : "input";
  91. struct gpio_reset *reset = (is_restart) ? &restart : &poweroff;
  92. rc = fdt_gpio_pin_get(fdt, nodeoff, 0, &reset->pin);
  93. if (rc)
  94. return rc;
  95. if (fdt_getprop(fdt, nodeoff, dir_prop, &len)) {
  96. rc = gpio_direction_input(&reset->pin);
  97. if (rc)
  98. return rc;
  99. }
  100. val = fdt_getprop(fdt, nodeoff, "active-delay-ms", &len);
  101. if (len > 0)
  102. reset->active_delay = fdt32_to_cpu(*val);
  103. val = fdt_getprop(fdt, nodeoff, "inactive-delay-ms", &len);
  104. if (len > 0)
  105. reset->inactive_delay = fdt32_to_cpu(*val);
  106. sbi_system_reset_set_device(&gpio_reset);
  107. return 0;
  108. }
  109. static const struct fdt_match gpio_poweroff_match[] = {
  110. { .compatible = "gpio-poweroff", .data = (void *)FALSE },
  111. { },
  112. };
  113. struct fdt_reset fdt_poweroff_gpio = {
  114. .match_table = gpio_poweroff_match,
  115. .init = gpio_reset_init,
  116. };
  117. static const struct fdt_match gpio_reset_match[] = {
  118. { .compatible = "gpio-restart", .data = (void *)TRUE },
  119. { },
  120. };
  121. struct fdt_reset fdt_reset_gpio = {
  122. .match_table = gpio_reset_match,
  123. .init = gpio_reset_init,
  124. };