plmt.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2019 Andes Technology Corporation
  5. *
  6. * Authors:
  7. * Zong Li <zong@andestech.com>
  8. * Nylon Chen <nylon7@andestech.com>
  9. */
  10. #include <sbi/riscv_asm.h>
  11. #include <sbi/riscv_io.h>
  12. #include <sbi/sbi_timer.h>
  13. static u32 plmt_time_hart_count;
  14. static volatile void *plmt_time_base;
  15. static volatile u64 *plmt_time_val;
  16. static volatile u64 *plmt_time_cmp;
  17. static u64 plmt_timer_value(void)
  18. {
  19. #if __riscv_xlen == 64
  20. return readq_relaxed(plmt_time_val);
  21. #else
  22. u32 lo, hi;
  23. do {
  24. hi = readl_relaxed((void *)plmt_time_val + 0x04);
  25. lo = readl_relaxed(plmt_time_val);
  26. } while (hi != readl_relaxed((void *)plmt_time_val + 0x04));
  27. return ((u64)hi << 32) | (u64)lo;
  28. #endif
  29. }
  30. static void plmt_timer_event_stop(void)
  31. {
  32. u32 target_hart = current_hartid();
  33. if (plmt_time_hart_count <= target_hart)
  34. return;
  35. /* Clear PLMT Time Compare */
  36. #if __riscv_xlen == 64
  37. writeq_relaxed(-1ULL, &plmt_time_cmp[target_hart]);
  38. #else
  39. writel_relaxed(-1UL, &plmt_time_cmp[target_hart]);
  40. writel_relaxed(-1UL, (void *)(&plmt_time_cmp[target_hart]) + 0x04);
  41. #endif
  42. }
  43. static void plmt_timer_event_start(u64 next_event)
  44. {
  45. u32 target_hart = current_hartid();
  46. if (plmt_time_hart_count <= target_hart)
  47. return;
  48. /* Program PLMT Time Compare */
  49. #if __riscv_xlen == 64
  50. writeq_relaxed(next_event, &plmt_time_cmp[target_hart]);
  51. #else
  52. u32 mask = -1UL;
  53. writel_relaxed(next_event & mask, &plmt_time_cmp[target_hart]);
  54. writel_relaxed(next_event >> 32,
  55. (void *)(&plmt_time_cmp[target_hart]) + 0x04);
  56. #endif
  57. }
  58. static struct sbi_timer_device plmt_timer = {
  59. .name = "ae350_plmt",
  60. .timer_value = plmt_timer_value,
  61. .timer_event_start = plmt_timer_event_start,
  62. .timer_event_stop = plmt_timer_event_stop
  63. };
  64. int plmt_warm_timer_init(void)
  65. {
  66. u32 target_hart = current_hartid();
  67. if (plmt_time_hart_count <= target_hart || !plmt_time_base)
  68. return -1;
  69. /* Clear PLMT Time Compare */
  70. #if __riscv_xlen == 64
  71. writeq_relaxed(-1ULL, &plmt_time_cmp[target_hart]);
  72. #else
  73. writel_relaxed(-1UL, &plmt_time_cmp[target_hart]);
  74. writel_relaxed(-1UL, (void *)(&plmt_time_cmp[target_hart]) + 0x04);
  75. #endif
  76. return 0;
  77. }
  78. int plmt_cold_timer_init(unsigned long base, u32 hart_count)
  79. {
  80. plmt_time_hart_count = hart_count;
  81. plmt_time_base = (void *)base;
  82. plmt_time_val = (u64 *)(plmt_time_base);
  83. plmt_time_cmp = (u64 *)(plmt_time_base + 0x8);
  84. sbi_timer_set_device(&plmt_timer);
  85. return 0;
  86. }