diff --git a/configure.ac b/configure.ac
index f7da75ec4..5bc84a71b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -109,7 +109,7 @@ AS_CASE([$host],
   [i686*], [ARCH_DIR=x86],
   [mips64*], [ARCH_DIR=mips64],
   [powerpc*], [ARCH_DIR=powerpc],
-  [aarch64*], [ARCH_DIR=arm],
+  [aarch64*], [ARCH_DIR=aarch64],
   [arm*], [ARCH_DIR=arm],
   [ARCH_DIR=undefined]
 )
@@ -219,6 +219,7 @@ AM_CONDITIONAL([user_guide], [test "x${user_guides}" = "xyes" ])
 AM_CONDITIONAL([HAVE_MSCGEN], [test "x${MSCGEN}" = "xmscgen"])
 AM_CONDITIONAL([helper_linux], [test x$helper_linux = xyes ])
 AM_CONDITIONAL([ARCH_IS_ARM], [test "x${ARCH_DIR}" = "xarm"])
+AM_CONDITIONAL([ARCH_IS_AARCH64], [test "x${ARCH_DIR}" = "xaarch64"])
 AM_CONDITIONAL([ARCH_IS_MIPS64], [test "x${ARCH_DIR}" = "xmips64"])
 AM_CONDITIONAL([ARCH_IS_POWERPC], [test "x${ARCH_DIR}" = "xpowerpc"])
 AM_CONDITIONAL([ARCH_IS_X86], [test "x${ARCH_DIR}" = "xx86"])
diff --git a/platform/Makefile.inc b/platform/Makefile.inc
index f67225603..bb5da187b 100644
--- a/platform/Makefile.inc
+++ b/platform/Makefile.inc
@@ -86,6 +86,9 @@ EXTRA_DIST = \
 	     arch/arm/odp/api/cpu_arch.h \
 	     arch/arm/odp_cpu_arch.c \
 	     arch/arm/odp_sysinfo_parse.c \
+	     arch/aarch64/odp/api/cpu_arch.h \
+	     arch/aarch64/odp_cpu_arch.c \
+	     arch/aarch64/odp_sysinfo_parse.c \
 	     arch/default/odp/api/cpu_arch.h \
 	     arch/default/odp_cpu_arch.c \
 	     arch/default/odp_sysinfo_parse.c \
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index f5f65384f..7257a60f5 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -71,6 +71,9 @@ odpapiinclude_HEADERS = \
 if ARCH_IS_ARM
 odpapiinclude_HEADERS += $(srcdir)/arch/arm/odp/api/cpu_arch.h
 endif
+if ARCH_IS_AARCH64
+odpapiinclude_HEADERS += $(srcdir)/arch/aarch64/odp/api/cpu_arch.h
+endif
 if ARCH_IS_MIPS64
 odpapiinclude_HEADERS += $(srcdir)/arch/mips64/odp/api/cpu_arch.h
 endif
@@ -238,6 +241,10 @@ if ARCH_IS_ARM
 __LIB__libodp_linux_la_SOURCES += arch/arm/odp_cpu_arch.c \
 				  arch/arm/odp_sysinfo_parse.c
 endif
+if ARCH_IS_AARCH64
+__LIB__libodp_linux_la_SOURCES += arch/aarch64/odp_cpu_arch.c \
+				  arch/aarch64/odp_sysinfo_parse.c
+endif
 if ARCH_IS_MIPS64
 __LIB__libodp_linux_la_SOURCES += arch/mips64/odp_cpu_arch.c \
 				  arch/mips64/odp_sysinfo_parse.c
diff --git a/platform/linux-generic/arch/aarch64/odp/api/cpu_arch.h b/platform/linux-generic/arch/aarch64/odp/api/cpu_arch.h
new file mode 100644
index 000000000..7c75a690e
--- /dev/null
+++ b/platform/linux-generic/arch/aarch64/odp/api/cpu_arch.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef ODP_PLAT_CPU_ARCH_H_
+#define ODP_PLAT_CPU_ARCH_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define _ODP_CACHE_LINE_SIZE 64
+
+static inline void odp_cpu_pause(void)
+{
+	/* YIELD hints the CPU to switch to another thread if possible
+	 * and executes as a NOP otherwise.
+	 * ISB flushes the pipeline, then restarts. This is guaranteed to
+	 * stall the CPU a number of cycles.
+	 */
+	__asm volatile("isb" ::: "memory");
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/linux-generic/arch/aarch64/odp_cpu_arch.c b/platform/linux-generic/arch/aarch64/odp_cpu_arch.c
new file mode 100644
index 000000000..b87d1c102
--- /dev/null
+++ b/platform/linux-generic/arch/aarch64/odp_cpu_arch.c
@@ -0,0 +1,94 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <odp_posix_extensions.h>
+
+#include <stdlib.h>
+#include <time.h>
+
+#include <odp/api/cpu.h>
+#include <odp/api/hints.h>
+#include <odp/api/system_info.h>
+#include <odp_debug_internal.h>
+#include <odp_time_internal.h>
+
+#define GIGA 1000000000
+
+uint64_t odp_cpu_cycles(void)
+{
+	struct timespec time;
+	uint64_t sec, ns, hz, cycles;
+	int ret;
+
+	ret = clock_gettime(CLOCK_MONOTONIC_RAW, &time);
+
+	if (ret != 0)
+		ODP_ABORT("clock_gettime failed\n");
+
+	hz  = odp_cpu_hz_max();
+	sec = (uint64_t)time.tv_sec;
+	ns  = (uint64_t)time.tv_nsec;
+
+	cycles  = sec * hz;
+	cycles += (ns * hz) / GIGA;
+
+	return cycles;
+}
+
+uint64_t odp_cpu_cycles_max(void)
+{
+	return UINT64_MAX;
+}
+
+uint64_t odp_cpu_cycles_resolution(void)
+{
+	return 1;
+}
+
+int cpu_has_global_time(void)
+{
+	uint64_t hz = cpu_global_time_freq();
+
+	/*
+	 * The system counter portion of the architected timer must
+	 * provide a uniform view of system time to all processing
+	 * elements in the system. This should hold true even for
+	 * heterogeneous SoCs.
+	 *
+	 * Determine whether the system has 'global time' by checking
+	 * whether a read of the architected timer frequency sys reg
+	 * returns a sane value. Sane is considered to be within
+	 * 1MHz and 6GHz (1us and .1667ns period).
+	 */
+	return hz >= 1000000 && hz <= 6000000000;
+}
+
+uint64_t cpu_global_time(void)
+{
+	uint64_t cntvct;
+
+	/*
+	 * To be consistent with other architectures, do not issue a
+	 * serializing instruction, e.g. ISB, before reading this
+	 * sys reg.
+	 */
+
+	/* Memory clobber to minimize optimization around load from sys reg. */
+	__asm__ volatile("mrs %0, cntvct_el0" : "=r"(cntvct) : : "memory");
+
+	return cntvct;
+}
+
+uint64_t cpu_global_time_freq(void)
+{
+	uint64_t cntfrq;
+
+	__asm__ volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq) : : );
+
+	return cntfrq;
+}
diff --git a/platform/linux-generic/arch/aarch64/odp_sysinfo_parse.c b/platform/linux-generic/arch/aarch64/odp_sysinfo_parse.c
new file mode 100644
index 000000000..1e2c729a7
--- /dev/null
+++ b/platform/linux-generic/arch/aarch64/odp_sysinfo_parse.c
@@ -0,0 +1,28 @@
+/* Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <odp_internal.h>
+#include <odp_debug_internal.h>
+#include <string.h>
+
+int cpuinfo_parser(FILE *file ODP_UNUSED, system_info_t *sysinfo)
+{
+	int i;
+
+	ODP_DBG("Warning: use dummy values for freq and model string\n");
+	for (i = 0; i < MAX_CPU_NUMBER; i++) {
+		sysinfo->cpu_hz_max[i] = 1400000000;
+		strcpy(sysinfo->model_str[i], "UNKNOWN");
+	}
+
+	return 0;
+}
+
+void sys_info_print_arch(void)
+{
+}
diff --git a/platform/linux-generic/arch/arm/odp_cpu_arch.c b/platform/linux-generic/arch/arm/odp_cpu_arch.c
index 6622e619f..fc49ce371 100644
--- a/platform/linux-generic/arch/arm/odp_cpu_arch.c
+++ b/platform/linux-generic/arch/arm/odp_cpu_arch.c
@@ -70,33 +70,10 @@ int cpu_has_global_time(void)
 
 uint64_t cpu_global_time(void)
 {
-#ifdef __aarch64__
-	uint64_t cntvct;
-
-	/*
-	 * To be consistent with other architectures, do not issue a
-	 * serializing instruction, e.g. ISB, before reading this
-	 * sys reg.
-	 */
-
-	/* Memory clobber to minimize optimization around load from sys reg. */
-	__asm__ volatile("mrs %0, cntvct_el0" : "=r"(cntvct) : : "memory");
-
-	return cntvct;
-#else
 	return 0;
-#endif
 }
 
 uint64_t cpu_global_time_freq(void)
 {
-#ifdef __aarch64__
-	uint64_t cntfrq;
-
-	__asm__ volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq) : : );
-
-	return cntfrq;
-#else
 	return 0;
-#endif
 }
