msm_shared: Add qtimer support

Change-Id: I6cd15a21eace8b10fa8f4365cf0959b49ae5e02e
diff --git a/platform/msm_shared/qtimer.c b/platform/msm_shared/qtimer.c
new file mode 100755
index 0000000..8af01f4
--- /dev/null
+++ b/platform/msm_shared/qtimer.c
@@ -0,0 +1,198 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <reg.h>
+#include <sys/types.h>
+
+#include <platform/timer.h>
+#include <platform/irqs.h>
+#include <platform/iomap.h>
+#include <platform/interrupts.h>
+#include <kernel/thread.h>
+
+#define QTMR_TIMER_CTRL_ENABLE          (1 << 0)
+#define QTMR_TIMER_CTRL_INT_MASK        (1 << 1)
+
+#define PLATFORM_TIMER_TYPE_PHYSICAL     1
+#define PLATFORM_TIMER_TYPE_VIRTUAL      2
+
+static platform_timer_callback timer_callback;
+static void *timer_arg;
+static time_t timer_interval;
+static unsigned int timer_type = PLATFORM_TIMER_TYPE_PHYSICAL;
+static volatile uint32_t ticks;
+
+static enum handler_return timer_irq(void *arg)
+{
+	ticks += timer_interval;
+
+	if (timer_type == PLATFORM_TIMER_TYPE_VIRTUAL)
+		__asm__("mcr p15, 0, %0, c14, c3, 0"::"r"(timer_interval));
+	else if (timer_type == PLATFORM_TIMER_TYPE_PHYSICAL)
+		__asm__("mcr p15, 0, %0, c14, c2, 0" : :"r" (timer_interval));
+
+	return timer_callback(timer_arg, ticks);
+}
+
+/* Programs the Virtual Down counter timer.
+ * interval : Counter ticks till expiry interrupt is fired.
+ */
+unsigned int platform_set_virtual_timer(uint32_t interval)
+{
+	uint32_t ctrl;
+
+	/* Program CTRL Register */
+	ctrl =0;
+	ctrl |= QTMR_TIMER_CTRL_ENABLE;
+	ctrl &= ~QTMR_TIMER_CTRL_INT_MASK;
+
+	__asm__("mcr p15, 0, %0, c14, c3, 1"::"r"(ctrl));
+
+	/* Set Virtual Down Counter */
+	__asm__("mcr p15, 0, %0, c14, c3, 0"::"r"(interval));
+
+	return INT_QTMR_VIRTUAL_TIMER_EXP;
+
+}
+
+/* Programs the Physical Secure Down counter timer.
+ * interval : Counter ticks till expiry interrupt is fired.
+ */
+unsigned int platform_set_physical_timer(uint32_t interval)
+{
+	uint32_t ctrl;
+
+	/* Program CTRL Register */
+	ctrl =0;
+	ctrl |= QTMR_TIMER_CTRL_ENABLE;
+	ctrl &= ~QTMR_TIMER_CTRL_INT_MASK;
+
+	__asm__("mcr p15, 0, %0, c14, c2, 1" : :"r" (ctrl));
+
+	/* Set Physical Down Counter */
+	__asm__("mcr p15, 0, %0, c14, c2, 0" : :"r" (interval));
+
+	return INT_QTMR_SECURE_PHYSICAL_TIMER_EXP;
+
+}
+
+
+status_t platform_set_periodic_timer(platform_timer_callback callback,
+	void *arg, time_t interval)
+{
+	uint32_t ppi_num;
+	unsigned long ctrl;
+	uint32_t tick_count = interval * platform_tick_rate() / 1000;
+
+	enter_critical_section();
+
+	timer_callback = callback;
+	timer_arg = arg;
+	timer_interval = interval;
+
+	if (timer_type == PLATFORM_TIMER_TYPE_VIRTUAL)
+		ppi_num = platform_set_virtual_timer(tick_count);
+	else if (timer_type == PLATFORM_TIMER_TYPE_PHYSICAL)
+		ppi_num = platform_set_physical_timer(tick_count);
+
+	register_int_handler(ppi_num, timer_irq, 0);
+	unmask_interrupt(ppi_num);
+
+	exit_critical_section();
+	return 0;
+}
+
+time_t current_time(void)
+{
+	return ticks;
+}
+
+void platform_uninit_timer(void)
+{
+	uint32_t ctrl;
+
+	unmask_interrupt(INT_DEBUG_TIMER_EXP);
+
+	/* program cntrl register */
+	ctrl =0;
+	ctrl |= ~QTMR_TIMER_CTRL_ENABLE;
+	ctrl &= QTMR_TIMER_CTRL_INT_MASK;
+
+	if (timer_type == PLATFORM_TIMER_TYPE_VIRTUAL)
+		__asm__("mcr p15, 0, %0, c14, c3, 1"::"r"(ctrl));
+	else if (timer_type == PLATFORM_TIMER_TYPE_PHYSICAL)
+		__asm__("mcr p15, 0, %0, c14, c2, 1" : :"r" (ctrl));
+
+}
+
+void mdelay(unsigned msecs)
+{
+	uint32_t phy_cnt_lo, phy_cnt_hi, cnt, timeout = 0;
+	uint64_t phy_cnt;
+	msecs = msecs *  platform_tick_rate() / 1000;
+
+	do{
+	/* read global counter */
+	__asm__("mrrc p15,0,%0,%1, c14":"=r"(phy_cnt_lo),"=r"(phy_cnt_hi));
+	phy_cnt = ((uint64_t)phy_cnt_hi << 32) | phy_cnt_lo;
+	/*Actual counter used in the simulation is only 32 bits
+	 * in reality the counter is actually 56 bits.
+	 */
+	cnt = phy_cnt & (uint32_t)~0;
+	if (timeout == 0)
+		timeout = cnt + msecs;
+	} while (cnt < timeout);
+
+}
+
+void udelay(unsigned usecs)
+{
+	uint32_t phy_cnt_lo, phy_cnt_hi, cnt, timeout = 0;
+	uint64_t phy_cnt;
+	usecs = (usecs * platform_tick_rate()) / 1000000;
+
+	do{
+	/* read global counter */
+	__asm__("mrrc p15,0,%0,%1, c14":"=r"(phy_cnt_lo),"=r"(phy_cnt_hi));
+	phy_cnt = ((uint64_t)phy_cnt_hi << 32) | phy_cnt_lo;
+
+	/*Actual counter used in the simulation is only 32 bits
+	 * in reality the counter is actually 56 bits.
+	 */
+	cnt = phy_cnt & (uint32_t)~0;
+	if (timeout == 0)
+		timeout = cnt + usecs;
+	} while (cnt < timeout);
+}
+
+/* Return current time in micro seconds */
+bigtime_t current_time_hires(void)
+{
+	return ticks * 1000000ULL;
+}