mirror of
				https://github.com/riscv-software-src/opensbi
				synced 2025-11-04 05:50:22 +00:00 
			
		
		
		
	Since we can get the PLMT base address and timer frequency from
device tree, move plmt timer device to fdt timer framework.
dts example (Quad-core AX45MP):
  cpus {
      ...
      timebase-frequency = <0x3938700>;
      ...
  }
  soc {
      ...
      plmt0@e6000000 {
          compatible = "andestech,plmt0";
          reg = <0x00 0xe6000000 0x00 0x100000>;
          interrupts-extended = <&cpu0_intc 0x07
                                 &cpu1_intc 0x07
                                 &cpu2_intc 0x07
                                 &cpu3_intc 0x07>;
      };
      ...
  }
Signed-off-by: Yu Chien Peter Lin <peterlin@andestech.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
		
	
			
		
			
				
	
	
		
			105 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			105 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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;
 | 
						|
}
 |