123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- /*
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2022 Andes Technology Corporation
- *
- * Authors:
- * Yu Chien Peter Lin <peterlin@andestech.com>
- */
- #include <sbi/riscv_asm.h>
- #include <sbi/riscv_io.h>
- #include <sbi/sbi_domain.h>
- #include <sbi/sbi_error.h>
- #include <sbi/sbi_timer.h>
- #include <sbi_utils/timer/andes_plmt.h>
- struct plmt_data plmt;
- static u64 plmt_timer_value(void)
- {
- #if __riscv_xlen == 64
- return readq_relaxed(plmt.time_val);
- #else
- u32 lo, hi;
- do {
- hi = readl_relaxed((void *)plmt.time_val + 0x04);
- lo = readl_relaxed(plmt.time_val);
- } while (hi != readl_relaxed((void *)plmt.time_val + 0x04));
- return ((u64)hi << 32) | (u64)lo;
- #endif
- }
- static void plmt_timer_event_stop(void)
- {
- u32 target_hart = current_hartid();
- if (plmt.hart_count <= target_hart)
- ebreak();
- /* Clear PLMT Time Compare */
- #if __riscv_xlen == 64
- writeq_relaxed(-1ULL, &plmt.time_cmp[target_hart]);
- #else
- writel_relaxed(-1UL, &plmt.time_cmp[target_hart]);
- writel_relaxed(-1UL, (void *)(&plmt.time_cmp[target_hart]) + 0x04);
- #endif
- }
- static void plmt_timer_event_start(u64 next_event)
- {
- u32 target_hart = current_hartid();
- if (plmt.hart_count <= target_hart)
- ebreak();
- /* Program PLMT Time Compare */
- #if __riscv_xlen == 64
- writeq_relaxed(next_event, &plmt.time_cmp[target_hart]);
- #else
- u32 mask = -1UL;
- writel_relaxed(next_event & mask, &plmt.time_cmp[target_hart]);
- writel_relaxed(next_event >> 32,
- (void *)(&plmt.time_cmp[target_hart]) + 0x04);
- #endif
- }
- static struct sbi_timer_device plmt_timer = {
- .name = "andes_plmt",
- .timer_freq = DEFAULT_AE350_PLMT_FREQ,
- .timer_value = plmt_timer_value,
- .timer_event_start = plmt_timer_event_start,
- .timer_event_stop = plmt_timer_event_stop
- };
- int plmt_cold_timer_init(struct plmt_data *plmt)
- {
- int rc;
- /* Add PLMT region to the root domain */
- rc = sbi_domain_root_add_memrange(
- (unsigned long)plmt->time_val, plmt->size, PLMT_REGION_ALIGN,
- SBI_DOMAIN_MEMREGION_MMIO | SBI_DOMAIN_MEMREGION_READABLE);
- if (rc)
- return rc;
- plmt_timer.timer_freq = plmt->timer_freq;
- sbi_timer_set_device(&plmt_timer);
- return 0;
- }
- int plmt_warm_timer_init(void)
- {
- if (!plmt.time_val)
- return SBI_ENODEV;
- plmt_timer_event_stop();
- return 0;
- }
|