andes_plmt.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2022 Andes Technology Corporation
  5. *
  6. * Authors:
  7. * Yu Chien Peter Lin <peterlin@andestech.com>
  8. */
  9. #include <sbi/riscv_asm.h>
  10. #include <sbi/riscv_io.h>
  11. #include <sbi/sbi_domain.h>
  12. #include <sbi/sbi_error.h>
  13. #include <sbi/sbi_timer.h>
  14. #include <sbi_utils/timer/andes_plmt.h>
  15. struct plmt_data plmt;
  16. static u64 plmt_timer_value(void)
  17. {
  18. #if __riscv_xlen == 64
  19. return readq_relaxed(plmt.time_val);
  20. #else
  21. u32 lo, hi;
  22. do {
  23. hi = readl_relaxed((void *)plmt.time_val + 0x04);
  24. lo = readl_relaxed(plmt.time_val);
  25. } while (hi != readl_relaxed((void *)plmt.time_val + 0x04));
  26. return ((u64)hi << 32) | (u64)lo;
  27. #endif
  28. }
  29. static void plmt_timer_event_stop(void)
  30. {
  31. u32 target_hart = current_hartid();
  32. if (plmt.hart_count <= target_hart)
  33. ebreak();
  34. /* Clear PLMT Time Compare */
  35. #if __riscv_xlen == 64
  36. writeq_relaxed(-1ULL, &plmt.time_cmp[target_hart]);
  37. #else
  38. writel_relaxed(-1UL, &plmt.time_cmp[target_hart]);
  39. writel_relaxed(-1UL, (void *)(&plmt.time_cmp[target_hart]) + 0x04);
  40. #endif
  41. }
  42. static void plmt_timer_event_start(u64 next_event)
  43. {
  44. u32 target_hart = current_hartid();
  45. if (plmt.hart_count <= target_hart)
  46. ebreak();
  47. /* Program PLMT Time Compare */
  48. #if __riscv_xlen == 64
  49. writeq_relaxed(next_event, &plmt.time_cmp[target_hart]);
  50. #else
  51. u32 mask = -1UL;
  52. writel_relaxed(next_event & mask, &plmt.time_cmp[target_hart]);
  53. writel_relaxed(next_event >> 32,
  54. (void *)(&plmt.time_cmp[target_hart]) + 0x04);
  55. #endif
  56. }
  57. static struct sbi_timer_device plmt_timer = {
  58. .name = "andes_plmt",
  59. .timer_freq = DEFAULT_AE350_PLMT_FREQ,
  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_cold_timer_init(struct plmt_data *plmt)
  65. {
  66. int rc;
  67. /* Add PLMT region to the root domain */
  68. rc = sbi_domain_root_add_memrange(
  69. (unsigned long)plmt->time_val, plmt->size, PLMT_REGION_ALIGN,
  70. SBI_DOMAIN_MEMREGION_MMIO | SBI_DOMAIN_MEMREGION_READABLE);
  71. if (rc)
  72. return rc;
  73. plmt_timer.timer_freq = plmt->timer_freq;
  74. sbi_timer_set_device(&plmt_timer);
  75. return 0;
  76. }
  77. int plmt_warm_timer_init(void)
  78. {
  79. if (!plmt.time_val)
  80. return SBI_ENODEV;
  81. plmt_timer_event_stop();
  82. return 0;
  83. }