intel: Enable watchdog timer on Intel S10 platform
Watchdog driver support & enablement during platform setup

Signed-off-by: Muhammad Hadi Asyrafi Abdul Halim <muhammad.hadi.asyrafi.abdul.halim@intel.com>
diff --git a/plat/intel/soc/stratix10/bl2_plat_setup.c b/plat/intel/soc/stratix10/bl2_plat_setup.c
index 9a2f9d3..58e8c02 100644
--- a/plat/intel/soc/stratix10/bl2_plat_setup.c
+++ b/plat/intel/soc/stratix10/bl2_plat_setup.c
@@ -32,6 +32,7 @@
 #include "aarch64/stratix10_private.h"
 #include "include/s10_mailbox.h"
 #include "drivers/qspi/cadence_qspi.h"
+#include "drivers/wdt/watchdog.h"
 
 
 const mmap_region_t plat_stratix10_mmap[] = {
@@ -72,6 +73,8 @@
 	deassert_peripheral_reset();
 	config_hps_hs_before_warm_reset();
 
+	watchdog_init(get_wdt_clk(&reverse_handoff_ptr));
+
 	console_16550_register(PLAT_UART0_BASE, PLAT_UART_CLOCK, PLAT_BAUDRATE,
 		&console);
 
diff --git a/plat/intel/soc/stratix10/drivers/wdt/watchdog.c b/plat/intel/soc/stratix10/drivers/wdt/watchdog.c
new file mode 100644
index 0000000..b4dbe5f
--- /dev/null
+++ b/plat/intel/soc/stratix10/drivers/wdt/watchdog.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#include "watchdog.h"
+
+
+/* Reset watchdog timer */
+void watchdog_sw_rst(void)
+{
+	mmio_write_32(WDT_CRR, WDT_SW_RST);
+}
+
+/* Print component information */
+void watchdog_info(void)
+{
+	INFO("Component Type    : %x\r\n", mmio_read_32(WDT_COMP_VERSION));
+	INFO("Component Version : %x\r\n", mmio_read_32(WDT_COMP_TYPE));
+}
+
+/* Check watchdog current status */
+void watchdog_status(void)
+{
+	if (mmio_read_32(WDT_CR) & 1) {
+		INFO("Watchdog Timer in currently enabled\n");
+		INFO("Current Counter : 0x%x\r\n", mmio_read_32(WDT_CCVR));
+	} else {
+		INFO("Watchdog Timer in currently disabled\n");
+	}
+}
+
+/* Initialize & enable watchdog */
+void watchdog_init(int watchdog_clk)
+{
+	uint8_t cycles_i = 0;
+	uint32_t wdt_cycles = WDT_MIN_CYCLES;
+	uint32_t top_init_cycles = WDT_PERIOD * watchdog_clk;
+
+	while ((cycles_i < 15) && (wdt_cycles < top_init_cycles)) {
+		wdt_cycles = (wdt_cycles << 1);
+		cycles_i++;
+	}
+
+	mmio_write_32(WDT_TORR, (cycles_i << 4) | cycles_i);
+
+	watchdog_enable();
+}
+
+void watchdog_enable(void)
+{
+	mmio_write_32(WDT_CR, WDT_CR_RMOD|WDT_CR_EN);
+}
diff --git a/plat/intel/soc/stratix10/drivers/wdt/watchdog.h b/plat/intel/soc/stratix10/drivers/wdt/watchdog.h
new file mode 100644
index 0000000..e920236
--- /dev/null
+++ b/plat/intel/soc/stratix10/drivers/wdt/watchdog.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019, Intel Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CAD_WATCHDOG_H__
+#define __CAD_WATCHDOG_H__
+
+#define WDT_BASE			(0xFFD00200)
+#define WDT_REG_SIZE_OFFSET		(0x4)
+#define WDT_MIN_CYCLES			(65536)
+#define WDT_PERIOD			(20)
+
+#define WDT_CR				(WDT_BASE + 0x0)
+#define WDT_TORR			(WDT_BASE + 0x4)
+
+#define WDT_CRR				(WDT_BASE + 0xC)
+
+#define WDT_CCVR			(WDT_BASE + 0x8)
+#define WDT_STAT			(WDT_BASE + 0x10)
+#define WDT_EOI				(WDT_BASE + 0x14)
+
+#define WDT_COMP_PARAM_1		(WDT_BASE + 0xF4)
+#define WDT_COMP_VERSION		(WDT_BASE + 0xF8)
+#define WDT_COMP_TYPE			(WDT_BASE + 0XFC)
+
+#define WDT_CR_RMOD			(0x0)
+#define WDT_CR_EN			(0x1)
+
+#define WDT_SW_RST			(0x76)
+
+
+void watchdog_init(int watchdog_clk);
+void watchdog_enable(void);
+void watchdog_info(void);
+void watchdog_status(void);
+void watchdog_sw_rst(void);
+
+#endif
diff --git a/plat/intel/soc/stratix10/include/s10_clock_manager.h b/plat/intel/soc/stratix10/include/s10_clock_manager.h
index 28192fa..99eb7a6 100644
--- a/plat/intel/soc/stratix10/include/s10_clock_manager.h
+++ b/plat/intel/soc/stratix10/include/s10_clock_manager.h
@@ -50,6 +50,11 @@
 #define ALT_CLKMGR_MAINPLL_VCOCALIB_HSCNT_SET(x) (((x) << 0) & 0x000000ff)
 #define ALT_CLKMGR_MAINPLL_VCOCALIB_MSCNT_SET(x) (((x) << 9) & 0x0001fe00)
 
+#define ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC(x)	(((x) & 0x00030000) >> 16)
+#define ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_EOSC1	0x0
+#define ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_INTOSC	0x1
+#define ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_F2S	0x2
+
 #define ALT_CLKMGR_PERPLL			0xffd100a4
 #define ALT_CLKMGR_PERPLL_EN			0x0
 #define ALT_CLKMGR_PERPLL_BYPASS		0xc
@@ -78,6 +83,14 @@
 #define ALT_CLKMGR_PERPLL_VCOCALIB_MSCNT_SET(x) (((x) << 9) & 0x0001fe00)
 #define ALT_CLKMGR_PERPLL_VCOCALIB		0x58
 
+
+typedef struct {
+	uint32_t  clk_freq_of_eosc1;
+	uint32_t  clk_freq_of_f2h_free;
+	uint32_t  clk_freq_of_cb_intosc_ls;
+} CLOCK_SOURCE_CONFIG;
+
 void config_clkmgr_handoff(handoff *hoff_ptr);
+int get_wdt_clk(handoff *hoff_ptr);
 
 #endif
diff --git a/plat/intel/soc/stratix10/platform.mk b/plat/intel/soc/stratix10/platform.mk
index 1f06fbd..fdd6e45 100644
--- a/plat/intel/soc/stratix10/platform.mk
+++ b/plat/intel/soc/stratix10/platform.mk
@@ -46,7 +46,8 @@
 		plat/intel/soc/stratix10/soc/s10_system_manager.c	\
 		common/desc_image_load.c				\
 		plat/intel/soc/stratix10/soc/s10_mailbox.c		\
-		plat/intel/soc/stratix10/drivers/qspi/cadence_qspi.c
+		plat/intel/soc/stratix10/drivers/qspi/cadence_qspi.c	\
+		plat/intel/soc/stratix10/drivers/wdt/watchdog.c
 
 BL31_SOURCES	+=	drivers/arm/cci/cci.c				\
 		lib/cpus/aarch64/cortex_a53.S				\
diff --git a/plat/intel/soc/stratix10/soc/s10_clock_manager.c b/plat/intel/soc/stratix10/soc/s10_clock_manager.c
index 9d4617a..dc90076 100644
--- a/plat/intel/soc/stratix10/soc/s10_clock_manager.c
+++ b/plat/intel/soc/stratix10/soc/s10_clock_manager.c
@@ -15,6 +15,14 @@
 #include "s10_clock_manager.h"
 #include "s10_handoff.h"
 
+static const CLOCK_SOURCE_CONFIG  clk_source = {
+	/* clk_freq_of_eosc1 */
+	(uint32_t) 25000000,
+	/* clk_freq_of_f2h_free */
+	(uint32_t) 460000000,
+	/* clk_freq_of_cb_intosc_ls */
+	(uint32_t) 50000000,
+};
 
 void wait_pll_lock(void)
 {
@@ -190,3 +198,37 @@
 			ALT_CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK);
 }
 
+int get_wdt_clk(handoff *hoff_ptr)
+{
+	int main_noc_base_clk, l3_main_free_clk, l4_sys_free_clk;
+	int data32, mdiv, refclkdiv, ref_clk;
+
+	data32 = mmio_read_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLGLOB);
+
+	switch (ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC(data32)) {
+	case ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_EOSC1:
+		ref_clk = clk_source.clk_freq_of_eosc1;
+		break;
+	case ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_INTOSC:
+		ref_clk = clk_source.clk_freq_of_cb_intosc_ls;
+		break;
+	case ALT_CLKMGR_MAINPLL_PLLGLOB_PSRC_F2S:
+		ref_clk = clk_source.clk_freq_of_f2h_free;
+		break;
+	default:
+		ref_clk = 0;
+		assert(0);
+		break;
+	}
+
+	refclkdiv = ALT_CLKMGR_MAINPLL_PLLGLOB_REFCLKDIV(data32);
+	data32 = mmio_read_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_FDBCK);
+	mdiv = ALT_CLKMGR_MAINPLL_FDBCK_MDIV(data32);
+	ref_clk = (ref_clk / refclkdiv) * (6 + mdiv);
+
+	main_noc_base_clk = ref_clk / (hoff_ptr->main_pll_pllc1 & 0xff);
+	l3_main_free_clk = main_noc_base_clk / (hoff_ptr->main_pll_nocclk + 1);
+	l4_sys_free_clk = l3_main_free_clk / 4;
+
+	return l4_sys_free_clk;
+}