feat(intel): implement timer init divider via CPU frequency for N5X

Get CPU frequency and update the timer init div with it.
The timer is vary based on the CPU frequency instead of hardcoded.

Signed-off-by: Jit Loon Lim <jit.loon.lim@intel.com>
Signed-off-by: Sieu Mun Tang <sieu.mun.tang@intel.com>
Change-Id: Ibfaa47fb7a25176eebf06f4828bf9729d56f12ed
diff --git a/plat/intel/soc/agilex/include/agilex_clock_manager.h b/plat/intel/soc/agilex/include/agilex_clock_manager.h
index f39d475..8ec8e59 100644
--- a/plat/intel/soc/agilex/include/agilex_clock_manager.h
+++ b/plat/intel/soc/agilex/include/agilex_clock_manager.h
@@ -127,5 +127,6 @@
 uint32_t get_wdt_clk(void);
 uint32_t get_uart_clk(void);
 uint32_t get_mmc_clk(void);
+uint32_t get_cpu_clk(void);
 
 #endif
diff --git a/plat/intel/soc/agilex/include/socfpga_plat_def.h b/plat/intel/soc/agilex/include/socfpga_plat_def.h
index b216ab1..4d7198c 100644
--- a/plat/intel/soc/agilex/include/socfpga_plat_def.h
+++ b/plat/intel/soc/agilex/include/socfpga_plat_def.h
@@ -35,6 +35,4 @@
 /* Platform specific system counter */
 #define PLAT_SYS_COUNTER_FREQ_IN_MHZ	get_cpu_clk()
 
-uint32_t get_cpu_clk(void);
-
 #endif /* PLAT_SOCFPGA_DEF_H */
diff --git a/plat/intel/soc/common/socfpga_delay_timer.c b/plat/intel/soc/common/socfpga_delay_timer.c
index dcd51e2..8fce5cf 100644
--- a/plat/intel/soc/common/socfpga_delay_timer.c
+++ b/plat/intel/soc/common/socfpga_delay_timer.c
@@ -10,6 +10,15 @@
 #include <lib/mmio.h>
 #include "socfpga_plat_def.h"
 
+
+#if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX
+#include "agilex_clock_manager.h"
+#elif PLATFORM_MODEL == PLAT_SOCFPGA_N5X
+#include "n5x_clock_manager.h"
+#elif PLATFORM_MODEL == PLAT_SOCFPGA_STRATIX10
+#include "s10_clock_manager.h"
+#endif
+
 #define SOCFPGA_GLOBAL_TIMER		0xffd01000
 #define SOCFPGA_GLOBAL_TIMER_EN		0x3
 
@@ -43,6 +52,8 @@
 	socfpga_delay_timer_init_args();
 	mmio_write_32(SOCFPGA_GLOBAL_TIMER, SOCFPGA_GLOBAL_TIMER_EN);
 
+	NOTICE("BL31 CLK freq = %d MHz\n", PLAT_SYS_COUNTER_FREQ_IN_MHZ);
+
 	asm volatile("msr cntp_ctl_el0, %0" : : "r" (SOCFPGA_GLOBAL_TIMER_EN));
 	asm volatile("msr cntp_tval_el0, %0" : : "r" (~0));
 
diff --git a/plat/intel/soc/n5x/include/n5x_clock_manager.h b/plat/intel/soc/n5x/include/n5x_clock_manager.h
new file mode 100644
index 0000000..6e2b978
--- /dev/null
+++ b/plat/intel/soc/n5x/include/n5x_clock_manager.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CLOCKMANAGER_H
+#define CLOCKMANAGER_H
+
+#include "socfpga_handoff.h"
+
+/* MACRO DEFINITION */
+#define SOCFPGA_GLOBAL_TIMER				0xffd01000
+#define SOCFPGA_GLOBAL_TIMER_EN				0x3
+
+#define CLKMGR_PLLGLOB_VCO_PSRC_MASK			GENMASK(17, 16)
+#define CLKMGR_PLLGLOB_VCO_PSRC_OFFSET			16
+#define CLKMGR_PLLDIV_FDIV_MASK				GENMASK(16, 8)
+#define CLKMGR_PLLDIV_FDIV_OFFSET			8
+#define CLKMGR_PLLDIV_REFCLKDIV_MASK			GENMASK(5, 0)
+#define CLKMGR_PLLDIV_REFCLKDIV_OFFSET			0
+#define CLKMGR_PLLDIV_OUTDIV_QDIV_MASK			GENMASK(26, 24)
+#define CLKMGR_PLLDIV_OUTDIV_QDIV_OFFSET		24
+
+#define CLKMGR_PLLOUTDIV_C1CNT_MASK			GENMASK(12, 8)
+#define CLKMGR_PLLOUTDIV_C1CNT_OFFSET			8
+#define CLKMGR_PLLDIV_OUTDIV_QDIV_MASK			GENMASK(26, 24)
+#define CLKMGR_PLLDIV_OUTDIV_QDIV_OFFSET		24
+#define CLKMGR_CLKSRC_MASK				GENMASK(18, 16)
+#define CLKMGR_CLKSRC_OFFSET				16
+#define CLKMGR_NOCDIV_DIVIDER_MASK			GENMASK(1, 0)
+#define CLKMGR_NOCDIV_L4MAIN_OFFSET			0
+
+#define CLKMGR_INTOSC_HZ				400000000
+#define CLKMGR_VCO_PSRC_EOSC1				0
+#define CLKMGR_VCO_PSRC_INTOSC				1
+#define CLKMGR_VCO_PSRC_F2S				2
+#define CLKMGR_CLKSRC_MAIN				0
+#define CLKMGR_CLKSRC_PER				1
+
+#define CLKMGR_N5X_BASE					0xffd10000
+#define CLKMGR_MAINPLL_NOCCLK				0x40
+#define CLKMGR_MAINPLL_NOCDIV				0x44
+#define CLKMGR_MAINPLL_PLLGLOB				0x48
+#define CLKMGR_MAINPLL_PLLOUTDIV			0x54
+#define CLKMGR_MAINPLL_PLLDIV				0x50
+#define CLKMGR_PERPLL_PLLGLOB				0x9c
+#define CLKMGR_PERPLL_PLLDIV				0xa4
+#define CLKMGR_PERPLL_PLLOUTDIV				0xa8
+
+/* FUNCTION DEFINITION */
+uint64_t clk_get_pll_output_hz(void);
+uint64_t get_l4_clk(void);
+uint32_t get_clk_freq(uint32_t psrc_reg);
+uint32_t get_cpu_clk(void);
+
+#endif
diff --git a/plat/intel/soc/n5x/include/socfpga_plat_def.h b/plat/intel/soc/n5x/include/socfpga_plat_def.h
index 4c36f91..eec8411 100644
--- a/plat/intel/soc/n5x/include/socfpga_plat_def.h
+++ b/plat/intel/soc/n5x/include/socfpga_plat_def.h
@@ -32,11 +32,6 @@
 #define SOCFPGA_SOC2FPGA_SCR_REG_BASE			U(0xffd21200)
 #define SOCFPGA_LWSOC2FPGA_SCR_REG_BASE			U(0xffd21300)
 
-/* Platform specific system counter */
-/*
- * In N5X the clk init is done in Uboot SPL.
- * BL31 shall bypass the clk init and only provides other APIs.
- */
-#define PLAT_SYS_COUNTER_FREQ_IN_MHZ	(400)
+#define PLAT_SYS_COUNTER_FREQ_IN_MHZ	get_cpu_clk()
 
 #endif /* PLAT_SOCFPGA_DEF_H */
diff --git a/plat/intel/soc/n5x/platform.mk b/plat/intel/soc/n5x/platform.mk
index 4f3da4e..7afeb74 100644
--- a/plat/intel/soc/n5x/platform.mk
+++ b/plat/intel/soc/n5x/platform.mk
@@ -36,6 +36,7 @@
 		lib/cpus/aarch64/cortex_a53.S				\
 		plat/common/plat_psci_common.c				\
 		plat/intel/soc/n5x/bl31_plat_setup.c			\
+		plat/intel/soc/n5x/soc/n5x_clock_manager.c		\
 		plat/intel/soc/common/socfpga_psci.c			\
 		plat/intel/soc/common/socfpga_sip_svc.c			\
 		plat/intel/soc/common/socfpga_sip_svc_v2.c		\
diff --git a/plat/intel/soc/n5x/soc/n5x_clock_manager.c b/plat/intel/soc/n5x/soc/n5x_clock_manager.c
new file mode 100644
index 0000000..c09b25b
--- /dev/null
+++ b/plat/intel/soc/n5x/soc/n5x_clock_manager.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include "n5x_clock_manager.h"
+#include "socfpga_system_manager.h"
+
+
+uint64_t clk_get_pll_output_hz(void)
+{
+	uint32_t clksrc;
+	uint32_t scr_reg;
+	uint32_t divf;
+	uint32_t divr;
+	uint32_t divq;
+	uint32_t power = 1;
+	uint64_t clock = 0;
+
+	clksrc = ((get_clk_freq(CLKMGR_PERPLL_PLLGLOB)) &
+			CLKMGR_PLLGLOB_VCO_PSRC_MASK) >> CLKMGR_PLLGLOB_VCO_PSRC_OFFSET;
+
+	switch (clksrc) {
+	case CLKMGR_VCO_PSRC_EOSC1:
+		scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_1);
+		clock = mmio_read_32(scr_reg);
+		break;
+
+	case CLKMGR_VCO_PSRC_INTOSC:
+		clock = CLKMGR_INTOSC_HZ;
+		break;
+
+	case CLKMGR_VCO_PSRC_F2S:
+		scr_reg = SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_2);
+		clock = mmio_read_32(scr_reg);
+		break;
+	}
+
+	divf = ((get_clk_freq(CLKMGR_PERPLL_PLLDIV)) &
+			CLKMGR_PLLDIV_FDIV_MASK) >> CLKMGR_PLLDIV_FDIV_OFFSET;
+	divr = ((get_clk_freq(CLKMGR_PERPLL_PLLDIV)) &
+			CLKMGR_PLLDIV_REFCLKDIV_MASK) >> CLKMGR_PLLDIV_REFCLKDIV_OFFSET;
+	divq = ((get_clk_freq(CLKMGR_PERPLL_PLLDIV)) &
+			CLKMGR_PLLDIV_OUTDIV_QDIV_MASK) >> CLKMGR_PLLDIV_OUTDIV_QDIV_OFFSET;
+
+	while (divq) {
+		power *= 2;
+		divq--;
+	}
+
+	return ((clock * 2 * (divf + 1)) / ((divr + 1) * power));
+}
+
+uint64_t get_l4_clk(void)
+{
+	uint32_t clock = 0;
+	uint32_t mainpll_c1cnt;
+	uint32_t perpll_c1cnt;
+	uint32_t clksrc;
+
+	mainpll_c1cnt = ((get_clk_freq(CLKMGR_MAINPLL_PLLOUTDIV)) &
+			CLKMGR_PLLOUTDIV_C1CNT_MASK) >> CLKMGR_PLLOUTDIV_C1CNT_OFFSET;
+
+	perpll_c1cnt = ((get_clk_freq(CLKMGR_PERPLL_PLLOUTDIV)) &
+			CLKMGR_PLLOUTDIV_C1CNT_MASK) >> CLKMGR_PLLOUTDIV_C1CNT_OFFSET;
+
+	clksrc = ((get_clk_freq(CLKMGR_MAINPLL_NOCCLK)) & CLKMGR_CLKSRC_MASK) >>
+			CLKMGR_CLKSRC_OFFSET;
+
+	switch (clksrc) {
+	case CLKMGR_CLKSRC_MAIN:
+		clock = clk_get_pll_output_hz();
+		clock /= 1 + mainpll_c1cnt;
+		break;
+
+	case CLKMGR_CLKSRC_PER:
+		clock = clk_get_pll_output_hz();
+		clock /= 1 + perpll_c1cnt;
+		break;
+
+	default:
+		return 0;
+	}
+
+	clock /= BIT(((get_clk_freq(CLKMGR_MAINPLL_NOCDIV)) >>
+			CLKMGR_NOCDIV_L4MAIN_OFFSET) & CLKMGR_NOCDIV_DIVIDER_MASK);
+
+	return clock;
+}
+
+/* Calculate clock frequency based on parameter */
+uint32_t get_clk_freq(uint32_t psrc_reg)
+{
+	uint32_t clk_psrc;
+
+	clk_psrc = mmio_read_32(CLKMGR_N5X_BASE + psrc_reg);
+
+	return clk_psrc;
+}
+
+/* Get cpu freq clock */
+uint32_t get_cpu_clk(void)
+{
+	uint32_t cpu_clk = 0;
+
+	cpu_clk = get_l4_clk()/PLAT_SYS_COUNTER_CONVERT_TO_MHZ;
+
+	return cpu_clk;
+}
diff --git a/plat/intel/soc/stratix10/include/s10_clock_manager.h b/plat/intel/soc/stratix10/include/s10_clock_manager.h
index cf57df3..661e204 100644
--- a/plat/intel/soc/stratix10/include/s10_clock_manager.h
+++ b/plat/intel/soc/stratix10/include/s10_clock_manager.h
@@ -95,5 +95,6 @@
 uint32_t get_mmc_clk(void);
 uint32_t get_l3_clk(uint32_t ref_clk);
 uint32_t get_ref_clk(uint32_t pllglob);
+uint32_t get_cpu_clk(void);
 
 #endif
diff --git a/plat/intel/soc/stratix10/include/socfpga_plat_def.h b/plat/intel/soc/stratix10/include/socfpga_plat_def.h
index 516cc75..da6414f 100644
--- a/plat/intel/soc/stratix10/include/socfpga_plat_def.h
+++ b/plat/intel/soc/stratix10/include/socfpga_plat_def.h
@@ -34,7 +34,5 @@
 /* Platform specific system counter */
 #define PLAT_SYS_COUNTER_FREQ_IN_MHZ	get_cpu_clk()
 
-uint32_t get_cpu_clk(void);
-
 #endif /* PLATSOCFPGA_DEF_H */