feat(hw_crc): add support for HW computed CRC

Added support for HW computed CRC using Arm ACLE intrinsics.
These are built-in intrinsics available for ARMv8.1-A, and
onwards.
These intrinsics are enabled via '-march=armv8-a+crc' compile
switch for ARMv8-A (supports CRC instructions optionally).

HW CRC support is enabled unconditionally in BL2 for all Arm
platforms.

HW CRC calculation is verified offline to ensure a similar
result as its respective ZLib utility function.

HW CRC calculation support will be used in the upcoming
firmware update patches.

Change-Id: Ia2ae801f62d2003e89a9c3e6d77469b5312614b3
Signed-off-by: Manish V Badarkhe <Manish.Badarkhe@arm.com>
diff --git a/common/hw_crc32.c b/common/hw_crc32.c
new file mode 100644
index 0000000..a8731da
--- /dev/null
+++ b/common/hw_crc32.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <assert.h>
+
+#include <arm_acle.h>
+#include <common/debug.h>
+
+/* hw_crc32 - compute CRC using Arm intrinsic function
+ *
+ * This function is useful for the platforms with the CPU ARMv8.0
+ * (with CRC instructions supported), and onwards.
+ * Platforms with CPU ARMv8.0 should make sure to add a compile switch
+ * '-march=armv8-a+crc" for successful compilation of this file.
+ *
+ * @crc: previous accumulated CRC
+ * @buf: buffer base address
+ * @size: the size of the buffer
+ *
+ * Return calculated CRC value
+ */
+uint32_t hw_crc32(uint32_t crc, const unsigned char *buf, size_t size)
+{
+	assert(buf != NULL);
+
+	uint32_t calc_crc = ~crc;
+	const unsigned char *local_buf = buf;
+	size_t local_size = size;
+
+	/*
+	 * calculate CRC over byte data
+	 */
+	while (local_size != 0UL) {
+		calc_crc = __crc32b(calc_crc, *local_buf);
+		local_buf++;
+		local_size--;
+	}
+
+	return ~calc_crc;
+}
diff --git a/include/common/hw_crc32.h b/include/common/hw_crc32.h
new file mode 100644
index 0000000..0d14d57
--- /dev/null
+++ b/include/common/hw_crc32.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HW_CRC32_H
+#define HW_CRC32_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* compute CRC using Arm intrinsic function */
+uint32_t hw_crc32(uint32_t crc, const unsigned char *buf, size_t size);
+
+#endif /* HW_CRC32_H */
diff --git a/include/lib/libc/arm_acle.h b/include/lib/libc/arm_acle.h
index 953933f..eb08552 100644
--- a/include/lib/libc/arm_acle.h
+++ b/include/lib/libc/arm_acle.h
@@ -14,8 +14,10 @@
 #define ARM_ACLE_H
 
 #if !defined(__aarch64__) || defined(__clang__)
+#	define __crc32b __builtin_arm_crc32b
 #	define __crc32w __builtin_arm_crc32w
 #else
+#	define __crc32b __builtin_aarch64_crc32b
 #	define __crc32w __builtin_aarch64_crc32w
 #endif
 
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index fff1294..5faf9f9 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -178,6 +178,13 @@
 			drivers/partition/partition.c
 endif
 
+# Enable CRC instructions via extension for ARMv8-A CPUs.
+# For ARMv8.1-A, and onwards CRC instructions are default enabled.
+# Enable HW computed CRC support unconditionally in BL2 component.
+ifeq (${ARM_ARCH_MINOR},0)
+  BL2_CPPFLAGS += -march=armv8-a+crc
+endif
+
 ifeq (${ARCH}, aarch64)
 PLAT_INCLUDES		+=	-Iinclude/plat/arm/common/aarch64
 endif
@@ -223,6 +230,7 @@
 				drivers/io/io_storage.c				\
 				plat/arm/common/arm_bl2_setup.c			\
 				plat/arm/common/arm_err.c			\
+				common/hw_crc32.c				\
 				${ARM_IO_SOURCES}
 
 # Firmware Configuration Framework sources