Merge pull request #821 from jeenu-arm/errata-printing

Errata printing infrastructure
diff --git a/Makefile b/Makefile
index c900e58..9e148fb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
@@ -180,6 +180,7 @@
 				-Iinclude/drivers/ti/uart		\
 				-Iinclude/lib				\
 				-Iinclude/lib/${ARCH}			\
+				-Iinclude/lib/cpus			\
 				-Iinclude/lib/cpus/${ARCH}		\
 				-Iinclude/lib/el3_runtime		\
 				-Iinclude/lib/el3_runtime/${ARCH}	\
diff --git a/bl1/bl1.mk b/bl1/bl1.mk
index 9ef5b40..45ad01e 100644
--- a/bl1/bl1.mk
+++ b/bl1/bl1.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
@@ -34,6 +34,7 @@
 				bl1/${ARCH}/bl1_entrypoint.S		\
 				bl1/${ARCH}/bl1_exceptions.S		\
 				lib/cpus/${ARCH}/cpu_helpers.S		\
+				lib/cpus/errata_report.c		\
 				lib/el3_runtime/${ARCH}/context_mgmt.c	\
 				plat/common/plat_bl1_common.c
 
diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c
index fbb75e0..90c06af 100644
--- a/bl1/bl1_main.c
+++ b/bl1/bl1_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -35,6 +35,7 @@
 #include <bl1.h>
 #include <bl_common.h>
 #include <debug.h>
+#include <errata_report.h>
 #include <platform.h>
 #include <platform_def.h>
 #include <smcc_helpers.h>
@@ -110,6 +111,7 @@
 	INFO("BL1: RAM %p - %p\n", (void *)BL1_RAM_BASE,
 					(void *)BL1_RAM_LIMIT);
 
+	print_errata_status();
 
 #if DEBUG
 	u_register_t val;
diff --git a/docs/cpu-specific-build-macros.md b/docs/cpu-specific-build-macros.md
index df2fbd8..a743487 100644
--- a/docs/cpu-specific-build-macros.md
+++ b/docs/cpu-specific-build-macros.md
@@ -34,6 +34,9 @@
 errata workaround is `ERRATA_<Processor name>_<ID>`, where the `Processor name`
 is for example `A57` for the `Cortex_A57` CPU.
 
+Refer to the section _CPU errata status reporting_ in [Firmware Design
+guide][Firmware Design] for information on to write errata workaround functions.
+
 All workarounds are disabled by default. The platform is responsible for
 enabling these workarounds according to its requirement by defining the
 errata workaround build flags in the platform specific makefile. In case
@@ -116,3 +119,4 @@
 [A57 SW Optimization Guide]: http://infocenter.arm.com/help/topic/com.arm.doc.uan0015b/Cortex_A57_Software_Optimization_Guide_external.pdf
 [A53 Errata Notice]:         http://infocenter.arm.com/help/topic/com.arm.doc.epm048406/index.html
 [A57 Errata Notice]:         http://infocenter.arm.com/help/topic/com.arm.doc.epm049219/cortex_a57_mpcore_software_developers_errata_notice.pdf
+[Firmware Design]:           firmware-design.md
diff --git a/docs/firmware-design.md b/docs/firmware-design.md
index 0acb1fa..bd6e2f6 100644
--- a/docs/firmware-design.md
+++ b/docs/firmware-design.md
@@ -1087,7 +1087,7 @@
 e.g. skip the action the second time, or undo/redo it.
 
 8.  CPU specific operations framework
------------------------------
+-------------------------------------
 
 Certain aspects of the ARMv8 architecture are implementation defined,
 that is, certain behaviours are not architecturally defined, but must be defined
@@ -1102,6 +1102,8 @@
 
 3.  Processor specific register dumping as a part of crash reporting.
 
+4.  Errata status reporting.
+
 Each of the above categories fulfils a different requirement.
 
 1.  allows any processor specific initialization before the caches and MMU
@@ -1115,6 +1117,9 @@
     in the event of a crash, for example Cortex-A53 has registers which
     can expose the data cache contents.
 
+4.  allows a processor to define a function that inspects and reports the status
+    of all errata workarounds on that processor.
+
 Please note that only 2. is mandated by the TRM.
 
 The CPU specific operations framework scales to accommodate a large number of
@@ -1185,6 +1190,70 @@
 be reported and a pointer to the ASCII list of register names in a format
 expected by the crash reporting framework.
 
+### CPU errata status reporting
+
+Errata workarounds for CPUs supported in ARM Trusted Firmware are applied during
+both cold and warm boots, shortly after reset. Individual Errata workarounds are
+enabled as build options. Some errata workarounds have potential run-time
+implications; therefore some are enabled by default, others not. Platform ports
+shall override build options to enable or disable errata as appropriate. The CPU
+drivers take care of applying errata workarounds that are enabled and applicable
+to a given CPU. Refer to the section titled _CPU Errata Workarounds_ in [CPUBM]
+for more information.
+
+Functions in CPU drivers that apply errata workaround must follow the
+conventions listed below.
+
+The errata workaround must be authored as two separate functions:
+
+* One that checks for errata. This function must determine whether that errata
+  applies to the current CPU. Typically this involves matching the current
+  CPUs revision and variant against a value that's known to be affected by the
+  errata. If the function determines that the errata applies to this CPU, it
+  must return `ERRATA_APPLIES`; otherwise, it must return
+  `ERRATA_NOT_APPLIES`.  The utility functions `cpu_get_rev_var` and
+  `cpu_rev_var_ls` functions may come in handy for this purpose.
+
+  For an errata identified as `E`, the check function must be named
+  `check_errata_E`.
+
+  This function will be invoked at different times, both from assembly and from
+  C run time. Therefore it must follow AAPCS, and must not use stack.
+
+* Another one that applies the errata workaround. This function would call the
+  check function described above, and applies errata workaround if required.
+
+CPU drivers that apply errata workaround can optionally implement an assembly
+function that report the status of errata workarounds pertaining to that CPU.
+For a driver that registers the CPU, for example, `cpux` via. `declare_cpu_ops`
+macro, the errata reporting function, if it exists, must be named
+`cpux_errata_report`. This function will always be called with MMU enabled; it
+must follow AAPCS and may use stack.
+
+In a debug build of ARM Trusted Firmware, on a CPU that comes out of reset, both
+BL1 and the run time firmware (BL31 in AArch64, and BL32 in AArch32) will invoke
+errata status reporting function, if one exists, for that type of CPU.
+
+To report the status of each errata workaround, the function shall use the
+assembler macro `report_errata`, passing it:
+
+* The build option that enables the errata;
+
+* The name of the CPU: this must be the same identifier that CPU driver
+  registered itself with, using `declare_cpu_ops`;
+
+* And the errata identifier: the identifier must match what's used in the
+  errata's check function described above.
+
+The errata status reporting function will be called once per CPU type/errata
+combination during the software's active life time.
+
+It's expected that whenever an errata workaround is submitted to ARM Trusted
+Firmware, the errata reporting function is appropriately extended to report its
+status as well.
+
+Reporting the status of errata workaround is for informational purpose only; it
+has no functional significance.
 
 9. Memory layout of BL images
 -----------------------------
diff --git a/include/common/aarch32/asm_macros.S b/include/common/aarch32/asm_macros.S
index 23122f3..45023a0 100644
--- a/include/common/aarch32/asm_macros.S
+++ b/include/common/aarch32/asm_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -32,6 +32,7 @@
 
 #include <arch.h>
 #include <asm_macros_common.S>
+#include <spinlock.h>
 
 #define WORD_SIZE	4
 
@@ -124,4 +125,13 @@
 #endif
 	.endm
 
+	/*
+	 * Reserve space for a spin lock in assembly file.
+	 */
+	.macro define_asm_spinlock _name:req
+	.align	SPINLOCK_ASM_ALIGN
+	\_name:
+	.space	SPINLOCK_ASM_SIZE
+	.endm
+
 #endif /* __ASM_MACROS_S__ */
diff --git a/include/common/aarch64/asm_macros.S b/include/common/aarch64/asm_macros.S
index 88e8d9c..b0f3a0d 100644
--- a/include/common/aarch64/asm_macros.S
+++ b/include/common/aarch64/asm_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -32,6 +32,7 @@
 
 #include <arch.h>
 #include <asm_macros_common.S>
+#include <spinlock.h>
 
 
 	.macro	func_prologue
@@ -200,4 +201,13 @@
 #endif
 	.endm
 
+	/*
+	 * Reserve space for a spin lock in assembly file.
+	 */
+	.macro define_asm_spinlock _name:req
+	.align	SPINLOCK_ASM_ALIGN
+	\_name:
+	.space	SPINLOCK_ASM_SIZE
+	.endm
+
 #endif /* __ASM_MACROS_S__ */
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index 989667a..3f71824 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -39,8 +39,10 @@
 #define MIDR_IMPL_SHIFT		0x18
 #define MIDR_VAR_SHIFT		20
 #define MIDR_VAR_BITS		4
+#define MIDR_VAR_MASK		0xf
 #define MIDR_REV_SHIFT		0
 #define MIDR_REV_BITS		4
+#define MIDR_REV_MASK		0xf
 #define MIDR_PN_MASK		0xfff
 #define MIDR_PN_SHIFT		0x4
 
diff --git a/include/lib/cpus/aarch32/cpu_macros.S b/include/lib/cpus/aarch32/cpu_macros.S
index 64df236..bf16e18 100644
--- a/include/lib/cpus/aarch32/cpu_macros.S
+++ b/include/lib/cpus/aarch32/cpu_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -31,6 +31,7 @@
 #define __CPU_MACROS_S__
 
 #include <arch.h>
+#include <errata_report.h>
 
 #define CPU_IMPL_PN_MASK	(MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \
 				(MIDR_PN_MASK << MIDR_PN_SHIFT)
@@ -44,6 +45,16 @@
 /* Word size for 32-bit CPUs */
 #define CPU_WORD_SIZE			4
 
+/*
+ * Whether errata status needs reporting. Errata status is printed in debug
+ * builds for both BL1 and BL32 images.
+ */
+#if (defined(IMAGE_BL1) || defined(IMAGE_BL32)) && DEBUG
+# define REPORT_ERRATA	1
+#else
+# define REPORT_ERRATA	0
+#endif
+
 	/*
 	 * Define the offsets to the fields in cpu_ops structure.
 	 */
@@ -59,6 +70,22 @@
 CPU_PWR_DWN_OPS: /* cpu_ops power down functions */
 	.space  (4 * CPU_MAX_PWR_DWN_OPS)
 #endif
+
+/*
+ * Fields required to print errata status. Only in BL32 that the printing
+ * require mutual exclusion and printed flag.
+ */
+#if REPORT_ERRATA
+CPU_ERRATA_FUNC: /* CPU errata status printing function */
+	.space  4
+#ifdef IMAGE_BL32
+CPU_ERRATA_LOCK:
+	.space	4
+CPU_ERRATA_PRINTED:
+	.space	4
+#endif
+#endif
+
 CPU_OPS_SIZE = .
 
 	/*
@@ -137,6 +164,79 @@
 	  .endif
 	.endif
 #endif
+
+#if REPORT_ERRATA
+	.ifndef \_name\()_cpu_str
+	  /*
+	   * Place errata reported flag, and the spinlock to arbitrate access to
+	   * it in the data section.
+	   */
+	  .pushsection .data
+	  define_asm_spinlock \_name\()_errata_lock
+	  \_name\()_errata_reported:
+	  .word	0
+	  .popsection
+
+	  /* Place CPU string in rodata */
+	  .pushsection .rodata
+	  \_name\()_cpu_str:
+	  .asciz "\_name"
+	  .popsection
+	.endif
+
+	/*
+	 * Weakly-bound, optional errata status printing function for CPUs of
+	 * this class.
+	 */
+	.weak \_name\()_errata_report
+	.word \_name\()_errata_report
+
+#ifdef IMAGE_BL32
+	/* Pointers to errata lock and reported flag */
+	.word \_name\()_errata_lock
+	.word \_name\()_errata_reported
+#endif
+#endif
 	.endm
 
+#if REPORT_ERRATA
+	/*
+	 * Print status of a CPU errata
+	 *
+	 * _chosen:
+	 *	Identifier indicating whether or not a CPU errata has been
+	 *	compiled in.
+	 * _cpu:
+	 *	Name of the CPU
+	 * _id:
+	 *	Errata identifier
+	 * _rev_var:
+	 *	Register containing the combined value CPU revision and variant
+	 *	- typically the return value of cpu_get_rev_var
+	 */
+	.macro report_errata _chosen, _cpu, _id, _rev_var=r4
+	/* Stash a string with errata ID */
+	.pushsection .rodata
+	\_cpu\()_errata_\_id\()_str:
+	.asciz	"\_id"
+	.popsection
+
+	/* Check whether errata applies */
+	mov	r0, \_rev_var
+	bl	check_errata_\_id
+
+	.ifeq \_chosen
+	/*
+	 * Errata workaround has not been compiled in. If the errata would have
+	 * applied had it been compiled in, print its status as missing.
+	 */
+	cmp	r0, #0
+	movne	r0, #ERRATA_MISSING
+	.endif
+	ldr	r1, =\_cpu\()_cpu_str
+	ldr	r2, =\_cpu\()_errata_\_id\()_str
+	bl	errata_print_msg
+	.endm
+#endif
+
 #endif /* __CPU_MACROS_S__ */
diff --git a/include/lib/cpus/aarch64/cpu_macros.S b/include/lib/cpus/aarch64/cpu_macros.S
index 5012877..e3b4afd 100644
--- a/include/lib/cpus/aarch64/cpu_macros.S
+++ b/include/lib/cpus/aarch64/cpu_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -31,6 +31,7 @@
 #define __CPU_MACROS_S__
 
 #include <arch.h>
+#include <errata_report.h>
 
 #define CPU_IMPL_PN_MASK	(MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \
 				(MIDR_PN_MASK << MIDR_PN_SHIFT)
@@ -44,6 +45,16 @@
 /* Word size for 64-bit CPUs */
 #define CPU_WORD_SIZE			8
 
+/*
+ * Whether errata status needs reporting. Errata status is printed in debug
+ * builds for both BL1 and BL31 images.
+ */
+#if (defined(IMAGE_BL1) || defined(IMAGE_BL31)) && DEBUG
+# define REPORT_ERRATA	1
+#else
+# define REPORT_ERRATA	0
+#endif
+
 	/*
 	 * Define the offsets to the fields in cpu_ops structure.
 	 */
@@ -59,6 +70,22 @@
 CPU_PWR_DWN_OPS: /* cpu_ops power down functions */
 	.space  (8 * CPU_MAX_PWR_DWN_OPS)
 #endif
+
+/*
+ * Fields required to print errata status. Only in BL31 that the printing
+ * require mutual exclusion and printed flag.
+ */
+#if REPORT_ERRATA
+CPU_ERRATA_FUNC:
+	.space	8
+#ifdef IMAGE_BL31
+CPU_ERRATA_LOCK:
+	.space	8
+CPU_ERRATA_PRINTED:
+	.space	8
+#endif
+#endif
+
 #if defined(IMAGE_BL31) && CRASH_REPORTING
 CPU_REG_DUMP: /* cpu specific register dump for crash reporting */
 	.space  8
@@ -141,9 +168,84 @@
 	  .endif
 	.endif
 #endif
+
+#if REPORT_ERRATA
+	.ifndef \_name\()_cpu_str
+	  /*
+	   * Place errata reported flag, and the spinlock to arbitrate access to
+	   * it in the data section.
+	   */
+	  .pushsection .data
+	  define_asm_spinlock \_name\()_errata_lock
+	  \_name\()_errata_reported:
+	  .word	0
+	  .popsection
+
+	  /* Place CPU string in rodata */
+	  .pushsection .rodata
+	  \_name\()_cpu_str:
+	  .asciz "\_name"
+	  .popsection
+	.endif
+
+	/*
+	 * Weakly-bound, optional errata status printing function for CPUs of
+	 * this class.
+	 */
+	.weak \_name\()_errata_report
+	.quad \_name\()_errata_report
+
+#ifdef IMAGE_BL31
+	/* Pointers to errata lock and reported flag */
+	.quad \_name\()_errata_lock
+	.quad \_name\()_errata_reported
+#endif
+#endif
+
 #if defined(IMAGE_BL31) && CRASH_REPORTING
 	.quad \_name\()_cpu_reg_dump
 #endif
 	.endm
 
+#if REPORT_ERRATA
+	/*
+	 * Print status of a CPU errata
+	 *
+	 * _chosen:
+	 *	Identifier indicating whether or not a CPU errata has been
+	 *	compiled in.
+	 * _cpu:
+	 *	Name of the CPU
+	 * _id:
+	 *	Errata identifier
+	 * _rev_var:
+	 *	Register containing the combined value CPU revision and variant
+	 *	- typically the return value of cpu_get_rev_var
+	 */
+	.macro report_errata _chosen, _cpu, _id, _rev_var=x8
+	/* Stash a string with errata ID */
+	.pushsection .rodata
+	\_cpu\()_errata_\_id\()_str:
+	.asciz	"\_id"
+	.popsection
+
+	/* Check whether errata applies */
+	mov	x0, \_rev_var
+	bl	check_errata_\_id
+
+	.ifeq \_chosen
+	/*
+	 * Errata workaround has not been compiled in. If the errata would have
+	 * applied had it been compiled in, print its status as missing.
+	 */
+	cbz	x0, 900f
+	mov	x0, #ERRATA_MISSING
+	.endif
+900:
+	adr	x1, \_cpu\()_cpu_str
+	adr	x2, \_cpu\()_errata_\_id\()_str
+	bl	errata_print_msg
+	.endm
+#endif
+
 #endif /* __CPU_MACROS_S__ */
diff --git a/include/lib/cpus/errata_report.h b/include/lib/cpus/errata_report.h
new file mode 100644
index 0000000..6c6a844
--- /dev/null
+++ b/include/lib/cpus/errata_report.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. 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 ARM 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ */
+
+#ifndef __ERRATA_H__
+#define __ERRATA_H__
+
+#ifndef __ASSEMBLY__
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <spinlock.h>
+#include <utils.h>
+
+#if DEBUG
+void print_errata_status(void);
+#else
+static inline void print_errata_status(void) {}
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+/* Errata status */
+#define ERRATA_NOT_APPLIES	0
+#define ERRATA_APPLIES		1
+#define ERRATA_MISSING		2
+
+#endif /* __ERRATA_H__ */
+
diff --git a/include/lib/spinlock.h b/include/lib/spinlock.h
index cb0bc3e..8273c78 100644
--- a/include/lib/spinlock.h
+++ b/include/lib/spinlock.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -31,11 +31,23 @@
 #ifndef __SPINLOCK_H__
 #define __SPINLOCK_H__
 
+#ifndef __ASSEMBLY__
+
+#include <types.h>
+
 typedef struct spinlock {
-	volatile unsigned int lock;
+	volatile uint32_t lock;
 } spinlock_t;
 
 void spin_lock(spinlock_t *lock);
 void spin_unlock(spinlock_t *lock);
 
+#else
+
+/* Spin lock definitions for use in assembly */
+#define SPINLOCK_ASM_ALIGN	2
+#define SPINLOCK_ASM_SIZE	4
+
+#endif
+
 #endif /* __SPINLOCK_H__ */
diff --git a/lib/cpus/aarch32/cpu_helpers.S b/lib/cpus/aarch32/cpu_helpers.S
index d8cabfe..c41978e 100644
--- a/lib/cpus/aarch32/cpu_helpers.S
+++ b/lib/cpus/aarch32/cpu_helpers.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -172,3 +172,86 @@
 error_exit:
 	bx	lr
 endfunc get_cpu_ops_ptr
+
+/*
+ * Extract CPU revision and variant, and combine them into a single numeric for
+ * easier comparison.
+ */
+	.globl	cpu_get_rev_var
+func cpu_get_rev_var
+	ldcopr	r1, MIDR
+
+	/*
+	 * Extract the variant[23:20] and revision[3:0] from r1 and pack it in
+	 * r0[0:7] as variant[7:4] and revision[3:0]:
+	 *
+	 * First extract r1[23:16] to r0[7:0] and zero fill the rest. Then
+	 * extract r1[3:0] into r0[3:0] retaining other bits.
+	 */
+	ubfx	r0, r1, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS)
+	bfi	r0, r1, #MIDR_REV_SHIFT, #MIDR_REV_BITS
+	bx	lr
+endfunc cpu_get_rev_var
+
+/*
+ * Compare the CPU's revision-variant (r0) with a given value (r1), for errata
+ * application purposes. If the revision-variant is less than or same as a given
+ * value, indicates that errata applies; otherwise not.
+ */
+	.globl	cpu_rev_var_ls
+func cpu_rev_var_ls
+	cmp	r0, r1
+	movls	r0, #ERRATA_APPLIES
+	movhi	r0, #ERRATA_NOT_APPLIES
+	bx	lr
+endfunc cpu_rev_var_ls
+
+#if REPORT_ERRATA
+/*
+ * void print_errata_status(void);
+ *
+ * Function to print errata status for CPUs of its class. Must be called only:
+ *
+ *   - with MMU and data caches are enabled;
+ *   - after cpu_ops have been initialized in per-CPU data.
+ */
+	.globl print_errata_status
+func print_errata_status
+	push	{r4, lr}
+#ifdef IMAGE_BL1
+	/*
+	 * BL1 doesn't have per-CPU data. So retrieve the CPU operations
+	 * directly.
+	 */
+	bl	get_cpu_ops_ptr
+	ldr	r0, [r0, #CPU_ERRATA_FUNC]
+	cmp	r0, #0
+	blxne	r0
+#else
+	/*
+	 * Retrieve pointer to cpu_ops, and further, the errata printing
+	 * function. If it's non-NULL, jump to the function in turn.
+	 */
+	bl	_cpu_data
+	ldr	r1, [r0, #CPU_DATA_CPU_OPS_PTR]
+	ldr	r0, [r1, #CPU_ERRATA_FUNC]
+	cmp	r0, #0
+	beq	1f
+
+	mov	r4, r0
+
+	/*
+	 * Load pointers to errata lock and printed flag. Call
+	 * errata_needs_reporting to check whether this CPU needs to report
+	 * errata status pertaining to its class.
+	 */
+	ldr	r0, [r1, #CPU_ERRATA_LOCK]
+	ldr	r1, [r1, #CPU_ERRATA_PRINTED]
+	bl	errata_needs_reporting
+	cmp	r0, #0
+	blxne	r4
+1:
+#endif
+	pop	{r4, pc}
+endfunc print_errata_status
+#endif
diff --git a/lib/cpus/aarch64/cortex_a53.S b/lib/cpus/aarch64/cortex_a53.S
index 06be9ce..1dd8a86 100644
--- a/lib/cpus/aarch64/cortex_a53.S
+++ b/lib/cpus/aarch64/cortex_a53.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -35,6 +35,11 @@
 #include <debug.h>
 #include <plat_macros.S>
 
+#if A53_DISABLE_NON_TEMPORAL_HINT
+#undef ERRATA_A53_836870
+#define ERRATA_A53_836870	1
+#endif
+
 	/* ---------------------------------------------
 	 * Disable L1 data cache and unified L2 cache
 	 * ---------------------------------------------
@@ -65,28 +70,29 @@
 	 * This applies only to revision <= r0p2 of Cortex A53.
 	 * Inputs:
 	 * x0: variant[4:7] and revision[0:3] of current cpu.
-	 * Clobbers : x0 - x5
+	 * Shall clobber: x0-x17
 	 * --------------------------------------------------
 	 */
 func errata_a53_826319_wa
 	/*
 	 * Compare x0 against revision r0p2
 	 */
-	cmp	x0, #2
-	b.ls	apply_826319
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-	b	print_revision_warning
-#else
-	ret
-#endif
-apply_826319:
+	mov	x17, x30
+	bl	check_errata_826319
+	cbz	x0, 1f
 	mrs	x1, L2ACTLR_EL1
 	bic	x1, x1, #L2ACTLR_ENABLE_UNIQUECLEAN
 	orr	x1, x1, #L2ACTLR_DISABLE_CLEAN_PUSH
 	msr	L2ACTLR_EL1, x1
-	ret
+1:
+	ret	x17
 endfunc errata_a53_826319_wa
 
+func check_errata_826319
+	mov	x1, #0x02
+	b	cpu_rev_var_ls
+endfunc check_errata_826319
+
 	/* ---------------------------------------------------------------------
 	 * Disable the cache non-temporal hint.
 	 *
@@ -101,53 +107,46 @@
 	 *
 	 * Inputs:
 	 * x0: variant[4:7] and revision[0:3] of current cpu.
-	 * Clobbers : x0 - x5
+	 * Shall clobber: x0-x17
 	 * ---------------------------------------------------------------------
 	 */
 func a53_disable_non_temporal_hint
 	/*
 	 * Compare x0 against revision r0p3
 	 */
-	cmp	x0, #3
-	b.ls	disable_hint
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-	b	print_revision_warning
-#else
-	ret
-#endif
-disable_hint:
+	mov	x17, x30
+	bl	check_errata_disable_non_temporal_hint
+	cbz	x0, 1f
 	mrs	x1, CPUACTLR_EL1
 	orr	x1, x1, #CPUACTLR_DTAH
 	msr	CPUACTLR_EL1, x1
-	ret
+1:
+	ret	x17
 endfunc a53_disable_non_temporal_hint
 
+func check_errata_disable_non_temporal_hint
+	mov	x1, #0x03
+	b	cpu_rev_var_ls
+endfunc check_errata_disable_non_temporal_hint
+
 	/* -------------------------------------------------
 	 * The CPU Ops reset function for Cortex-A53.
-	 * Clobbers: x0-x5, x15, x19, x30
+	 * Shall clobber: x0-x19
 	 * -------------------------------------------------
 	 */
 func cortex_a53_reset_func
 	mov	x19, x30
-	mrs	x0, midr_el1
+	bl	cpu_get_rev_var
+	mov	x18, x0
 
-	/*
-	 * Extract the variant[20:23] and revision[0:3] from x0
-	 * and pack it in x15[0:7] as variant[4:7] and revision[0:3].
-	 * First extract x0[16:23] to x15[0:7] and zero fill the rest.
-	 * Then extract x0[0:3] into x15[0:3] retaining other bits.
-	 */
-	ubfx	x15, x0, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), \
-			#(MIDR_REV_BITS + MIDR_VAR_BITS)
-	bfxil	x15, x0, #MIDR_REV_SHIFT, #MIDR_REV_BITS
 
 #if ERRATA_A53_826319
-	mov	x0, x15
+	mov	x0, x18
 	bl	errata_a53_826319_wa
 #endif
 
-#if ERRATA_A53_836870 || A53_DISABLE_NON_TEMPORAL_HINT
-	mov	x0, x15
+#if ERRATA_A53_836870
+	mov	x0, x18
 	bl	a53_disable_non_temporal_hint
 #endif
 
@@ -223,6 +222,28 @@
 	b	cortex_a53_disable_smp
 endfunc cortex_a53_cluster_pwr_dwn
 
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A53. Must follow AAPCS.
+ */
+func cortex_a53_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A53_826319, cortex_a53, 826319
+	report_errata ERRATA_A53_836870, cortex_a53, disable_non_temporal_hint
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a53_errata_report
+#endif
+
 	/* ---------------------------------------------
 	 * This function provides cortex_a53 specific
 	 * register information for crash reporting.
diff --git a/lib/cpus/aarch64/cortex_a57.S b/lib/cpus/aarch64/cortex_a57.S
index e531b1e..ffdc930 100644
--- a/lib/cpus/aarch64/cortex_a57.S
+++ b/lib/cpus/aarch64/cortex_a57.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -92,52 +92,55 @@
 	 * This applies only to revision r0p0 of Cortex A57.
 	 * Inputs:
 	 * x0: variant[4:7] and revision[0:3] of current cpu.
-	 * Clobbers : x0 - x5
+	 * Shall clobber: x0-x17
 	 * --------------------------------------------------
 	 */
 func errata_a57_806969_wa
 	/*
 	 * Compare x0 against revision r0p0
 	 */
-	cbz	x0, apply_806969
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-	b	print_revision_warning
-#else
-	ret
-#endif
-apply_806969:
+	mov	x17, x30
+	bl	check_errata_806969
+	cbz	x0, 1f
 	mrs	x1, CPUACTLR_EL1
 	orr	x1, x1, #CPUACTLR_NO_ALLOC_WBWA
 	msr	CPUACTLR_EL1, x1
-	ret
+1:
+	ret	x17
 endfunc errata_a57_806969_wa
 
+func check_errata_806969
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_806969
 
 	/* ---------------------------------------------------
 	 * Errata Workaround for Cortex A57 Errata #813420.
 	 * This applies only to revision r0p0 of Cortex A57.
 	 * Inputs:
 	 * x0: variant[4:7] and revision[0:3] of current cpu.
-	 * Clobbers : x0 - x5
+	 * Shall clobber: x0-x17
 	 * ---------------------------------------------------
 	 */
 func errata_a57_813420_wa
 	/*
 	 * Compare x0 against revision r0p0
 	 */
-	cbz	x0, apply_813420
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-	b	print_revision_warning
-#else
-	ret
-#endif
-apply_813420:
+	mov	x17, x30
+	bl	check_errata_813420
+	cbz	x0, 1f
 	mrs	x1, CPUACTLR_EL1
 	orr	x1, x1, #CPUACTLR_DCC_AS_DCCI
 	msr	CPUACTLR_EL1, x1
-	ret
+1:
+	ret	x17
 endfunc errata_a57_813420_wa
 
+func check_errata_813420
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_813420
+
 	/* --------------------------------------------------------------------
 	 * Disable the over-read from the LDNP instruction.
 	 *
@@ -146,99 +149,97 @@
 	 *
 	 * Inputs:
 	 * x0: variant[4:7] and revision[0:3] of current cpu.
-	 * Clobbers : x0 - x5, x30
+	 * Shall clobber: x0-x17
 	 * ---------------------------------------------------------------------
 	 */
 func a57_disable_ldnp_overread
 	/*
 	 * Compare x0 against revision r1p2
 	 */
-	cmp	x0, #0x12
-	b.ls	disable_hint
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-	b	print_revision_warning
-#else
-	ret
-#endif
-disable_hint:
+	mov	x17, x30
+	bl	check_errata_disable_ldnp_overread
+	cbz	x0, 1f
 	mrs	x1, CPUACTLR_EL1
 	orr	x1, x1, #CPUACTLR_DIS_OVERREAD
 	msr	CPUACTLR_EL1, x1
-	ret
+1:
+	ret	x17
 endfunc a57_disable_ldnp_overread
 
+func check_errata_disable_ldnp_overread
+	mov	x1, #0x12
+	b	cpu_rev_var_ls
+endfunc check_errata_disable_ldnp_overread
+
 	/* ---------------------------------------------------
 	 * Errata Workaround for Cortex A57 Errata #826974.
 	 * This applies only to revision <= r1p1 of Cortex A57.
 	 * Inputs:
 	 * x0: variant[4:7] and revision[0:3] of current cpu.
-	 * Clobbers : x0 - x5
+	 * Shall clobber: x0-x17
 	 * ---------------------------------------------------
 	 */
 func errata_a57_826974_wa
 	/*
 	 * Compare x0 against revision r1p1
 	 */
-	cmp	x0, #0x11
-	b.ls	apply_826974
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-	b	print_revision_warning
-#else
-	ret
-#endif
-apply_826974:
+	mov	x17, x30
+	bl	check_errata_826974
+	cbz	x0, 1f
 	mrs	x1, CPUACTLR_EL1
 	orr	x1, x1, #CPUACTLR_DIS_LOAD_PASS_DMB
 	msr	CPUACTLR_EL1, x1
-	ret
+1:
+	ret	x17
 endfunc errata_a57_826974_wa
 
+func check_errata_826974
+	mov	x1, #0x11
+	b	cpu_rev_var_ls
+endfunc check_errata_826974
+
 	/* ---------------------------------------------------
 	 * Errata Workaround for Cortex A57 Errata #826977.
 	 * This applies only to revision <= r1p1 of Cortex A57.
 	 * Inputs:
 	 * x0: variant[4:7] and revision[0:3] of current cpu.
-	 * Clobbers : x0 - x5
+	 * Shall clobber: x0-x17
 	 * ---------------------------------------------------
 	 */
 func errata_a57_826977_wa
 	/*
 	 * Compare x0 against revision r1p1
 	 */
-	cmp	x0, #0x11
-	b.ls	apply_826977
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-	b	print_revision_warning
-#else
-	ret
-#endif
-apply_826977:
+	mov	x17, x30
+	bl	check_errata_826977
+	cbz	x0, 1f
 	mrs	x1, CPUACTLR_EL1
 	orr	x1, x1, #CPUACTLR_GRE_NGRE_AS_NGNRE
 	msr	CPUACTLR_EL1, x1
-	ret
+1:
+	ret	x17
 endfunc errata_a57_826977_wa
 
+func check_errata_826977
+	mov	x1, #0x11
+	b	cpu_rev_var_ls
+endfunc check_errata_826977
+
 	/* ---------------------------------------------------
 	 * Errata Workaround for Cortex A57 Errata #828024.
 	 * This applies only to revision <= r1p1 of Cortex A57.
 	 * Inputs:
 	 * x0: variant[4:7] and revision[0:3] of current cpu.
-	 * Clobbers : x0 - x5
+	 * Shall clobber: x0-x17
 	 * ---------------------------------------------------
 	 */
 func errata_a57_828024_wa
 	/*
 	 * Compare x0 against revision r1p1
 	 */
-	cmp	x0, #0x11
-	b.ls	apply_828024
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-	b	print_revision_warning
-#else
-	ret
-#endif
-apply_828024:
+	mov	x17, x30
+	bl	check_errata_828024
+	cbz	x0, 1f
 	mrs	x1, CPUACTLR_EL1
 	/*
 	 * Setting the relevant bits in CPUACTLR_EL1 has to be done in 2
@@ -248,116 +249,116 @@
 	orr	x1, x1, #CPUACTLR_NO_ALLOC_WBWA
 	orr	x1, x1, #(CPUACTLR_DIS_L1_STREAMING | CPUACTLR_DIS_STREAMING)
 	msr	CPUACTLR_EL1, x1
-	ret
+1:
+	ret	x17
 endfunc errata_a57_828024_wa
 
+func check_errata_828024
+	mov	x1, #0x11
+	b	cpu_rev_var_ls
+endfunc check_errata_828024
+
 	/* ---------------------------------------------------
 	 * Errata Workaround for Cortex A57 Errata #829520.
 	 * This applies only to revision <= r1p2 of Cortex A57.
 	 * Inputs:
 	 * x0: variant[4:7] and revision[0:3] of current cpu.
-	 * Clobbers : x0 - x5
+	 * Shall clobber: x0-x17
 	 * ---------------------------------------------------
 	 */
 func errata_a57_829520_wa
 	/*
 	 * Compare x0 against revision r1p2
 	 */
-	cmp	x0, #0x12
-	b.ls	apply_829520
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-	b	print_revision_warning
-#else
-	ret
-#endif
-apply_829520:
+	mov	x17, x30
+	bl	check_errata_829520
+	cbz	x0, 1f
 	mrs	x1, CPUACTLR_EL1
 	orr	x1, x1, #CPUACTLR_DIS_INDIRECT_PREDICTOR
 	msr	CPUACTLR_EL1, x1
-	ret
+1:
+	ret	x17
 endfunc errata_a57_829520_wa
 
+func check_errata_829520
+	mov	x1, #0x12
+	b	cpu_rev_var_ls
+endfunc check_errata_829520
+
 	/* ---------------------------------------------------
 	 * Errata Workaround for Cortex A57 Errata #833471.
 	 * This applies only to revision <= r1p2 of Cortex A57.
 	 * Inputs:
 	 * x0: variant[4:7] and revision[0:3] of current cpu.
-	 * Clobbers : x0 - x5
+	 * Shall clobber: x0-x17
 	 * ---------------------------------------------------
 	 */
 func errata_a57_833471_wa
 	/*
 	 * Compare x0 against revision r1p2
 	 */
-	cmp	x0, #0x12
-	b.ls	apply_833471
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-	b	print_revision_warning
-#else
-	ret
-#endif
-apply_833471:
+	mov	x17, x30
+	bl	check_errata_833471
+	cbz	x0, 1f
 	mrs	x1, CPUACTLR_EL1
 	orr	x1, x1, #CPUACTLR_FORCE_FPSCR_FLUSH
 	msr	CPUACTLR_EL1, x1
-	ret
+1:
+	ret	x17
 endfunc errata_a57_833471_wa
 
+func check_errata_833471
+	mov	x1, #0x12
+	b	cpu_rev_var_ls
+endfunc check_errata_833471
+
 	/* -------------------------------------------------
 	 * The CPU Ops reset function for Cortex-A57.
-	 * Clobbers: x0-x5, x15, x19, x30
+	 * Shall clobber: x0-x19
 	 * -------------------------------------------------
 	 */
 func cortex_a57_reset_func
 	mov	x19, x30
-	mrs	x0, midr_el1
-
-	/*
-	 * Extract the variant[20:23] and revision[0:3] from x0
-	 * and pack it in x15[0:7] as variant[4:7] and revision[0:3].
-	 * First extract x0[16:23] to x15[0:7] and zero fill the rest.
-	 * Then extract x0[0:3] into x15[0:3] retaining other bits.
-	 */
-	ubfx	x15, x0, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS)
-	bfxil	x15, x0, #MIDR_REV_SHIFT, #MIDR_REV_BITS
+	bl	cpu_get_rev_var
+	mov	x18, x0
 
 #if ERRATA_A57_806969
-	mov	x0, x15
+	mov	x0, x18
 	bl	errata_a57_806969_wa
 #endif
 
 #if ERRATA_A57_813420
-	mov	x0, x15
+	mov	x0, x18
 	bl	errata_a57_813420_wa
 #endif
 
 #if A57_DISABLE_NON_TEMPORAL_HINT
-	mov	x0, x15
+	mov	x0, x18
 	bl	a57_disable_ldnp_overread
 #endif
 
 #if ERRATA_A57_826974
-	mov	x0, x15
+	mov	x0, x18
 	bl	errata_a57_826974_wa
 #endif
 
 #if ERRATA_A57_826977
-	mov	x0, x15
+	mov	x0, x18
 	bl	errata_a57_826977_wa
 #endif
 
 #if ERRATA_A57_828024
-	mov	x0, x15
+	mov	x0, x18
 	bl	errata_a57_828024_wa
 #endif
 
 #if ERRATA_A57_829520
-	mov	x0, x15
+	mov	x0, x18
 	bl	errata_a57_829520_wa
 #endif
 
 #if ERRATA_A57_833471
-	mov	x0, x15
+	mov	x0, x18
 	bl	errata_a57_833471_wa
 #endif
 
@@ -466,6 +467,35 @@
 	b	cortex_a57_disable_ext_debug
 endfunc cortex_a57_cluster_pwr_dwn
 
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A57. Must follow AAPCS.
+ */
+func cortex_a57_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_A57_806969, cortex_a57, 806969
+	report_errata ERRATA_A57_813420, cortex_a57, 813420
+	report_errata A57_DISABLE_NON_TEMPORAL_HINT, cortex_a57, \
+		disable_ldnp_overread
+	report_errata ERRATA_A57_826974, cortex_a57, 826974
+	report_errata ERRATA_A57_826977, cortex_a57, 826977
+	report_errata ERRATA_A57_828024, cortex_a57, 828024
+	report_errata ERRATA_A57_829520, cortex_a57, 829520
+	report_errata ERRATA_A57_833471, cortex_a57, 833471
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a57_errata_report
+#endif
+
 	/* ---------------------------------------------
 	 * This function provides cortex_a57 specific
 	 * register information for crash reporting.
diff --git a/lib/cpus/aarch64/cpu_helpers.S b/lib/cpus/aarch64/cpu_helpers.S
index 7365d35..6a3669d 100644
--- a/lib/cpus/aarch64/cpu_helpers.S
+++ b/lib/cpus/aarch64/cpu_helpers.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -36,6 +36,7 @@
 #endif
 #include <cpu_macros.S>
 #include <debug.h>
+#include <errata_report.h>
 
  /* Reset fn is needed in BL at reset vector */
 #if defined(IMAGE_BL1) || defined(IMAGE_BL31)
@@ -199,30 +200,94 @@
 	ret
 endfunc get_cpu_ops_ptr
 
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-.section .rodata.rev_verbose_str, "aS"
-rev_verbose_str:
-	.asciz "VERBOSE: Skipping CPU specific reset operation for non-matching CPU revision number.\n"
+/*
+ * Extract CPU revision and variant, and combine them into a single numeric for
+ * easier comparison.
+ */
+	.globl	cpu_get_rev_var
+func cpu_get_rev_var
+	mrs	x1, midr_el1
 
 	/*
-	 * This function prints the above warning message to the crash console.
-	 * It should be called when a CPU specific operation is enabled in the
-	 * build but doesn't apply to this CPU revision/part number.
+	 * Extract the variant[23:20] and revision[3:0] from MIDR, and pack them
+	 * as variant[7:4] and revision[3:0] of x0.
 	 *
-	 * Clobber: x30, x0 - x5
+	 * First extract x1[23:16] to x0[7:0] and zero fill the rest. Then
+	 * extract x1[3:0] into x0[3:0] retaining other bits.
 	 */
-	.globl	print_revision_warning
-func print_revision_warning
-	mov	x5, x30
-	/* Ensure the console is initialized */
-	bl	plat_crash_console_init
-	/* Check if the console is initialized */
-	cbz	x0, 1f
-	/* The console is initialized */
-	adr	x4, rev_verbose_str
-	bl	asm_print_str
-1:
-	ret	x5
-endfunc print_revision_warning
-#endif
+	ubfx	x0, x1, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS)
+	bfxil	x0, x1, #MIDR_REV_SHIFT, #MIDR_REV_BITS
+	ret
+endfunc cpu_get_rev_var
+
+/*
+ * Compare the CPU's revision-variant (x0) with a given value (x1), for errata
+ * application purposes. If the revision-variant is less than or same as a given
+ * value, indicates that errata applies; otherwise not.
+ */
+	.globl	cpu_rev_var_ls
+func cpu_rev_var_ls
+	mov	x2, #ERRATA_APPLIES
+	mov	x3, #ERRATA_NOT_APPLIES
+	cmp	x0, x1
+	csel	x0, x2, x3, ls
+	ret
+endfunc cpu_rev_var_ls
+
+#if REPORT_ERRATA
+/*
+ * void print_errata_status(void);
+ *
+ * Function to print errata status for CPUs of its class. Must be called only:
+ *
+ *   - with MMU and data caches are enabled;
+ *   - after cpu_ops have been initialized in per-CPU data.
+ */
+	.globl print_errata_status
+func print_errata_status
+#ifdef IMAGE_BL1
+	/*
+	 * BL1 doesn't have per-CPU data. So retrieve the CPU operations
+	 * directly.
+	 */
+	stp	xzr, x30, [sp, #-16]!
+	bl	get_cpu_ops_ptr
+	ldp	xzr, x30, [sp], #16
+	ldr	x1, [x0, #CPU_ERRATA_FUNC]
+	cbnz	x1, .Lprint
+#else
+	/*
+	 * Retrieve pointer to cpu_ops from per-CPU data, and further, the
+	 * errata printing function. If it's non-NULL, jump to the function in
+	 * turn.
+	 */
+	mrs	x0, tpidr_el3
+	ldr	x1, [x0, #CPU_DATA_CPU_OPS_PTR]
+	ldr	x0, [x1, #CPU_ERRATA_FUNC]
+	cbz	x0, .Lnoprint
+
+	/*
+	 * Printing errata status requires atomically testing the printed flag.
+	 */
+	stp	x8, x30, [sp, #-16]!
+	mov	x8, x0
 
+	/*
+	 * Load pointers to errata lock and printed flag. Call
+	 * errata_needs_reporting to check whether this CPU needs to report
+	 * errata status pertaining to its class.
+	 */
+	ldr	x0, [x1, #CPU_ERRATA_LOCK]
+	ldr	x1, [x1, #CPU_ERRATA_PRINTED]
+	bl	errata_needs_reporting
+	mov	x1, x8
+	ldp	x8, x30, [sp], #16
+	cbnz	x0, .Lprint
+#endif
+.Lnoprint:
+	ret
+.Lprint:
+	/* Jump to errata reporting function for this CPU */
+	br	x1
+endfunc print_errata_status
+#endif
diff --git a/lib/cpus/errata_report.c b/lib/cpus/errata_report.c
new file mode 100644
index 0000000..29b26c2
--- /dev/null
+++ b/lib/cpus/errata_report.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. 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 ARM 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ */
+
+/* Runtime firmware routines to report errata status for the current CPU. */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <cpu_data.h>
+#include <debug.h>
+#include <errata_report.h>
+#include <spinlock.h>
+#include <utils.h>
+
+#ifdef IMAGE_BL1
+# define BL_STRING	"BL1"
+#elif defined(AARCH64) && defined(IMAGE_BL31)
+# define BL_STRING	"BL31"
+#elif defined(AARCH32) && defined(IMAGE_BL32)
+# define BL_STRING	"BL32"
+#else
+# error This image should not be printing errata status
+#endif
+
+/* Errata format: BL stage, CPU, errata ID, message */
+#define ERRATA_FORMAT	"%s: %s: errata workaround for %s was %s\n"
+
+/*
+ * Returns whether errata needs to be reported. Passed arguments are private to
+ * a CPU type.
+ */
+int errata_needs_reporting(spinlock_t *lock, uint32_t *reported)
+{
+	int report_now;
+
+	/* If already reported, return false. */
+	if (*reported)
+		return 0;
+
+	/*
+	 * Acquire lock. Determine whether status needs reporting, and then mark
+	 * report status to true.
+	 */
+	spin_lock(lock);
+	report_now = !(*reported);
+	if (report_now)
+		*reported = 1;
+	spin_unlock(lock);
+
+	return report_now;
+}
+
+/*
+ * Print errata status message.
+ *
+ * Unknown: WARN
+ * Missing: WARN
+ * Applied: INFO
+ * Not applied: VERBOSE
+ */
+void errata_print_msg(int status, const char *cpu, const char *id)
+{
+	/* Errata status strings */
+	static const char *const errata_status_str[] = {
+		[ERRATA_NOT_APPLIES] = "not applied",
+		[ERRATA_APPLIES] = "applied",
+		[ERRATA_MISSING] = "missing!"
+	};
+	static const char *const __unused bl_str = BL_STRING;
+	const char *msg __unused;
+
+
+	assert(status >= 0 && status < ARRAY_SIZE(errata_status_str));
+	assert(cpu);
+	assert(id);
+
+	msg = errata_status_str[status];
+
+	switch (status) {
+	case ERRATA_NOT_APPLIES:
+		VERBOSE(ERRATA_FORMAT, bl_str, cpu, id, msg);
+		break;
+
+	case ERRATA_APPLIES:
+		INFO(ERRATA_FORMAT, bl_str, cpu, id, msg);
+		break;
+
+	case ERRATA_MISSING:
+		WARN(ERRATA_FORMAT, bl_str, cpu, id, msg);
+		break;
+
+	default:
+		WARN(ERRATA_FORMAT, bl_str, cpu, id, "unknown");
+		break;
+	}
+}
diff --git a/lib/psci/psci_lib.mk b/lib/psci/psci_lib.mk
index 8daa831..82736cd 100644
--- a/lib/psci/psci_lib.mk
+++ b/lib/psci/psci_lib.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are met:
@@ -32,6 +32,7 @@
 				lib/el3_runtime/${ARCH}/cpu_data.S	\
 				lib/el3_runtime/${ARCH}/context_mgmt.c	\
 				lib/cpus/${ARCH}/cpu_helpers.S		\
+				lib/cpus/errata_report.c		\
 				lib/locks/exclusive/${ARCH}/spinlock.S	\
 				lib/psci/psci_off.c			\
 				lib/psci/psci_on.c			\
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index cb8b77d..7327b92 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -34,6 +34,7 @@
 #include <bl_common.h>
 #include <context.h>
 #include <context_mgmt.h>
+#include <errata_report.h>
 #include <platform.h>
 #include <stddef.h>
 #include "psci_private.h"
@@ -287,6 +288,9 @@
 
 	/* Initialize the cpu_ops pointer. */
 	init_cpu_ops();
+
+	/* Having initialized cpu_ops, we can now print errata status */
+	print_errata_status();
 }
 
 /******************************************************************************