timer: Add Xilinx ZynqMP PS ttc timer

Add Xilinx PS ttc timer for Xilinx ZynqMP platform.

Signed-off-by: Wendy Liang <wendy.liang@xilinx.com>
diff --git a/CODEOWNERS b/CODEOWNERS
index e1bf0e5..32fc145 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -165,6 +165,7 @@
 /drivers/timer/altera_avalon_timer_hal.c  @wentongwu
 /drivers/timer/riscv_machine_timer.c      @nategraff-sifive @kgugala @pgielda
 /drivers/timer/litex_timer.c              @mateusz-holenko @kgugala @pgielda
+/drivers/timer/xlnx_psttc_timer.c         @wjliang
 /drivers/usb/                             @jfischer-phytec-iot @finikorg
 /drivers/usb/device/usb_dc_stm32.c        @ydamigos @loicpoulain
 /drivers/i2c/i2c_ll_stm32*                @ldts @ydamigos
diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt
index ef8cb2b..b124c6f 100644
--- a/drivers/timer/CMakeLists.txt
+++ b/drivers/timer/CMakeLists.txt
@@ -15,3 +15,4 @@
 zephyr_sources_if_kconfig(              sam0_rtc_timer.c)
 zephyr_sources_if_kconfig(              litex_timer.c)
 zephyr_sources_if_kconfig(              mchp_xec_rtos_timer.c)
+zephyr_sources_if_kconfig(              xlnx_psttc_timer.c)
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index 90b0a70..7c68071 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -241,6 +241,23 @@
 	  XEC series RTOS timer and provides the standard "system clock
 	  driver" interfaces.
 
+config XLNX_PSTTC_TIMER
+	bool "Xilinx PS ttc timer support"
+	default y
+	depends on SOC_XILINX_ZYNQMP
+	help
+	  This module implements a kernel device driver for the Xilinx ZynqMP
+	  platform provides the standard "system clock driver" interfaces.
+	  If unchecked, no timer will be used.
+
+config XLNX_PSTTC_TIMER_INDEX
+	int "Xilinx PS ttc timer index"
+	range 0 3
+	default 0
+	depends on XLNX_PSTTC_TIMER
+	help
+	  This is the index of TTC timer picked to provide system clock.
+
 config SYSTEM_CLOCK_DISABLE
 	bool "API to disable system clock"
 	help
diff --git a/drivers/timer/xlnx_psttc_timer.c b/drivers/timer/xlnx_psttc_timer.c
new file mode 100644
index 0000000..5ec46ab
--- /dev/null
+++ b/drivers/timer/xlnx_psttc_timer.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2018 Xilinx, Inc.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <drivers/timer/system_timer.h>
+#include <sys_clock.h>
+#include "irq.h"
+#include "legacy_api.h"
+
+#define TIMER_FREQ          CONFIG_SYS_CLOCK_TICKS_PER_SEC
+
+#if (CONFIG_XLNX_PSTTC_TIMER_INDEX == 0)
+#define TIMER_INPUT_CLKHZ   DT_INST_0_CDNS_TTC_CLOCK_FREQUENCY
+#define TIMER_IRQ           DT_INST_0_CDNS_TTC_IRQ_0
+#define TIMER_BASEADDR      DT_INST_0_CDNS_TTC_BASE_ADDRESS
+#else
+#error ("No timer is specified")
+#endif
+
+#define XTTCPS_CLK_CNTRL_OFFSET	   0x00000000U  /**< Clock Control Register */
+#define XTTCPS_CNT_CNTRL_OFFSET	   0x0000000CU  /**< Counter Control Register*/
+#define XTTCPS_COUNT_VALUE_OFFSET  0x00000018U  /**< Current Counter Value */
+#define XTTCPS_INTERVAL_VAL_OFFSET 0x00000024U  /**< Interval Count Value */
+#define XTTCPS_MATCH_0_OFFSET	   0x00000030U  /**< Match 1 value */
+#define XTTCPS_MATCH_1_OFFSET	   0x0000003CU  /**< Match 2 value */
+#define XTTCPS_MATCH_2_OFFSET	   0x00000048U  /**< Match 3 value */
+#define XTTCPS_ISR_OFFSET	   0x00000054U  /**< Interrupt Status Register */
+#define XTTCPS_IER_OFFSET	   0x00000060U  /**< Interrupt Enable Register */
+
+/* Clock Control Register definitions */
+#define XTTCPS_CLK_CNTRL_PS_EN_MASK	0x00000001U  /**< Prescale enable */
+#define XTTCPS_CLK_CNTRL_PS_VAL_MASK	0x0000001EU  /**< Prescale value */
+#define XTTCPS_CLK_CNTRL_PS_VAL_SHIFT	1U  /**< Prescale shift */
+#define XTTCPS_CLK_CNTRL_PS_DISABLE	16U  /**< Prescale disable */
+#define XTTCPS_CLK_CNTRL_SRC_MASK	0x00000020U  /**< Clock source */
+#define XTTCPS_CLK_CNTRL_EXT_EDGE_MASK	0x00000040U  /**< External Clock edge */
+
+/* Counter Control Register definitions */
+#define XTTCPS_CNT_CNTRL_DIS_MASK	0x00000001U /**< Disable the counter */
+#define XTTCPS_CNT_CNTRL_INT_MASK	0x00000002U /**< Interval mode */
+#define XTTCPS_CNT_CNTRL_DECR_MASK	0x00000004U /**< Decrement mode */
+#define XTTCPS_CNT_CNTRL_MATCH_MASK	0x00000008U /**< Match mode */
+#define XTTCPS_CNT_CNTRL_RST_MASK	0x00000010U /**< Reset counter */
+#define XTTCPS_CNT_CNTRL_EN_WAVE_MASK	0x00000020U /**< Enable waveform */
+#define XTTCPS_CNT_CNTRL_POL_WAVE_MASK	0x00000040U /**< Waveform polarity */
+#define XTTCPS_CNT_CNTRL_RESET_VALUE	0x00000021U /**< Reset value */
+
+/* Interrupt register masks */
+#define XTTCPS_IXR_INTERVAL_MASK	0x00000001U  /**< Interval Interrupt */
+#define XTTCPS_IXR_MATCH_0_MASK		0x00000002U  /**< Match 1 Interrupt */
+#define XTTCPS_IXR_MATCH_1_MASK		0x00000004U  /**< Match 2 Interrupt */
+#define XTTCPS_IXR_MATCH_2_MASK		0x00000008U  /**< Match 3 Interrupt */
+#define XTTCPS_IXR_CNT_OVR_MASK		0x00000010U  /**< Counter Overflow */
+#define XTTCPS_IXR_ALL_MASK		0x0000001FU  /**< All valid Interrupts */
+
+#define XTTC_MAX_INTERVAL_COUNT 0xFFFFFFFFU /**< Maximum value of interval counter */
+
+static u32_t accumulated_cycles;
+static s32_t _sys_idle_elapsed_ticks = 1;
+
+static int xttc_calculate_interval(u32_t *interval, u8_t *prescaler)
+{
+	u32_t tmpinterval = 0;
+	u8_t tmpprescaler = 0;
+	unsigned int tmpval;
+
+	tmpval = (u32_t)(TIMER_INPUT_CLKHZ / TIMER_FREQ);
+
+	if (tmpval < (u32_t)65536U) {
+		/* no prescaler is required */
+		tmpinterval = tmpval;
+		tmpprescaler = 0;
+	} else {
+		for (tmpprescaler = 1U; tmpprescaler < 16; tmpprescaler++) {
+			tmpval = (u32_t)(TIMER_INPUT_CLKHZ /
+					 (TIMER_FREQ * (1U << tmpprescaler)));
+			if (tmpval < (u32_t)65536U) {
+				tmpinterval = tmpval;
+				break;
+			}
+		}
+	}
+
+	if (tmpinterval != 0) {
+		*interval = tmpinterval;
+		*prescaler = tmpprescaler;
+		return 0;
+	}
+
+	/* TBD: Is there a way to adjust the sys clock parameters such as
+	 * ticks per sec if it failed to configure the timer as specified
+	 */
+	return -EINVAL;
+}
+
+/**
+ * @brief System timer tick handler
+ *
+ * This routine handles the system clock tick interrupt. A TICK_EVENT event
+ * is pushed onto the kernel stack.
+ *
+ * The symbol for this routine is either _timer_int_handler.
+ *
+ * @return N/A
+ */
+void _timer_int_handler(void *unused)
+{
+	ARG_UNUSED(unused);
+
+	u32_t regval;
+
+	regval = sys_read32(TIMER_BASEADDR + XTTCPS_ISR_OFFSET);
+	accumulated_cycles += sys_clock_hw_cycles_per_tick();
+	z_clock_announce(_sys_idle_elapsed_ticks);
+}
+
+/**
+ * @brief Initialize and enable the system clock
+ *
+ * This routine is used to program the systick to deliver interrupts at the
+ * rate specified via the 'sys_clock_us_per_tick' global variable.
+ *
+ * @return 0
+ */
+int z_clock_driver_init(struct device *device)
+{
+	int ret;
+	u32_t interval;
+	u8_t prescaler;
+	u32_t regval;
+
+	/* Stop timer */
+	sys_write32(XTTCPS_CNT_CNTRL_DIS_MASK,
+		    TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
+
+	/* Calculate prescaler */
+	ret = xttc_calculate_interval(&interval, &prescaler);
+	if (ret < 0) {
+		printk("Failed to calculate prescaler.\n");
+		return ret;
+	}
+
+	/* Reset registers */
+	sys_write32(XTTCPS_CNT_CNTRL_RESET_VALUE,
+		    TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
+	sys_write32(0, TIMER_BASEADDR + XTTCPS_CLK_CNTRL_OFFSET);
+	sys_write32(0, TIMER_BASEADDR + XTTCPS_INTERVAL_VAL_OFFSET);
+	sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_0_OFFSET);
+	sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_1_OFFSET);
+	sys_write32(0, TIMER_BASEADDR + XTTCPS_MATCH_2_OFFSET);
+	sys_write32(0, TIMER_BASEADDR + XTTCPS_IER_OFFSET);
+	sys_write32(XTTCPS_IXR_ALL_MASK, TIMER_BASEADDR + XTTCPS_ISR_OFFSET);
+	/* Reset counter value */
+	regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
+	regval |= XTTCPS_CNT_CNTRL_RST_MASK;
+	sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
+
+	/* Set options */
+	regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
+	regval |= XTTCPS_CNT_CNTRL_INT_MASK;
+	sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
+
+	/* Set interval and prescaller */
+	sys_write32(interval, TIMER_BASEADDR + XTTCPS_INTERVAL_VAL_OFFSET);
+	regval = (u32_t)((prescaler & 0xFU) << 1);
+	sys_write32(regval, TIMER_BASEADDR + XTTCPS_CLK_CNTRL_OFFSET);
+
+	/* Enable timer interrupt */
+	IRQ_CONNECT(TIMER_IRQ, 0, _timer_int_handler, 0, 0);
+	irq_enable(TIMER_IRQ);
+	regval = sys_read32(TIMER_BASEADDR + XTTCPS_IER_OFFSET);
+	regval |= XTTCPS_IXR_INTERVAL_MASK;
+	sys_write32(regval, TIMER_BASEADDR + XTTCPS_IER_OFFSET);
+
+	/* Start timer */
+	regval = sys_read32(TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
+	regval &= (~XTTCPS_CNT_CNTRL_DIS_MASK);
+	sys_write32(regval, TIMER_BASEADDR + XTTCPS_CNT_CNTRL_OFFSET);
+
+	return 0;
+}
+
+
+/**
+ * @brief Read the platform's timer hardware
+ *
+ * This routine returns the current time in terms of timer hardware clock
+ * cycles.
+ *
+ * @return up counter of elapsed clock cycles
+ */
+u32_t z_timer_cycle_get_32(void)
+{
+	return accumulated_cycles;
+}
diff --git a/dts/bindings/timer/xlnx,ttcps.yaml b/dts/bindings/timer/xlnx,ttcps.yaml
new file mode 100644
index 0000000..dc2d352
--- /dev/null
+++ b/dts/bindings/timer/xlnx,ttcps.yaml
@@ -0,0 +1,24 @@
+---
+title: Xilinx ZynqMP PS TTC TIMERS
+
+description: >
+    This binding gives a base representation of the Xilinx ZynqMP PS TTC TIMERS
+
+inherits:
+    !include base.yaml
+
+properties:
+    compatible:
+      constraint: "cdns,ttc"
+
+    label:
+      category: required
+
+    reg:
+      category: required
+
+    clock-frequency:
+      type: int
+      category: optional
+      description: Clock frequency information for Timer operation
+...
diff --git a/tests/kernel/context/src/main.c b/tests/kernel/context/src/main.c
index 14b96db..d4cca0f 100644
--- a/tests/kernel/context/src/main.c
+++ b/tests/kernel/context/src/main.c
@@ -67,6 +67,8 @@
 #define TICK_IRQ DT_LITEX_TIMER0_E0002800_IRQ_0
 #elif defined(CONFIG_RV32M1_LPTMR_TIMER)
 #define TICK_IRQ DT_OPENISA_RV32M1_LPTMR_SYSTEM_LPTMR_IRQ_0
+#elif defined(CONFIG_XLNX_PSTTC_TIMER)
+#define TICK_IRQ DT_INST_0_CDNS_TTC_IRQ_0
 #elif defined(CONFIG_CPU_CORTEX_M)
 /*
  * The Cortex-M use the SYSTICK exception for the system timer, which is