test(interrupts): secure watchdog driver for SPs

The secure watchdog timer is used as the source of secure interrupt
in upcoming patches to exercise secure interrupt handling in two
test configurations belonging to the `ffa_secure_partitions` setup:
1. The target SP for the secure virtual interrupt is a S-EL1 partition
2. The target SP for the secure virtual interrupt is a S-EL0 partition

Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: I30a807458fed84b2dfe5f36da571705fefd2f415
diff --git a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/BUILD.gn b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/BUILD.gn
index 48487de..0b94be5 100644
--- a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/BUILD.gn
+++ b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/BUILD.gn
@@ -67,6 +67,17 @@
   ]
 }
 
+source_set("sp805") {
+  testonly = true
+  public_configs = [
+    ":config",
+    "//src/arch/aarch64:arch_config",
+  ]
+  sources = [
+    "sp805.c",
+  ]
+}
+
 source_set("message_loop") {
   testonly = true
   public_configs = [
@@ -93,6 +104,7 @@
 
   deps = [
     ":message_loop",
+    ":sp805",
     "//src/arch/aarch64/hftest:interrupts",
     "//test/hftest:hftest_secure_service",
   ]
diff --git a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/el0/BUILD.gn b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/el0/BUILD.gn
index c857bd0..2db73c7 100644
--- a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/el0/BUILD.gn
+++ b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/el0/BUILD.gn
@@ -20,6 +20,7 @@
     "//src/arch/aarch64/hftest/el0:interrupts",
     "//test/hftest:hftest_sel0_partition_base",
     "//test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure:message_loop",
+    "//test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure:sp805",
   ]
 }
 
diff --git a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/inc/sp805.h b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/inc/sp805.h
new file mode 100644
index 0000000..599e4f6
--- /dev/null
+++ b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/inc/sp805.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+/* SP805 register offset. */
+#define SP805_WDOG_LOAD_OFF 0x000
+#define SP805_WDOG_CTRL_OFF 0x008
+#define SP805_WDOG_INT_CLR_OFF 0x00c
+#define SP805_WDOG_LOCK_OFF 0xc00
+
+/*
+ * Magic word to unlock access to all other watchdog registers, writing any
+ * other value locks them.
+ */
+#define SP805_WDOG_UNLOCK_ACCESS 0x1ACCE551
+
+/* The register field definitions. */
+#define SP805_WDOG_CTRL_MASK 0x03
+#define SP805_WDOG_CTRL_RESEN (1 << 1)
+#define SP805_WDOG_CTRL_INTEN (1 << 0)
+
+#define ARM_SP805_TWDG_CLK_HZ 32768
+#define SP805_TWDOG_BASE 0x2A490000
+
+/* Public APIs for trusted watchdog module. */
+void sp805_twdog_start(unsigned int wdog_cycles);
+void sp805_twdog_stop(void);
+void sp805_twdog_refresh(void);
diff --git a/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/sp805.c b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/sp805.c
new file mode 100644
index 0000000..233ee80
--- /dev/null
+++ b/test/vmapi/ffa_secure_partitions/services/arch/aarch64/secure/sp805.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2023 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+#include "sp805.h"
+
+#include "hf/mmio.h"
+
+#include "test/hftest.h"
+
+static inline void sp805_write_wdog_load(void *base, uint32_t value)
+{
+	mmio_write32_offset(base, SP805_WDOG_LOAD_OFF, value);
+}
+
+static inline void sp805_write_wdog_ctrl(void *base, uint32_t value)
+{
+	/* Not setting reserved bits. */
+	ASSERT_FALSE((value & ~SP805_WDOG_CTRL_MASK));
+	mmio_write32_offset(base, SP805_WDOG_CTRL_OFF, value);
+}
+
+static inline void sp805_write_wdog_int_clr(void *base, uint32_t value)
+{
+	mmio_write32_offset(base, SP805_WDOG_INT_CLR_OFF, value);
+}
+
+static inline void sp805_write_wdog_lock(void *base, uint32_t value)
+{
+	mmio_write32_offset(base, SP805_WDOG_LOCK_OFF, value);
+}
+
+static void sp805_wdog_start_(void *base, uint32_t wdog_cycles)
+{
+	/* Unlock to access the watchdog registers. */
+	sp805_write_wdog_lock(base, SP805_WDOG_UNLOCK_ACCESS);
+
+	/* Write the number of cycles needed. */
+	sp805_write_wdog_load(base, wdog_cycles);
+
+	/* Enable reset interrupt and watchdog interrupt on expiry. */
+	sp805_write_wdog_ctrl(base,
+			      SP805_WDOG_CTRL_RESEN | SP805_WDOG_CTRL_INTEN);
+
+	/* Lock registers so that they can't be accidently overwritten. */
+	sp805_write_wdog_lock(base, 0x0);
+}
+
+static void sp805_wdog_stop_(void *base)
+{
+	/* Unlock to access the watchdog registers. */
+	sp805_write_wdog_lock(base, SP805_WDOG_UNLOCK_ACCESS);
+
+	/* Clearing INTEN bit stops the counter. */
+	sp805_write_wdog_ctrl(base, 0x00);
+
+	/* Lock registers so that they can't be accidently overwritten. */
+	sp805_write_wdog_lock(base, 0x0);
+}
+
+static void sp805_wdog_refresh_(void *base)
+{
+	/* Unlock to access the watchdog registers. */
+	sp805_write_wdog_lock(base, SP805_WDOG_UNLOCK_ACCESS);
+
+	/*
+	 * Write of any value to WdogIntClr clears interrupt and reloads
+	 * the counter from the value in WdogLoad Register.
+	 */
+	sp805_write_wdog_int_clr(base, 1);
+
+	/* Lock registers so that they can't be accidently overwritten. */
+	sp805_write_wdog_lock(base, 0x0);
+}
+
+void sp805_twdog_start(uint32_t wdog_cycles)
+{
+	sp805_wdog_start_((void *)SP805_TWDOG_BASE, wdog_cycles);
+}
+
+void sp805_twdog_stop(void)
+{
+	sp805_wdog_stop_((void *)SP805_TWDOG_BASE);
+}
+
+void sp805_twdog_refresh(void)
+{
+	sp805_wdog_refresh_((void *)SP805_TWDOG_BASE);
+}