fdt_reset_thead.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. */
  4. #include <libfdt.h>
  5. #include <sbi/riscv_io.h>
  6. #include <sbi/sbi_bitops.h>
  7. #include <sbi/sbi_hart.h>
  8. #include <sbi/sbi_scratch.h>
  9. #include <sbi_utils/fdt/fdt_helper.h>
  10. #include <sbi_utils/reset/fdt_reset.h>
  11. #include "fdt_reset_thead.h"
  12. struct custom_csr custom_csr[MAX_CUSTOM_CSR];
  13. #define CSR_OPCODE 0x39073
  14. static void clone_csrs(int cnt)
  15. {
  16. unsigned long i;
  17. for (i = 0; i < cnt; i++) {
  18. /* Write csr BIT[31 - 20] to stub */
  19. __reset_thead_csr_stub[3*i + 1] =
  20. CSR_OPCODE | (custom_csr[i].index << 20);
  21. /* Mask csr BIT[31 - 20] */
  22. *(u32 *)&__fdt_reset_thead_csrr &= BIT(20) - 1;
  23. smp_mb();
  24. /* Write csr BIT[31 - 20] to __fdt_reset_thead_csrr */
  25. *(u32 *)&__fdt_reset_thead_csrr |= custom_csr[i].index << 20;
  26. smp_mb();
  27. RISCV_FENCE_I;
  28. custom_csr[i].value = __fdt_reset_thead_csrr();
  29. }
  30. }
  31. extern void __thead_pre_start_warm(void);
  32. static int thead_reset_init(void *fdt, int nodeoff,
  33. const struct fdt_match *match)
  34. {
  35. void *p;
  36. const fdt64_t *val;
  37. const fdt32_t *val_w;
  38. int len, i, cnt;
  39. u32 t, tmp = 0;
  40. /* Prepare clone csrs */
  41. val_w = fdt_getprop(fdt, nodeoff, "csr-copy", &len);
  42. if (len > 0 && val_w) {
  43. cnt = len / sizeof(fdt32_t);
  44. if (cnt > MAX_CUSTOM_CSR)
  45. sbi_hart_hang();
  46. for (i = 0; i < cnt; i++) {
  47. custom_csr[i].index = fdt32_to_cpu(val_w[i]);
  48. }
  49. }
  50. if (cnt)
  51. clone_csrs(cnt);
  52. /* Delegate plic enable regs for S-mode */
  53. val = fdt_getprop(fdt, nodeoff, "plic-delegate", &len);
  54. if (len > 0 && val) {
  55. p = (void *)(ulong)fdt64_to_cpu(*val);
  56. writel(BIT(0), p);
  57. }
  58. /* Old reset method for secondary harts */
  59. if (fdt_getprop(fdt, nodeoff, "using-csr-reset", &len)) {
  60. csr_write(0x7c7, (ulong)&__thead_pre_start_warm);
  61. csr_write(0x7c6, -1);
  62. }
  63. /* Custom reset method for secondary harts */
  64. val = fdt_getprop(fdt, nodeoff, "entry-reg", &len);
  65. if (len > 0 && val) {
  66. p = (void *)(ulong)fdt64_to_cpu(*val);
  67. val_w = fdt_getprop(fdt, nodeoff, "entry-cnt", &len);
  68. if (len > 0 && val_w) {
  69. tmp = fdt32_to_cpu(*val_w);
  70. for (i = 0; i < tmp; i++) {
  71. t = (ulong)&__thead_pre_start_warm;
  72. writel(t, p + (8 * i));
  73. t = (u64)(ulong)&__thead_pre_start_warm >> 32;
  74. writel(t, p + (8 * i) + 4);
  75. }
  76. }
  77. val = fdt_getprop(fdt, nodeoff, "control-reg", &len);
  78. if (len > 0 && val) {
  79. p = (void *)(ulong)fdt64_to_cpu(*val);
  80. val_w = fdt_getprop(fdt, nodeoff, "control-val", &len);
  81. if (len > 0 && val_w) {
  82. tmp = fdt32_to_cpu(*val_w);
  83. tmp |= readl(p);
  84. writel(tmp, p);
  85. }
  86. }
  87. }
  88. return 0;
  89. }
  90. int thead_system_reset_check(u32 type, u32 reason)
  91. {
  92. return 1;
  93. }
  94. void thead_system_reset(u32 type, u32 reason)
  95. {
  96. ebreak();
  97. }
  98. static const struct fdt_match thead_reset_match[] = {
  99. { .compatible = "thead,reset-sample" },
  100. { },
  101. };
  102. struct fdt_reset fdt_reset_thead = {
  103. .match_table = thead_reset_match,
  104. .init = thead_reset_init,
  105. .system_reset_check = thead_system_reset_check,
  106. .system_reset = thead_system_reset
  107. };