Merge pull request #1232 from masahir0y/uniphier

uniphier: migrate to BL2-AT-EL3
diff --git a/Makefile b/Makefile
index 1cd6b62..c16cad7 100644
--- a/Makefile
+++ b/Makefile
@@ -488,6 +488,7 @@
 $(eval $(call assert_boolean,GICV2_G0_FOR_EL3))
 $(eval $(call assert_boolean,HW_ASSISTED_COHERENCY))
 $(eval $(call assert_boolean,LOAD_IMAGE_V2))
+$(eval $(call assert_boolean,MULTI_CONSOLE_API))
 $(eval $(call assert_boolean,NS_TIMER_SWITCH))
 $(eval $(call assert_boolean,PL011_GENERIC_UART))
 $(eval $(call assert_boolean,PROGRAMMABLE_RESET_ADDRESS))
@@ -530,6 +531,7 @@
 $(eval $(call add_define,HW_ASSISTED_COHERENCY))
 $(eval $(call add_define,LOAD_IMAGE_V2))
 $(eval $(call add_define,LOG_LEVEL))
+$(eval $(call add_define,MULTI_CONSOLE_API))
 $(eval $(call add_define,NS_TIMER_SWITCH))
 $(eval $(call add_define,PL011_GENERIC_UART))
 $(eval $(call add_define,PLAT_${PLAT}))
diff --git a/bl31/aarch64/crash_reporting.S b/bl31/aarch64/crash_reporting.S
index cf32b31..0986a0a 100644
--- a/bl31/aarch64/crash_reporting.S
+++ b/bl31/aarch64/crash_reporting.S
@@ -9,13 +9,13 @@
 #include <cpu_data.h>
 #include <plat_macros.S>
 #include <platform_def.h>
+#include <utils_def.h>
 
 	.globl	report_unhandled_exception
 	.globl	report_unhandled_interrupt
 	.globl	el3_panic
 
 #if CRASH_REPORTING
-#define REG_SIZE	0x8
 
 	/* ------------------------------------------------------
 	 * The below section deals with dumping the system state
@@ -92,7 +92,7 @@
 	mov	x6, x4
 	adr	x4, print_spacer
 	bl	asm_print_str
-	ldr	x4, [x7], #REG_SIZE
+	ldr	x4, [x7], #REGSZ
 	bl	asm_print_hex
 	bl	print_newline
 	b	test_size_list
@@ -114,9 +114,9 @@
 	/* restore the crash buf address in x0 */
 	mrs	x0, tpidr_el3
 	stp	x8, x9, [x0]
-	stp	x10, x11, [x0, #REG_SIZE * 2]
-	stp	x12, x13, [x0, #REG_SIZE * 4]
-	stp	x14, x15, [x0, #REG_SIZE * 6]
+	stp	x10, x11, [x0, #REGSZ * 2]
+	stp	x12, x13, [x0, #REGSZ * 4]
+	stp	x14, x15, [x0, #REGSZ * 6]
 	b	size_controlled_print
 endfunc str_in_crash_buf_print
 
@@ -136,7 +136,7 @@
 	add	x0, x0, #CPU_DATA_CRASH_BUF_OFFSET
 	/* Store crash buffer address in tpidr_el3 */
 	msr	tpidr_el3, x0
-	str	x1, [x0, #REG_SIZE]
+	str	x1, [x0, #REGSZ]
 	mov	x1, sp
 	str	x1, [x0]
 	.endm
@@ -214,9 +214,9 @@
 	/* Retrieve the crash buf from tpidr_el3 */
 	mrs	x0, tpidr_el3
 	/* Store x2 - x6, x30 in the crash buffer */
-	stp	x2, x3, [x0, #REG_SIZE * 2]
-	stp	x4, x5, [x0, #REG_SIZE * 4]
-	stp	x6, x30, [x0, #REG_SIZE * 6]
+	stp	x2, x3, [x0, #REGSZ * 2]
+	stp	x4, x5, [x0, #REGSZ * 4]
+	stp	x6, x30, [x0, #REGSZ * 6]
 	/* Initialize the crash console */
 	bl	plat_crash_console_init
 	/* Verify the console is initialized */
@@ -227,13 +227,13 @@
 	/* load the crash buf address */
 	mrs	x0, tpidr_el3
 	/* report x30 first from the crash buf */
-	ldr	x4, [x0, #REG_SIZE * 7]
+	ldr	x4, [x0, #REGSZ * 7]
 	bl	asm_print_hex
 	bl	print_newline
 	/* Load the crash buf address */
 	mrs	x0, tpidr_el3
 	/* Now mov x7 into crash buf */
-	str	x7, [x0, #REG_SIZE * 7]
+	str	x7, [x0, #REGSZ * 7]
 
 	/* Report x0 - x29 values stored in crash buf*/
 	/* Store the ascii list pointer in x6 */
@@ -246,15 +246,15 @@
 	mrs	x0, tpidr_el3
 	/* Store the rest of gp regs and print */
 	stp	x16, x17, [x0]
-	stp	x18, x19, [x0, #REG_SIZE * 2]
-	stp	x20, x21, [x0, #REG_SIZE * 4]
-	stp	x22, x23, [x0, #REG_SIZE * 6]
+	stp	x18, x19, [x0, #REGSZ * 2]
+	stp	x20, x21, [x0, #REGSZ * 4]
+	stp	x22, x23, [x0, #REGSZ * 6]
 	bl	size_controlled_print
 	/* Load the crash buf address */
 	mrs	x0, tpidr_el3
 	stp	x24, x25, [x0]
-	stp	x26, x27, [x0, #REG_SIZE * 2]
-	stp	x28, x29, [x0, #REG_SIZE * 4]
+	stp	x26, x27, [x0, #REGSZ * 2]
+	stp	x28, x29, [x0, #REGSZ * 4]
 	bl	size_controlled_print
 
 	/* Print the el3 sys registers */
diff --git a/bl32/sp_min/aarch32/entrypoint.S b/bl32/sp_min/aarch32/entrypoint.S
index b2b7953..e7528d3 100644
--- a/bl32/sp_min/aarch32/entrypoint.S
+++ b/bl32/sp_min/aarch32/entrypoint.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -17,6 +17,8 @@
 	.globl	sp_min_vector_table
 	.globl	sp_min_entrypoint
 	.globl	sp_min_warm_entrypoint
+	.globl	sp_min_handle_smc
+	.globl	sp_min_handle_fiq
 
 	.macro route_fiq_to_sp_min reg
 		/* -----------------------------------------------------
@@ -43,12 +45,12 @@
 vector_base sp_min_vector_table
 	b	sp_min_entrypoint
 	b	plat_panic_handler	/* Undef */
-	b	handle_smc		/* Syscall */
+	b	sp_min_handle_smc	/* Syscall */
 	b	plat_panic_handler	/* Prefetch abort */
 	b	plat_panic_handler	/* Data abort */
 	b	plat_panic_handler	/* Reserved */
 	b	plat_panic_handler	/* IRQ */
-	b	handle_fiq		/* FIQ */
+	b	sp_min_handle_fiq	/* FIQ */
 
 
 /*
@@ -151,7 +153,7 @@
 /*
  * SMC handling function for SP_MIN.
  */
-func handle_smc
+func sp_min_handle_smc
 	/* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */
 	str	lr, [sp, #SMC_CTX_LR_MON]
 
@@ -199,12 +201,12 @@
 
 	/* `r0` points to `smc_ctx_t` */
 	b	sp_min_exit
-endfunc handle_smc
+endfunc sp_min_handle_smc
 
 /*
  * Secure Interrupts handling function for SP_MIN.
  */
-func handle_fiq
+func sp_min_handle_fiq
 #if !SP_MIN_WITH_SECURE_FIQ
 	b plat_panic_handler
 #else
@@ -242,7 +244,7 @@
 
 	b	sp_min_exit
 #endif
-endfunc handle_fiq
+endfunc sp_min_handle_fiq
 
 /*
  * The Warm boot entrypoint for SP_MIN.
diff --git a/bl32/sp_min/sp_min.mk b/bl32/sp_min/sp_min.mk
index 56489a3..67a1981 100644
--- a/bl32/sp_min/sp_min.mk
+++ b/bl32/sp_min/sp_min.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -26,6 +26,11 @@
 BL32_SOURCES		+=	lib/extensions/amu/aarch32/amu.c
 endif
 
+ifeq (${WORKAROUND_CVE_2017_5715},1)
+BL32_SOURCES		+=	bl32/sp_min/workaround_cve_2017_5715_bpiall.S	\
+				bl32/sp_min/workaround_cve_2017_5715_icache_inv.S
+endif
+
 BL32_LINKERFILE	:=	bl32/sp_min/sp_min.ld.S
 
 # Include the platform-specific SP_MIN Makefile
diff --git a/bl32/sp_min/workaround_cve_2017_5715_bpiall.S b/bl32/sp_min/workaround_cve_2017_5715_bpiall.S
new file mode 100644
index 0000000..5387cef
--- /dev/null
+++ b/bl32/sp_min/workaround_cve_2017_5715_bpiall.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.globl	workaround_bpiall_runtime_exceptions
+
+vector_base workaround_bpiall_runtime_exceptions
+	/* We encode the exception entry in the bottom 3 bits of SP */
+	add	sp, sp, #1	/* Reset: 0b111 */
+	add	sp, sp, #1	/* Undef: 0b110 */
+	add	sp, sp, #1	/* Syscall: 0b101 */
+	add	sp, sp, #1	/* Prefetch abort: 0b100 */
+	add	sp, sp, #1	/* Data abort: 0b011 */
+	add	sp, sp, #1	/* Reserved: 0b010 */
+	add	sp, sp, #1	/* IRQ: 0b001 */
+	nop			/* FIQ: 0b000 */
+
+	/*
+	 * Invalidate the branch predictor, `r0` is a dummy register
+	 * and is unused.
+	 */
+	stcopr	r0, BPIALL
+	isb
+
+	/*
+	 * As we cannot use any temporary registers and cannot
+	 * clobber SP, we can decode the exception entry using
+	 * an unrolled binary search.
+	 *
+	 * Note, if this code is re-used by other secure payloads,
+	 * the below exception entry vectors must be changed to
+	 * the vectors specific to that secure payload.
+	 */
+
+	tst	sp, #4
+	bne	1f
+
+	tst	sp, #2
+	bne	3f
+
+	/* Expected encoding: 0x1 and 0x0 */
+	tst	sp, #1
+	/* Restore original value of SP by clearing the bottom 3 bits */
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* IRQ */
+	b	sp_min_handle_fiq	/* FIQ */
+
+1:
+	tst	sp, #2
+	bne	2f
+
+	/* Expected encoding: 0x4 and 0x5 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_handle_smc	/* Syscall */
+	b	plat_panic_handler	/* Prefetch abort */
+
+2:
+	/* Expected encoding: 0x7 and 0x6 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_entrypoint	/* Reset */
+	b	plat_panic_handler	/* Undef */
+
+3:
+	/* Expected encoding: 0x2 and 0x3 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* Data abort */
+	b	plat_panic_handler	/* Reserved */
diff --git a/bl32/sp_min/workaround_cve_2017_5715_icache_inv.S b/bl32/sp_min/workaround_cve_2017_5715_icache_inv.S
new file mode 100644
index 0000000..9102b02
--- /dev/null
+++ b/bl32/sp_min/workaround_cve_2017_5715_icache_inv.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+
+	.globl	workaround_icache_inv_runtime_exceptions
+
+vector_base workaround_icache_inv_runtime_exceptions
+	/* We encode the exception entry in the bottom 3 bits of SP */
+	add	sp, sp, #1	/* Reset: 0b111 */
+	add	sp, sp, #1	/* Undef: 0b110 */
+	add	sp, sp, #1	/* Syscall: 0b101 */
+	add	sp, sp, #1	/* Prefetch abort: 0b100 */
+	add	sp, sp, #1	/* Data abort: 0b011 */
+	add	sp, sp, #1	/* Reserved: 0b010 */
+	add	sp, sp, #1	/* IRQ: 0b001 */
+	nop			/* FIQ: 0b000 */
+
+	/*
+	 * Invalidate the instruction cache, which we assume also
+	 * invalidates the branch predictor.  This may depend on
+	 * other CPU specific changes (e.g. an ACTLR setting).
+	 */
+	stcopr	r0, ICIALLU
+	isb
+
+	/*
+	 * As we cannot use any temporary registers and cannot
+	 * clobber SP, we can decode the exception entry using
+	 * an unrolled binary search.
+	 *
+	 * Note, if this code is re-used by other secure payloads,
+	 * the below exception entry vectors must be changed to
+	 * the vectors specific to that secure payload.
+	 */
+
+	tst	sp, #4
+	bne	1f
+
+	tst	sp, #2
+	bne	3f
+
+	/* Expected encoding: 0x1 and 0x0 */
+	tst	sp, #1
+	/* Restore original value of SP by clearing the bottom 3 bits */
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* IRQ */
+	b	sp_min_handle_fiq	/* FIQ */
+
+1:
+	/* Expected encoding: 0x4 and 0x5 */
+	tst	sp, #2
+	bne	2f
+
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_handle_smc	/* Syscall */
+	b	plat_panic_handler	/* Prefetch abort */
+
+2:
+	/* Expected encoding: 0x7 and 0x6 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	sp_min_entrypoint	/* Reset */
+	b	plat_panic_handler	/* Undef */
+
+3:
+	/* Expected encoding: 0x2 and 0x3 */
+	tst	sp, #1
+	bic	sp, sp, #0x7
+	bne	plat_panic_handler	/* Data abort */
+	b	plat_panic_handler	/* Reserved */
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index 84bd2cd..7683ded 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -1929,12 +1929,8 @@
 
 The purpose of this function is allow the platform to perform any BL31 runtime
 setup just prior to BL31 exit during cold boot. The default weak
-implementation of this function will invoke ``console_uninit()`` which will
-suppress any BL31 runtime logs.
-
-In ARM Standard platforms, this function will initialize the BL31 runtime
-console which will cause all further BL31 logs to be output to the
-runtime console.
+implementation of this function will invoke ``console_switch_state()`` to switch
+console output to consoles marked for use in the ``runtime`` state.
 
 Function : bl31\_get\_next\_image\_info() [mandatory]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2702,14 +2698,20 @@
 Crash Reporting mechanism (in BL31)
 -----------------------------------
 
+NOTE: This section assumes that your platform is enabling the MULTI_CONSOLE_API
+flag in its platform.mk. Not using this flag is deprecated for new platforms.
+
 BL31 implements a crash reporting mechanism which prints the various registers
-of the CPU to enable quick crash analysis and debugging. It requires that a
-console is designated as the crash console by the platform which will be used to
-print the register dump.
+of the CPU to enable quick crash analysis and debugging. By default, the
+definitions in ``plat/common/aarch64/platform\_helpers.S`` will cause the crash
+output to be routed over the normal console infrastructure and get printed on
+consoles configured to output in crash state. ``console_set_scope()`` can be
+used to control whether a console is used for crash output.
 
-The following functions must be implemented by the platform if it wants crash
-reporting mechanism in BL31. The functions are implemented in assembly so that
-they can be invoked without a C Runtime stack.
+In some cases (such as debugging very early crashes that happen before the
+normal boot console can be set up), platforms may want to control crash output
+more explicitly. For these, the following functions can be overridden by
+platform code. They are executed outside of a C environment and without a stack.
 
 Function : plat\_crash\_console\_init
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2720,9 +2722,30 @@
     Return   : int
 
 This API is used by the crash reporting mechanism to initialize the crash
-console. It must only use the general purpose registers x0 to x4 to do the
+console. It must only use the general purpose registers x0 through x7 to do the
 initialization and returns 1 on success.
 
+If you are trying to debug crashes before the console driver would normally get
+registered, you can use this to register a driver from assembly with hardcoded
+parameters. For example, you could register the 16550 driver like this:
+
+::
+
+    .section .data.crash_console      /* Reserve space for console structure */
+    crash_console:
+    .zero 6 * 8                       /* console_16550_t has 6 8-byte words */
+    func plat_crash_console_init
+        ldr     x0, =YOUR_16550_BASE_ADDR
+        ldr     x1, =YOUR_16550_SRCCLK_IN_HZ
+        ldr     x2, =YOUR_16550_TARGET_BAUD_RATE
+        adrp    x3, crash_console
+        add     x3, x3, :lo12:crash_console
+        b       console_16550_register  /* tail call, returns 1 on success */
+    endfunc plat_crash_console_init
+
+If you're trying to debug crashes in BL1, you can call the console_xxx_core_init
+function exported by some console drivers from here.
+
 Function : plat\_crash\_console\_putc
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2736,6 +2759,12 @@
 x2 to do its work. The parameter and the return value are in general purpose
 register x0.
 
+If you have registered a normal console driver in ``plat_crash_console_init``,
+you can keep the default implementation here (which calls ``console_putc()``).
+
+If you're trying to debug crashes in BL1, you can call the console_xxx_core_putc
+function exported by some console drivers from here.
+
 Function : plat\_crash\_console\_flush
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -2746,9 +2775,15 @@
 
 This API is used by the crash reporting mechanism to force write of all buffered
 data on the designated crash console. It should only use general purpose
-registers x0 and x1 to do its work. The return value is 0 on successful
+registers x0 through x5 to do its work. The return value is 0 on successful
 completion; otherwise the return value is -1.
 
+If you have registered a normal console driver in ``plat_crash_console_init``,
+you can keep the default implementation here (which calls ``console_flush()``).
+
+If you're trying to debug crashes in BL1, you can call the console_xx_core_flush
+function exported by some console drivers from here.
+
 Build flags
 -----------
 
diff --git a/drivers/arm/pl011/aarch64/pl011_console.S b/drivers/arm/pl011/aarch64/pl011_console.S
index 8b15d56..6f2510a 100644
--- a/drivers/arm/pl011/aarch64/pl011_console.S
+++ b/drivers/arm/pl011/aarch64/pl011_console.S
@@ -5,6 +5,7 @@
  */
 #include <arch.h>
 #include <asm_macros.S>
+#include <assert_macros.S>
 #include <pl011.h>
 
 /*
@@ -13,15 +14,21 @@
  */
 #include "../../../console/aarch64/console.S"
 
-
-	.globl	console_core_init
-	.globl	console_core_putc
-	.globl	console_core_getc
-	.globl	console_core_flush
+	/*
+	 * "core" functions are low-level implementations that don't require
+	 * writable memory and are thus safe to call in BL1 crash context.
+	 */
+	.globl console_pl011_core_init
+	.globl console_pl011_core_putc
+	.globl console_pl011_core_getc
+	.globl console_pl011_core_flush
 
+	.globl	console_pl011_putc
+	.globl	console_pl011_getc
+	.globl	console_pl011_flush
 
 	/* -----------------------------------------------
-	 * int console_core_init(uintptr_t base_addr,
+	 * int console_pl011_core_init(uintptr_t base_addr,
 	 * unsigned int uart_clk, unsigned int baud_rate)
 	 * Function to initialize the console without a
 	 * C Runtime to print debug information. This
@@ -34,7 +41,7 @@
 	 * Clobber list : x1, x2, x3, x4
 	 * -----------------------------------------------
 	 */
-func console_core_init
+func console_pl011_core_init
 	/* Check the input base address */
 	cbz	x0, core_init_fail
 #if !PL011_GENERIC_UART
@@ -71,10 +78,54 @@
 core_init_fail:
 	mov	w0, wzr
 	ret
-endfunc console_core_init
+endfunc console_pl011_core_init
+
+#if MULTI_CONSOLE_API
+	.globl console_pl011_register
+
+	/* -----------------------------------------------
+	 * int console_pl011_register(console_pl011_t *console,
+		uintptr_t base, uint32_t clk, uint32_t baud)
+	 * Function to initialize and register a new PL011
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: x0 - UART register base address
+	 *     w1 - UART clock in Hz
+	 *     w2 - Baud rate
+	 *     x3 - pointer to empty console_pl011_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * -----------------------------------------------
+	 */
+func console_pl011_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_PL011_BASE]
+
+	bl	console_pl011_core_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register pl011
+
+register_fail:
+	ret	x7
+endfunc console_pl011_register
+#else
+	.globl console_core_init
+	.globl console_core_putc
+	.globl console_core_getc
+	.globl console_core_flush
+	.equ console_core_init,console_pl011_core_init
+	.equ console_core_putc,console_pl011_core_putc
+	.equ console_core_getc,console_pl011_core_getc
+	.equ console_core_flush,console_pl011_core_flush
+#endif
 
 	/* --------------------------------------------------------
-	 * int console_core_putc(int c, uintptr_t base_addr)
+	 * int console_pl011_core_putc(int c, uintptr_t base_addr)
 	 * Function to output a character over the console. It
 	 * returns the character printed on success or -1 on error.
 	 * In : w0 - character to be printed
@@ -83,9 +134,12 @@
 	 * Clobber list : x2
 	 * --------------------------------------------------------
 	 */
-func console_core_putc
-	/* Check the input parameter */
-	cbz	x1, putc_error
+func console_pl011_core_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
 	/* Prepend '\r' to '\n' */
 	cmp	w0, #0xA
 	b.ne	2f
@@ -101,36 +155,75 @@
 	tbnz	w2, #PL011_UARTFR_TXFF_BIT, 2b
 	str	w0, [x1, #UARTDR]
 	ret
-putc_error:
-	mov	w0, #-1
-	ret
-endfunc console_core_putc
+endfunc console_pl011_core_putc
+
+	/* --------------------------------------------------------
+	 * int console_pl011_putc(int c, console_pl011_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_pl011_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x1, [x1, #CONSOLE_T_PL011_BASE]
+	b	console_pl011_core_putc
+endfunc console_pl011_putc
 
 	/* ---------------------------------------------
-	 * int console_core_getc(uintptr_t base_addr)
+	 * int console_pl011_core_getc(uintptr_t base_addr)
 	 * Function to get a character from the console.
 	 * It returns the character grabbed on success
-	 * or -1 on error.
+	 * or -1 if no character is available.
 	 * In : x0 - console base address
+	 * Out: w0 - character if available, else -1
 	 * Clobber list : x0, x1
 	 * ---------------------------------------------
 	 */
-func console_core_getc
-	cbz	x0, getc_error
-1:
+func console_pl011_core_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
 	/* Check if the receive FIFO is empty */
 	ldr	w1, [x0, #UARTFR]
-	tbnz	w1, #PL011_UARTFR_RXFE_BIT, 1b
+	tbnz	w1, #PL011_UARTFR_RXFE_BIT, no_char
 	ldr	w1, [x0, #UARTDR]
 	mov	w0, w1
 	ret
-getc_error:
-	mov	w0, #-1
+no_char:
+	mov	w0, #ERROR_NO_PENDING_CHAR
 	ret
-endfunc console_core_getc
+endfunc console_pl011_core_getc
+
+	/* ---------------------------------------------
+	 * int console_pl011_getc(console_pl011_t *console)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 if no character is available.
+	 * In : x0 - pointer to console_t structure
+	 * Out: w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_pl011_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_PL011_BASE]
+	b	console_pl011_core_getc
+endfunc console_pl011_getc
 
 	/* ---------------------------------------------
-	 * int console_core_flush(uintptr_t base_addr)
+	 * int console_pl011_core_flush(uintptr_t base_addr)
 	 * Function to force a write of all buffered
 	 * data that hasn't been output.
 	 * In : x0 - console base address
@@ -138,9 +231,11 @@
 	 * Clobber list : x0, x1
 	 * ---------------------------------------------
 	 */
-func console_core_flush
-	cbz	x0, flush_error
-
+func console_pl011_core_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
 1:
 	/* Loop until the transmit FIFO is empty */
 	ldr	w1, [x0, #UARTFR]
@@ -148,7 +243,22 @@
 
 	mov	w0, #0
 	ret
-flush_error:
-	mov	w0, #-1
-	ret
-endfunc console_core_flush
+endfunc console_pl011_core_flush
+
+	/* ---------------------------------------------
+	 * int console_pl011_flush(console_pl011_t *console)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output.
+	 * In : x0 - pointer to console_t structure
+	 * Out : return -1 on error else return 0.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_pl011_flush
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_PL011_BASE]
+	b	console_pl011_core_flush
+endfunc console_pl011_flush
diff --git a/drivers/cadence/uart/aarch64/cdns_console.S b/drivers/cadence/uart/aarch64/cdns_console.S
index f6a1532..fc357f8 100644
--- a/drivers/cadence/uart/aarch64/cdns_console.S
+++ b/drivers/cadence/uart/aarch64/cdns_console.S
@@ -5,16 +5,22 @@
  */
 #include <arch.h>
 #include <asm_macros.S>
+#include <assert_macros.S>
 #include <cadence/cdns_uart.h>
 
-	.globl  console_core_init
-	.globl  console_core_putc
-	.globl  console_core_getc
-	.globl	console_core_flush
+	/*
+	 * "core" functions are low-level implementations that don't require
+	 * writable memory and are thus safe to call in BL1 crash context.
+	 */
+	.globl console_cdns_core_init
+	.globl console_cdns_core_putc
+	.globl console_cdns_core_getc
+
+	.globl  console_cdns_putc
+	.globl  console_cdns_getc
 
 	/* -----------------------------------------------
-	 * int console_core_init(unsigned long base_addr,
-	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * int console_cdns_core_init(uintptr_t base_addr)
 	 * Function to initialize the console without a
 	 * C Runtime to print debug information. This
 	 * function will be accessed by console_init and
@@ -23,18 +29,13 @@
 	 * the HW (baud, ...) and only enable the trans-
 	 * mitter and receiver here.
 	 * In: x0 - console base address
-	 *     w1 - Uart clock in Hz
-	 *     w2 - Baud rate
 	 * Out: return 1 on success else 0 on error
 	 * Clobber list : x1, x2, x3
 	 * -----------------------------------------------
 	 */
-func console_core_init
+func console_cdns_core_init
 	/* Check the input base address */
 	cbz	x0, core_init_fail
-	/* Check baud rate and uart clock for sanity */
-	cbz	w1, core_init_fail
-	cbz	w2, core_init_fail
 
 	/* RX/TX enabled & reset */
 	mov	w3, #(R_UART_CR_TX_EN | R_UART_CR_RX_EN | R_UART_CR_TXRST | R_UART_CR_RXRST)
@@ -45,10 +46,51 @@
 core_init_fail:
 	mov	w0, wzr
 	ret
-endfunc console_core_init
+endfunc console_cdns_core_init
+
+#if MULTI_CONSOLE_API
+	.globl console_cdns_register
+
+	/* -----------------------------------------------
+	 * int console_cdns_register(console_cdns_t *console,
+		uintptr_t base, uint32_t clk, uint32_t baud)
+	 * Function to initialize and register a new CDNS
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: x0 - UART register base address
+	 *     x1 - pointer to empty console_cdns_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * -----------------------------------------------
+	 */
+func console_cdns_register
+	mov	x7, x30
+	mov	x6, x1
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_CDNS_BASE]
+
+	bl	console_cdns_core_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, v7
+	finish_console_register cdns
+
+register_fail:
+	ret	x7
+endfunc console_cdns_register
+#else
+	.globl console_core_init
+	.globl console_core_putc
+	.globl console_core_getc
+	.globl console_core_flush
+	.equ console_core_init,console_cdns_core_init
+	.equ console_core_putc,console_cdns_core_putc
+	.equ console_core_getc,console_cdns_core_getc
+#endif
 
 	/* --------------------------------------------------------
-	 * int console_core_putc(int c, unsigned long base_addr)
+	 * int console_cdns_core_putc(int c, uintptr_t base_addr)
 	 * Function to output a character over the console. It
 	 * returns the character printed on success or -1 on error.
 	 * In : w0 - character to be printed
@@ -57,9 +99,12 @@
 	 * Clobber list : x2
 	 * --------------------------------------------------------
 	 */
-func console_core_putc
-	/* Check the input parameter */
-	cbz	x1, putc_error
+func console_cdns_core_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
 	/* Prepend '\r' to '\n' */
 	cmp	w0, #0xA
 	b.ne	2f
@@ -75,36 +120,76 @@
 	tbnz	w2, #UART_SR_INTR_TFUL_BIT, 2b
 	str	w0, [x1, #R_UART_TX]
 	ret
-putc_error:
-	mov	w0, #-1
-	ret
-endfunc console_core_putc
+endfunc console_cdns_core_putc
+
+	/* --------------------------------------------------------
+	 * int console_cdns_putc(int c, console_cdns_t *cdns)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_cdns_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x1, [x1, #CONSOLE_T_CDNS_BASE]
+	b	console_cdns_core_putc
+endfunc console_cdns_putc
 
 	/* ---------------------------------------------
-	 * int console_core_getc(unsigned long base_addr)
+	 * int console_cdns_core_getc(uintptr_t base_addr)
 	 * Function to get a character from the console.
 	 * It returns the character grabbed on success
-	 * or -1 on error.
+	 * or -1 if no character is available.
 	 * In : x0 - console base address
+	 * Out: w0 - character if available, else -1
 	 * Clobber list : x0, x1
 	 * ---------------------------------------------
 	 */
-func console_core_getc
-	cbz	x0, getc_error
-1:
+func console_cdns_core_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
 	/* Check if the receive FIFO is empty */
 	ldr	w1, [x0, #R_UART_SR]
-	tbnz	w1, #UART_SR_INTR_REMPTY_BIT, 1b
+	tbnz	w1, #UART_SR_INTR_REMPTY_BIT, no_char
 	ldr	w1, [x0, #R_UART_RX]
 	mov	w0, w1
 	ret
-getc_error:
-	mov	w0, #-1
+no_char:
+	mov	w0, #ERROR_NO_PENDING_CHAR
 	ret
-endfunc console_core_getc
+endfunc console_cdns_core_getc
 
 	/* ---------------------------------------------
+	 * int console_cdns_getc(console_cdns_t *console)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 if no character is available.
+	 * In : x0 - pointer to console_t structure
+	 * Out: w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_cdns_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_CDNS_BASE]
+	b	console_cdns_core_getc
+endfunc console_cdns_getc
+
+	/* ---------------------------------------------
 	 * int console_core_flush(uintptr_t base_addr)
+	 * DEPRECATED: Not used with MULTI_CONSOLE_API!
 	 * Function to force a write of all buffered
 	 * data that hasn't been output.
 	 * In : x0 - console base address
diff --git a/drivers/console/aarch64/console.S b/drivers/console/aarch64/console.S
index 7cc04dd..f847ed5 100644
--- a/drivers/console/aarch64/console.S
+++ b/drivers/console/aarch64/console.S
@@ -1,105 +1,11 @@
 /*
- * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
-#include <asm_macros.S>
-
-	.globl	console_init
-	.globl	console_uninit
-	.globl	console_putc
-	.globl	console_getc
-	.globl	console_flush
-
-	/*
-	 *  The console base is in the data section and not in .bss
-	 *  even though it is zero-init. In particular, this allows
-	 *  the console functions to start using this variable before
-	 *  the runtime memory is initialized for images which do not
-	 *  need to copy the .data section from ROM to RAM.
-	 */
-.section .data.console_base ; .align 3
-	console_base: .quad 0x0
-
-	/* -----------------------------------------------
-	 * int console_init(uintptr_t base_addr,
-	 * unsigned int uart_clk, unsigned int baud_rate)
-	 * Function to initialize the console without a
-	 * C Runtime to print debug information. It saves
-	 * the console base to the data section.
-	 * In: x0 - console base address
-	 *     w1 - Uart clock in Hz
-	 *     w2 - Baud rate
-	 * out: return 1 on success else 0 on error
-	 * Clobber list : x1 - x4
-	 * -----------------------------------------------
-	 */
-func console_init
-	/* Check the input base address */
-	cbz	x0, init_fail
-	adrp	x3, console_base
-	str	x0, [x3, :lo12:console_base]
-	b	console_core_init
-init_fail:
-	ret
-endfunc console_init
-
-	/* -----------------------------------------------
-	 * void console_uninit(void)
-	 * Function to finish the use of console driver.
-	 * It sets the console_base as NULL so that any
-	 * further invocation of `console_putc` or
-	 * `console_getc` APIs would return error.
-	 * -----------------------------------------------
-	 */
-func console_uninit
-	mov	x0, #0
-	adrp	x3, console_base
-	str	x0, [x3, :lo12:console_base]
-	ret
-endfunc console_uninit
-
-	/* ---------------------------------------------
-	 * int console_putc(int c)
-	 * Function to output a character over the
-	 * console. It returns the character printed on
-	 * success or -1 on error.
-	 * In : x0 - character to be printed
-	 * Out : return -1 on error else return character.
-	 * Clobber list : x1, x2
-	 * ---------------------------------------------
-	 */
-func console_putc
-	adrp	x2, console_base
-	ldr	x1, [x2, :lo12:console_base]
-	b	console_core_putc
-endfunc console_putc
-
-	/* ---------------------------------------------
-	 * int console_getc(void)
-	 * Function to get a character from the console.
-	 * It returns the character grabbed on success
-	 * or -1 on error.
-	 * Clobber list : x0, x1
-	 * ---------------------------------------------
-	 */
-func console_getc
-	adrp	x1, console_base
-	ldr	x0, [x1, :lo12:console_base]
-	b	console_core_getc
-endfunc console_getc
 
-	/* ---------------------------------------------
-	 * int console_flush(void)
-	 * Function to force a write of all buffered
-	 * data that hasn't been output. It returns 0
-	 * upon successful completion, otherwise it
-	 * returns -1.
-	 * Clobber list : x0, x1
-	 * ---------------------------------------------
-	 */
-func console_flush
-	adrp	x1, console_base
-	ldr	x0, [x1, :lo12:console_base]
-	b	console_core_flush
-endfunc console_flush
+#if MULTI_CONSOLE_API
+#include "multi_console.S"
+#else
+#include "deprecated_console.S"
+#endif
diff --git a/drivers/console/aarch64/deprecated_console.S b/drivers/console/aarch64/deprecated_console.S
new file mode 100644
index 0000000..c83e246
--- /dev/null
+++ b/drivers/console/aarch64/deprecated_console.S
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <asm_macros.S>
+
+/*
+ * This is the common console core code for the deprecated single-console API.
+ * New platforms should set MULTI_CONSOLE_API=1 and not use this file.
+ */
+
+	.globl	console_init
+	.globl	console_uninit
+	.globl	console_putc
+	.globl	console_getc
+	.globl	console_flush
+
+	/*
+	 *  The console base is in the data section and not in .bss
+	 *  even though it is zero-init. In particular, this allows
+	 *  the console functions to start using this variable before
+	 *  the runtime memory is initialized for images which do not
+	 *  need to copy the .data section from ROM to RAM.
+	 */
+.section .data.console_base ; .align 3
+	console_base: .quad 0x0
+
+	/* -----------------------------------------------
+	 * int console_init(uintptr_t base_addr,
+	 * unsigned int uart_clk, unsigned int baud_rate)
+	 * Function to initialize the console without a
+	 * C Runtime to print debug information. It saves
+	 * the console base to the data section.
+	 * In: x0 - console base address
+	 *     w1 - Uart clock in Hz
+	 *     w2 - Baud rate
+	 * out: return 1 on success else 0 on error
+	 * Clobber list : x1 - x4
+	 * -----------------------------------------------
+	 */
+func console_init
+	/* Check the input base address */
+	cbz	x0, init_fail
+	adrp	x3, console_base
+	str	x0, [x3, :lo12:console_base]
+	b	console_core_init
+init_fail:
+	ret
+endfunc console_init
+
+	/* -----------------------------------------------
+	 * void console_uninit(void)
+	 * Function to finish the use of console driver.
+	 * It sets the console_base as NULL so that any
+	 * further invocation of `console_putc` or
+	 * `console_getc` APIs would return error.
+	 * -----------------------------------------------
+	 */
+func console_uninit
+	mov	x0, #0
+	adrp	x3, console_base
+	str	x0, [x3, :lo12:console_base]
+	ret
+endfunc console_uninit
+
+	/* ---------------------------------------------
+	 * int console_putc(int c)
+	 * Function to output a character over the
+	 * console. It returns the character printed on
+	 * success or -1 on error.
+	 * In : x0 - character to be printed
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x1, x2
+	 * ---------------------------------------------
+	 */
+func console_putc
+	adrp	x2, console_base
+	ldr	x1, [x2, :lo12:console_base]
+	b	console_core_putc
+endfunc console_putc
+
+	/* ---------------------------------------------
+	 * int console_getc(void)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on error.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_getc
+	adrp	x1, console_base
+	ldr	x0, [x1, :lo12:console_base]
+	b	console_core_getc
+endfunc console_getc
+
+	/* ---------------------------------------------
+	 * int console_flush(void)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output. It returns 0
+	 * upon successful completion, otherwise it
+	 * returns -1.
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_flush
+	adrp	x1, console_base
+	ldr	x0, [x1, :lo12:console_base]
+	b	console_core_flush
+endfunc console_flush
diff --git a/drivers/console/aarch64/multi_console.S b/drivers/console/aarch64/multi_console.S
new file mode 100644
index 0000000..15c3ba4
--- /dev/null
+++ b/drivers/console/aarch64/multi_console.S
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <console.h>
+
+	.globl	console_register
+	.globl	console_unregister
+	.globl  console_set_scope
+	.globl	console_switch_state
+	.globl	console_putc
+	.globl	console_getc
+	.globl	console_flush
+
+	/*
+	 *  The console list pointer is in the data section and not in
+	 *  .bss even though it is zero-init. In particular, this allows
+	 *  the console functions to start using this variable before
+	 *  the runtime memory is initialized for images which do not
+	 *  need to copy the .data section from ROM to RAM.
+	 */
+.section .data.console_list ; .align 3
+	console_list: .quad 0x0
+.section .data.console_state ; .align 0
+	console_state: .byte CONSOLE_FLAG_BOOT
+
+	/* -----------------------------------------------
+	 * int console_register(console_t *console)
+	 * Function to insert a new console structure into
+	 * the console list. Should usually be called by
+	 * console_<driver>_register implementations. The
+	 * data structure passed will be taken over by the
+	 * console framework and *MUST* be allocated in
+	 * persistent memory (e.g. the data section).
+	 * In : x0 - address of console_t structure
+	 * Out: x0 - Always 1 (for easier tail calling)
+	 * Clobber list: x0, x1, x14
+	 * -----------------------------------------------
+	 */
+func console_register
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+	adrp	x1, __STACKS_START__
+	add	x1, x1, :lo12:__STACKS_START__
+	cmp	x0, x1
+	b.lo	not_on_stack
+	adrp	x1, __STACKS_END__
+	add	x1, x1, :lo12:__STACKS_END__
+	cmp	x0, x1
+	ASM_ASSERT(hs)
+not_on_stack:
+#endif /* ENABLE_ASSERTIONS */
+	adrp	x14, console_list
+	ldr	x1, [x14, :lo12:console_list]	/* X1 = first struct in list */
+	str	x0, [x14, :lo12:console_list]	/* list head = new console */
+	str	x1, [x0, #CONSOLE_T_NEXT]	/* new console next ptr = X1 */
+	mov	x0, #1
+	ret
+endfunc console_register
+
+	/* -----------------------------------------------
+	 * int console_unregister(console_t *console)
+	 * Function to find a specific console in the list
+	 * of currently active consoles and remove it.
+	 * In: x0 - address of console_t struct to remove
+	 * Out: x0 - removed address, or NULL if not found
+	 * Clobber list: x0, x1, x14
+	 * -----------------------------------------------
+	 */
+func console_unregister
+	adrp	x14, console_list
+	add	x14, x14, :lo12:console_list	/* X14 = ptr to first struct */
+	ldr	x1, [x14]			/* X1 = first struct */
+
+unregister_loop:
+	cbz	x1, unregister_not_found
+	cmp	x0, x1
+	b.eq	unregister_found
+	ldr	x14, [x14]			/* X14 = next ptr of struct */
+	ldr	x1, [x14]			/* X1 = next struct */
+	b	unregister_loop
+
+unregister_found:
+	ldr	x1, [x1]			/* X1 = next struct */
+	str	x1, [x14]			/* prev->next = cur->next */
+	ret
+
+unregister_not_found:
+	mov	x0, #0				/* return NULL if not found */
+	ret
+endfunc console_unregister
+
+	/* -----------------------------------------------
+	 * void console_switch_state(unsigned int new_state)
+	 * Function to switch the current console state.
+	 * The console state determines which of the
+	 * registered consoles are actually used at a time.
+	 * In : w0 - global console state to move to
+	 * Clobber list: x0, x1
+	 * -----------------------------------------------
+	 */
+func console_switch_state
+	adrp	x1, console_state
+	strb	w0, [x1, :lo12:console_state]
+	ret
+endfunc console_switch_state
+
+	/* -----------------------------------------------
+	 * void console_set_scope(console_t *console,
+	 *                       unsigned int scope)
+	 * Function to update the states that a given console
+	 * may be active in.
+	 * In : x0 - pointer to console_t struct
+	 *    : w1 - new active state mask
+	 * Clobber list: x0, x1, x2
+	 * -----------------------------------------------
+	 */
+func console_set_scope
+#if ENABLE_ASSERTIONS
+	tst	w1, #~CONSOLE_FLAG_SCOPE_MASK
+	ASM_ASSERT(eq)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	w2, [x0, #CONSOLE_T_FLAGS]
+	and	w2, w2, #~CONSOLE_FLAG_SCOPE_MASK
+	orr	w2, w2, w1
+	str	w2, [x0, #CONSOLE_T_FLAGS]
+	ret
+endfunc console_set_scope
+
+	/* ---------------------------------------------
+	 * int console_putc(int c)
+	 * Function to output a character. Calls all
+	 * active console's putc() handlers in succession.
+	 * In : x0 - character to be printed
+	 * Out: x0 - printed character on success, or < 0
+	             if at least one console had an error
+	 * Clobber list : x0, x1, x2, x12, x13, x14, x15
+	 * ---------------------------------------------
+	 */
+func console_putc
+	mov	x15, x30
+	mov	w13, #ERROR_NO_VALID_CONSOLE	/* W13 = current return value */
+	mov	w12, w0				/* W12 = character to print */
+	adrp	x14, console_list
+	ldr	x14, [x14, :lo12:console_list]	/* X14 = first console struct */
+
+putc_loop:
+	cbz	x14, putc_done
+	adrp	x1, console_state
+	ldrb	w1, [x1, :lo12:console_state]
+	ldr	x2, [x14, #CONSOLE_T_FLAGS]
+	tst	w1, w2
+	b.eq	putc_continue
+	ldr	x2, [x14, #CONSOLE_T_PUTC]
+	cbz	x2, putc_continue
+	mov	w0, w12
+	mov	x1, x14
+	blr	x2
+	cmp	w13, #ERROR_NO_VALID_CONSOLE	/* update W13 if it's NOVALID */
+	ccmp	w0, #0, #0x8, ne		/* else update it if W0 < 0 */
+	csel	w13, w0, w13, lt
+putc_continue:
+	ldr	x14, [x14]			/* X14 = next struct */
+	b	putc_loop
+
+putc_done:
+	mov	w0, w13
+	ret	x15
+endfunc console_putc
+
+	/* ---------------------------------------------
+	 * int console_getc(void)
+	 * Function to get a character from any console.
+	 * Keeps looping through all consoles' getc()
+	 * handlers until one of them returns a
+	 * character, then stops iterating and returns
+	 * that character to the caller. Will stop looping
+	 * if all active consoles report real errors
+	 * (other than just not having a char available).
+	 * Out : x0 - read character, or < 0 on error
+	 * Clobber list : x0, x1, x13, x14, x15
+	 * ---------------------------------------------
+	 */
+func console_getc
+	mov	x15, x30
+getc_try_again:
+	mov	w13, #ERROR_NO_VALID_CONSOLE	/* W13 = current return value */
+	adrp	x14, console_list
+	ldr	x14, [x14, :lo12:console_list]	/* X14 = first console struct */
+	cbnz	x14, getc_loop
+	mov	w0, w13				/* If no consoles registered */
+	ret	x15				/* return immediately. */
+
+getc_loop:
+	adrp	x0, console_state
+	ldrb	w0, [x0, :lo12:console_state]
+	ldr	x1, [x14, #CONSOLE_T_FLAGS]
+	tst	w0, w1
+	b.eq	getc_continue
+	ldr	x1, [x14, #CONSOLE_T_GETC]
+	cbz	x1, getc_continue
+	mov	x0, x14
+	blr	x1
+	cmp	w0, #0				/* if X0 >= 0: return */
+	b.ge	getc_found
+	cmp	w13, #ERROR_NO_PENDING_CHAR	/* may update W13 (NOCHAR has */
+	csel	w13, w13, w0, eq		/* precedence vs real errors) */
+getc_continue:
+	ldr	x14, [x14]			/* X14 = next struct */
+	cbnz	x14, getc_loop
+	cmp	w13, #ERROR_NO_PENDING_CHAR	/* Keep scanning if at least */
+	b.eq	getc_try_again			/* one console returns NOCHAR */
+	mov	w0, w13
+
+getc_found:
+	ret	x15
+endfunc console_getc
+
+	/* ---------------------------------------------
+	 * int console_flush(void)
+	 * Function to force a write of all buffered
+	 * data that hasn't been output. Calls all
+	 * console's flush() handlers in succession.
+	 * Out: x0 - 0 on success, < 0 if at least one error
+	 * Clobber list : x0, x1, x2, x3, x4, x5, x13, x14, x15
+	 * ---------------------------------------------
+	 */
+func console_flush
+	mov	x15, x30
+	mov	w13, #ERROR_NO_VALID_CONSOLE	/* W13 = current return value */
+	adrp	x14, console_list
+	ldr	x14, [x14, :lo12:console_list]	/* X14 = first console struct */
+
+flush_loop:
+	cbz	x14, flush_done
+	adrp	x1, console_state
+	ldrb	w1, [x1, :lo12:console_state]
+	ldr	x2, [x14, #CONSOLE_T_FLAGS]
+	tst	w1, w2
+	b.eq	flush_continue
+	ldr	x1, [x14, #CONSOLE_T_FLUSH]
+	cbz	x1, flush_continue
+	mov	x0, x14
+	blr	x1
+	cmp	w13, #ERROR_NO_VALID_CONSOLE	/* update W13 if it's NOVALID */
+	ccmp	w0, #0, #0x8, ne		/* else update it if W0 < 0 */
+	csel	w13, w0, w13, lt
+flush_continue:
+	ldr	x14, [x14]			/* X14 = next struct */
+	b	flush_loop
+
+flush_done:
+	mov	w0, w13
+	ret	x15
+endfunc console_flush
diff --git a/drivers/console/aarch64/skeleton_console.S b/drivers/console/aarch64/skeleton_console.S
index 9db6157..1b5d739 100644
--- a/drivers/console/aarch64/skeleton_console.S
+++ b/drivers/console/aarch64/skeleton_console.S
@@ -4,99 +4,171 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 #include <asm_macros.S>
+#include <console_macros.S>
 
 	/*
-	 * This file contains a skeleton console implementation that can
-	 * be used as basis for a real console implementation by platforms
-	 * that do not contain PL011 hardware.
+	 * This file contains a skeleton console driver that can be used as
+	 * basis for a real console driver. Console drivers in Trusted Firmware
+	 * can be instantiated multiple times. Each instance is described by a
+	 * separate console_t structure which must be registered with the common
+	 * console framework via console_register(). Console drivers should
+	 * define a console_xxx_register() function that initializes a new
+	 * console_t structure passed in from the caller and registers it after
+	 * initializing the console hardware. Drivers may define their own
+	 * structures extending console_t to store private driver information.
+	 * Console drivers *MUST* take care that the console callbacks they
+	 * implement only change registers allowed in the clobber lists defined
+	 * in this file. (Note that in addition to the explicit clobber lists,
+	 * any function may always clobber the intra-procedure-call registers
+	 * X16 and X17, but may never depend on them retaining their values
+	 * across any function call.)
+	 * Platforms using drivers based on this template need to enable
+	 * MULTI_CONSOLE_API := 1 in their platform.mk.
 	 */
 
-	.globl	console_core_init
-	.globl	console_core_putc
-	.globl	console_core_getc
-	.globl	console_core_flush
+	.globl	console_xxx_register
+	.globl	console_xxx_putc
+	.globl	console_xxx_getc
+	.globl	console_xxx_flush
 
 	/* -----------------------------------------------
-	 * int console_core_init(uintptr_t base_addr,
-	 * unsigned int uart_clk, unsigned int baud_rate)
-	 * Function to initialize the console without a
-	 * C Runtime to print debug information. This
-	 * function will be accessed by console_init and
-	 * crash reporting.
-	 * In: x0 - console base address
-	 *     w1 - Uart clock in Hz
-	 *     w2 - Baud rate
-	 * Out: return 1 on success else 0 on error
-	 * Clobber list : x1, x2
+	 * int console_xxx_register(console_xxx_t *console,
+	 * 	...additional parameters as desired...)
+	 * Function to initialize and register the console.
+	 * The caller needs to pass an empty console_xxx_t
+	 * structure in which *MUST* be allocated in
+	 * persistent memory (e.g. a global or static local
+	 * variable, *NOT* on the stack).
+	 * In : x0 - pointer to empty console_t structure
+	 *      x1 through x7: additional parameters as desired
+	 * Out: x0 - 1 on success, 0 on error
+	 * Clobber list : x0 - x7
 	 * -----------------------------------------------
 	 */
-func console_core_init
-	/* Check the input base address */
-	cbz	x0, core_init_fail
-	/* Check baud rate and uart clock for sanity */
-	cbz	w1, core_init_fail
-	cbz	w2, core_init_fail
-	/* Insert implementation here */
-	mov	w0, #1
-	ret
-core_init_fail:
-	mov	w0, wzr
+func console_xxx_register
+	/*
+	 * Store parameters (e.g. hardware base address) in driver-specific
+	 * console_xxx_t structure field if they will need to be retrieved
+	 * by later console callback (e.g. putc).
+	 * Example:
+	 */
+	str	x1, [x0, #CONSOLE_T_XXX_BASE]
+	str	x2, [x0, #CONSOLE_T_XXX_SOME_OTHER_VALUE]
+
+	/*
+	 * Initialize console hardware, using x1 - x7 parameters as needed.
+	 * Keep console_t pointer in x0 for later.
+	 */
+
+	/* Macro to finish up registration and return (needs valid x0 + x30). */
+	finish_console_register xxx
+
+	/* Jump here if hardware init fails or parameters are invalid. */
+register_fail:
+	mov	w0, #0
 	ret
-endfunc console_core_init
+endfunc console_xxx_register
 
 	/* --------------------------------------------------------
-	 * int console_core_putc(int c, uintptr_t base_addr)
+	 * int console_xxx_putc(int c, console_xxx_t *console)
 	 * Function to output a character over the console. It
 	 * returns the character printed on success or -1 on error.
 	 * In : w0 - character to be printed
-	 *      x1 - console base address
-	 * Out : return -1 on error else return character.
-	 * Clobber list : x2
+	 *      x1 - pointer to console_t struct
+	 * Out: w0 - printed character on success, < 0 on error.
+	 * Clobber list : x0, x1, x2
 	 * --------------------------------------------------------
 	 */
-func console_core_putc
-	/* Check the input parameter */
-	cbz	x1, putc_error
-	/* Insert implementation here */
+func console_xxx_putc
+	/*
+	 * Retrieve values we need (e.g. hardware base address) from
+	 * console_xxx_t structure pointed to by x1.
+	 * Example:
+	 */
+	ldr	x1, [x1, #CONSOLE_T_XXX_BASE]
+
+	/*
+	 * Write w0 to hardware.
+	 */
+
 	ret
+
+	/* Jump here if output fails for any reason. */
 putc_error:
 	mov	w0, #-1
 	ret
-endfunc console_core_putc
+endfunc console_xxx_putc
 
 	/* ---------------------------------------------
-	 * int console_core_getc(uintptr_t base_addr)
+	 * int console_xxx_getc(console_xxx_t *console)
 	 * Function to get a character from the console.
-	 * It returns the character grabbed on success
-	 * or -1 on error.
-	 * In : x0 - console base address
+	 * Even though console_getc() is blocking, this
+	 * callback has to be non-blocking and always
+	 * return immediately to allow polling multiple
+	 * drivers concurrently.
+	 * Returns the character grabbed on success,
+	 * ERROR_NO_PENDING_CHAR if no character was
+	 * available at this time, or any value
+	 * between -2 and -127 if there was an error.
+	 * In : x0 - pointer to console_t struct
+	 * Out: w0 - character on success,
+	 *           ERROR_NO_PENDING_CHAR if no char,
+	 *           < -1 on error
 	 * Clobber list : x0, x1
 	 * ---------------------------------------------
 	 */
+func console_xxx_getc
+	/*
+	 * Retrieve values we need (e.g. hardware base address) from
+	 * console_xxx_t structure pointed to by x0.
+	 * Example:
+	 */
-func console_core_getc
-	cbz	x0, getc_error
-	/* Insert implementation here */
+	ldr	x1, [x0, #CONSOLE_T_XXX_BASE]
+
+	/*
+	 * Try to read character into w0 from hardware.
+	 */
+
 	ret
+
+	/* Jump here if there is no character available at this time. */
+getc_no_char:
+	mov	w0, #ERROR_NO_PENDING_CHAR
+	ret
+
+	/* Jump here if there was any hardware error. */
 getc_error:
-	mov	w0, #-1
+	mov	w0, #-2		/* may pick error codes between -2 and -127 */
 	ret
-endfunc console_core_getc
+endfunc console_xxx_getc
 
 	/* ---------------------------------------------
-	 * int console_core_flush(uintptr_t base_addr)
+	 * int console_xxx_flush(console_xxx_t *console)
 	 * Function to force a write of all buffered
 	 * data that hasn't been output.
-	 * In : x0 - console base address
-	 * Out : return -1 on error else return 0.
-	 * Clobber list : x0, x1
+	 * In : x0 - pointer to console_xxx_t struct
+	 * Out: w0 - 0 on success, < 0 on error
+	 * Clobber list : x0, x1, x2, x3, x4, x5
 	 * ---------------------------------------------
 	 */
+func console_xxx_flush
+	/*
+	 * Retrieve values we need (e.g. hardware base address) from
+	 * console_xxx_t structure pointed to by x0.
+	 * Example:
+	 */
+	ldr	x1, [x0, #CONSOLE_T_XXX_BASE]
+
+	/*
+	 * Flush all remaining output from hardware FIFOs. Do not return until
+	 * all data has been flushed or there was an unrecoverable error.
+	 */
-func console_core_flush
-	cbz	x0, flush_error
-	/* Insert implementation here */
+
 	mov	w0, #0
 	ret
+
+	/* Jump here if an unrecoverable error has been encountered. */
 flush_error:
 	mov	w0, #-1
 	ret
-endfunc console_core_flush
+endfunc console_xxx_flush
diff --git a/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S
new file mode 100644
index 0000000..2fc0603
--- /dev/null
+++ b/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <cbmem_console.h>
+#include <console_macros.S>
+
+/*
+ * This driver implements access to coreboot's in-memory console
+ * (CBMEM console). For the original implementation, see
+ * <coreboot>/src/lib/cbmem_console.c.
+ */
+
+	.globl console_cbmc_register
+	.globl console_cbmc_putc
+	.globl console_cbmc_flush
+
+	/* -----------------------------------------------
+	 * int console_cbmc_register(console_cbmc_t *console,
+	 *			     uintptr_t base)
+	 * Registers a new CBMEM console instance. Reads
+	 * the size field from the buffer header structure
+	 * and stores it in our console_cbmc_t struct, so
+	 * that we keep the size in secure memory where we
+	 * can trust it. A malicious EL1 could manipulate
+	 * the console buffer (including the header), so we
+	 * must not trust its contents after boot.
+	 * In:  x0 - CBMEM console base address
+	 *      x1 - pointer to empty console_cbmc_t struct
+	 * Out: x0 - 1 to indicate success
+	 * Clobber list: x0, x1, x2, x7
+	 * -----------------------------------------------
+	 */
+func console_cbmc_register
+	str	x0, [x1, #CONSOLE_T_CBMC_BASE]
+	ldr	w2, [x0]
+	str	w2, [x1, #CONSOLE_T_CBMC_SIZE]
+	mov	x0, x1
+	finish_console_register cbmc
+endfunc console_cbmc_register
+
+	/* -----------------------------------------------
+	 * int console_cbmc_puts(int c, console_cbmc_t *console)
+	 * Writes a character to the CBMEM console buffer,
+	 * including overflow handling of the cursor field.
+	 * The character must be preserved in x0.
+	 * In: x0 - character to be stored
+	 *     x1 - pointer to console_cbmc_t struct
+	 * Clobber list: x1, x2, x16, x17
+	 * -----------------------------------------------
+	 */
+func console_cbmc_putc
+	ldr	w2, [x1, #CONSOLE_T_CBMC_SIZE]
+	ldr	x1, [x1, #CONSOLE_T_CBMC_BASE]
+	add	x1, x1, #8		/* keep address of body in x1 */
+
+	ldr	w16, [x1, #-4]		/* load cursor (one u32 before body) */
+	and	w17, w16, #0xf0000000	/* keep flags part in w17 */
+	and	w16, w16, #0x0fffffff	/* keep actual cursor part in w16 */
+
+	cmp	w16, w2			/* sanity check that cursor < size */
+	b.lo	putc_within_bounds
+	mov	w0, #-1			/* cursor >= size must be malicious */
+	ret				/* so return error, don't write char */
+
+putc_within_bounds:
+	strb	w0, [x1, w16, uxtw]	/* body[cursor] = character */
+	add	w16, w16, #1		/* cursor++ */
+	cmp	w16, w2			/* if cursor < size... */
+	b.lo	putc_write_back		/* ...skip overflow handling */
+
+	mov	w16, #0			/* on overflow, set cursor back to 0 */
+	orr	w17, w17, #(1 << 31)	/* and set overflow flag */
+
+putc_write_back:
+	orr	w16, w16, w17		/* merge cursor and flags back */
+	str	w16, [x1, #-4]		/* write back cursor to memory */
+	ret
+endfunc	console_cbmc_putc
+
+	/* -----------------------------------------------
+	 * int console_cbmc_flush(console_cbmc_t *console)
+	 * Flushes the CBMEM console by flushing the
+	 * console buffer from the CPU's data cache.
+	 * In:  x0 - pointer to console_cbmc_t struct
+	 * Out: x0 - 0 for success
+	 * Clobber list: x0, x1, x2, x3, x5
+	 * -----------------------------------------------
+	 */
+func console_cbmc_flush
+	mov	x5, x30
+	ldr	x1, [x0, #CONSOLE_T_CBMC_SIZE]
+	ldr	x0, [x0, #CONSOLE_T_CBMC_BASE]
+	add	x1, x1, #8		/* add size of console header */
+	bl	clean_dcache_range	/* (clobbers x2 and x3) */
+	mov	x0, #0
+	ret	x5
+endfunc console_cbmc_flush
diff --git a/drivers/ti/uart/aarch64/16550_console.S b/drivers/ti/uart/aarch64/16550_console.S
index f9ccd57..b02209d 100644
--- a/drivers/ti/uart/aarch64/16550_console.S
+++ b/drivers/ti/uart/aarch64/16550_console.S
@@ -6,15 +6,24 @@
 
 #include <arch.h>
 #include <asm_macros.S>
+#include <assert_macros.S>
+#include <console_macros.S>
 #include <uart_16550.h>
 
-	.globl	console_core_init
-	.globl	console_core_putc
-	.globl	console_core_getc
-	.globl	console_core_flush
+	/*
+	 * "core" functions are low-level implementations that don't require
+	 * writable memory and are thus safe to call in BL1 crash context.
+	 */
+	.globl console_16550_core_init
+	.globl console_16550_core_putc
+	.globl console_16550_core_getc
+
+	.globl console_16550_putc
+	.globl console_16550_getc
+
 
 	/* -----------------------------------------------
-	 * int console_core_init(unsigned long base_addr,
+	 * int console_16550_core_init(uintptr_t base_addr,
 	 * unsigned int uart_clk, unsigned int baud_rate)
 	 * Function to initialize the console without a
 	 * C Runtime to print debug information. This
@@ -23,11 +32,11 @@
 	 * In: x0 - console base address
 	 *     w1 - Uart clock in Hz
 	 *     w2 - Baud rate
-	 * Out: return 1 on success
+	 * Out: return 1 on success, 0 on error
 	 * Clobber list : x1, x2, x3
 	 * -----------------------------------------------
 	 */
-func console_core_init
+func console_16550_core_init
 	/* Check the input base address */
 	cbz	x0, init_fail
 	/* Check baud rate and uart clock for sanity */
@@ -63,12 +72,57 @@
 	mov	w3, #3
 	str	w3, [x0, #UARTMCR]
 	mov	w0, #1
+	ret
 init_fail:
+	mov	w0, #0
 	ret
-endfunc console_core_init
+endfunc console_16550_core_init
+
+#if MULTI_CONSOLE_API
+	.globl console_16550_register
+
+	/* -----------------------------------------------
+	 * int console_16550_register(console_16550_t *console,
+		uintptr_t base, uint32_t clk, uint32_t baud)
+	 * Function to initialize and register a new 16550
+	 * console. Storage passed in for the console struct
+	 * *must* be persistent (i.e. not from the stack).
+	 * In: x0 - UART register base address
+	 *     w1 - UART clock in Hz
+	 *     w2 - Baud rate
+	 *     x3 - pointer to empty console_16550_t struct
+	 * Out: return 1 on success, 0 on error
+	 * Clobber list : x0, x1, x2, x6, x7, x14
+	 * -----------------------------------------------
+	 */
+func console_16550_register
+	mov	x7, x30
+	mov	x6, x3
+	cbz	x6, register_fail
+	str	x0, [x6, #CONSOLE_T_16550_BASE]
+
+	bl	console_16550_core_init
+	cbz	x0, register_fail
+
+	mov	x0, x6
+	mov	x30, x7
+	finish_console_register 16550
+
+register_fail:
+	ret	x7
+endfunc console_16550_register
+#else
+	.globl console_core_init
+	.globl console_core_putc
+	.globl console_core_getc
+	.globl console_core_flush
+	.equ console_core_init,console_16550_core_init
+	.equ console_core_putc,console_16550_core_putc
+	.equ console_core_getc,console_16550_core_getc
+#endif
 
 	/* --------------------------------------------------------
-	 * int console_core_putc(int c, unsigned int base_addr)
+	 * int console_16550_core_putc(int c, uintptr_t base_addr)
 	 * Function to output a character over the console. It
 	 * returns the character printed on success or -1 on error.
 	 * In : w0 - character to be printed
@@ -77,9 +131,11 @@
 	 * Clobber list : x2
 	 * --------------------------------------------------------
 	 */
-func console_core_putc
-	/* Check the input parameter */
-	cbz	x1, putc_error
+func console_16550_core_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
 
 	/* Prepend '\r' to '\n' */
 	cmp	w0, #0xA
@@ -99,34 +155,75 @@
 	b.ne	2b
 	str	w0, [x1, #UARTTX]
 	ret
-putc_error:
-	mov	w0, #-1
-	ret
-endfunc console_core_putc
+endfunc console_16550_core_putc
+
+	/* --------------------------------------------------------
+	 * int console_16550_putc(int c, console_16550_t *console)
+	 * Function to output a character over the console. It
+	 * returns the character printed on success or -1 on error.
+	 * In : w0 - character to be printed
+	 *      x1 - pointer to console_t structure
+	 * Out : return -1 on error else return character.
+	 * Clobber list : x2
+	 * --------------------------------------------------------
+	 */
+func console_16550_putc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x1, [x1, #CONSOLE_T_16550_BASE]
+	b	console_16550_core_putc
+endfunc console_16550_putc
 
 	/* ---------------------------------------------
-	 * int console_core_getc(void)
+	 * int console_16550_core_getc(uintptr_t base_addr)
 	 * Function to get a character from the console.
 	 * It returns the character grabbed on success
-	 * or -1 on error.
-	 * In : w0 - console base address
-	 * Out : return -1 on error else return character.
+	 * or -1 on if no character is available.
+	 * In :  x0 - console base address
+	 * Out : w0 - character if available, else -1
 	 * Clobber list : x0, x1
 	 * ---------------------------------------------
 	 */
-func console_core_getc
+func console_16550_core_getc
+#if ENABLE_ASSERTIONS
+	cmp	x0, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+
 	/* Check if the receive FIFO is empty */
 1:	ldr	w1, [x0, #UARTLSR]
-	tbz	w1, #UARTLSR_RDR_BIT, 1b
+	tbz	w1, #UARTLSR_RDR_BIT, no_char
 	ldr	w0, [x0, #UARTRX]
 	ret
-getc_error:
-	mov	w0, #-1
+no_char:
+	mov	w0, #ERROR_NO_PENDING_CHAR
 	ret
-endfunc console_core_getc
+endfunc console_16550_core_getc
+
+	/* ---------------------------------------------
+	 * int console_16550_getc(console_16550_t *console)
+	 * Function to get a character from the console.
+	 * It returns the character grabbed on success
+	 * or -1 on if no character is available.
+	 * In :  x0 - pointer to console_t stucture
+	 * Out : w0 - character if available, else -1
+	 * Clobber list : x0, x1
+	 * ---------------------------------------------
+	 */
+func console_16550_getc
+#if ENABLE_ASSERTIONS
+	cmp	x1, #0
+	ASM_ASSERT(ne)
+#endif /* ENABLE_ASSERTIONS */
+	ldr	x0, [x0, #CONSOLE_T_16550_BASE]
+	b	console_16550_core_getc
+endfunc console_16550_getc
 
 	/* ---------------------------------------------
 	 * int console_core_flush(uintptr_t base_addr)
+	 * DEPRECATED: Not used with MULTI_CONSOLE_API!
 	 * Function to force a write of all buffered
 	 * data that hasn't been output.
 	 * In : x0 - console base address
diff --git a/include/common/aarch32/el3_common_macros.S b/include/common/aarch32/el3_common_macros.S
index d654b65..5db8854 100644
--- a/include/common/aarch32/el3_common_macros.S
+++ b/include/common/aarch32/el3_common_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,7 +14,7 @@
 	/*
 	 * Helper macro to initialise EL3 registers we care about.
 	 */
-	.macro el3_arch_init_common _exception_vectors
+	.macro el3_arch_init_common
 	/* ---------------------------------------------------------------------
 	 * SCTLR has already been initialised - read current value before
 	 * modifying.
@@ -34,15 +34,6 @@
 	isb
 
 	/* ---------------------------------------------------------------------
-	 * Set the exception vectors (VBAR/MVBAR).
-	 * ---------------------------------------------------------------------
-	 */
-	ldr	r0, =\_exception_vectors
-	stcopr	r0, VBAR
-	stcopr	r0, MVBAR
-	isb
-
-	/* ---------------------------------------------------------------------
 	 * Initialise SCR, setting all fields rather than relying on the hw.
 	 *
 	 * SCR.SIF: Enabled so that Secure state instruction fetches from
@@ -211,6 +202,15 @@
 	.endif /* _warm_boot_mailbox */
 
 	/* ---------------------------------------------------------------------
+	 * Set the exception vectors (VBAR/MVBAR).
+	 * ---------------------------------------------------------------------
+	 */
+	ldr	r0, =\_exception_vectors
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	isb
+
+	/* ---------------------------------------------------------------------
 	 * It is a cold boot.
 	 * Perform any processor specific actions upon reset e.g. cache, TLB
 	 * invalidations etc.
@@ -218,7 +218,7 @@
 	 */
 	bl	reset_handler
 
-	el3_arch_init_common \_exception_vectors
+	el3_arch_init_common
 
 	.if \_secondary_cold_boot
 		/* -------------------------------------------------------------
diff --git a/include/common/aarch64/console_macros.S b/include/common/aarch64/console_macros.S
new file mode 100644
index 0000000..0ebea2c
--- /dev/null
+++ b/include/common/aarch64/console_macros.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __CONSOLE_MACROS_S__
+#define __CONSOLE_MACROS_S__
+
+#include <console.h>
+
+/*
+ * This macro encapsulates the common setup that has to be done at the end of
+ * a console driver's register function. It will register all of the driver's
+ * callbacks in the console_t structure and initialize the flags field (by
+ * default consoles are enabled for the "boot" and "crash" states, this can be
+ * changed after registration with the console_set_scope() function). It ends
+ * with a tail call that will include return to the caller.
+ * REQUIRES console_t pointer in x0 and a valid return address in x30.
+ */
+	.macro	finish_console_register _driver
+	/*
+	 * Add these weak definitions so we will automatically write a 0 if the
+	 * function doesn't exist. I'd rather use .ifdef but that only works if
+	 * the function was defined (not just declared .global) above this point
+	 * in the file, which we can't guarantee.
+	 */
+	.weak console_\_driver\()_putc
+	.weak console_\_driver\()_getc
+	.weak console_\_driver\()_flush
+
+	/* Don't use adrp on weak funcs! See GNU ld bugzilla issue 22589. */
+	ldr	x1, =console_\_driver\()_putc
+	str	x1, [x0, #CONSOLE_T_PUTC]
+	ldr	x1, =console_\_driver\()_getc
+	str	x1, [x0, #CONSOLE_T_GETC]
+	ldr	x1, =console_\_driver\()_flush
+	str	x1, [x0, #CONSOLE_T_FLUSH]
+	mov	x1, #(CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH)
+	str	x1, [x0, #CONSOLE_T_FLAGS]
+	b	console_register
+	.endm
+
+#endif /* __CONSOLE_MACROS_S__ */
diff --git a/include/drivers/arm/pl011.h b/include/drivers/arm/pl011.h
index cd259c5..06d7543 100644
--- a/include/drivers/arm/pl011.h
+++ b/include/drivers/arm/pl011.h
@@ -7,6 +7,8 @@
 #ifndef __PL011_H__
 #define __PL011_H__
 
+#include <console.h>
+
 /* PL011 Registers */
 #define UARTDR                    0x000
 #define UARTRSR                   0x004
@@ -79,4 +81,26 @@
 
 #endif /* !PL011_GENERIC_UART */
 
+#define CONSOLE_T_PL011_BASE	CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLY__
+
+#include <types.h>
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_pl011_t;
+
+/*
+ * Initialize a new PL011 console instance and register it with the console
+ * framework. The |console| pointer must point to storage that will be valid
+ * for the lifetime of the console, such as a global or static local variable.
+ * Its contents will be reinitialized from scratch.
+ */
+int console_pl011_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			   console_pl011_t *console);
+
+#endif /*__ASSEMBLY__*/
+
 #endif	/* __PL011_H__ */
diff --git a/include/drivers/cadence/cdns_uart.h b/include/drivers/cadence/cdns_uart.h
index 3aadde3..7ab6df0 100644
--- a/include/drivers/cadence/cdns_uart.h
+++ b/include/drivers/cadence/cdns_uart.h
@@ -7,6 +7,8 @@
 #ifndef __CADENCE_UART_H__
 #define __CADENCE_UART_H__
 
+#include <console.h>
+
 /* This is very minimalistic and will only work in QEMU.  */
 
 /* CADENCE Registers */
@@ -23,4 +25,26 @@
 #define R_UART_TX	0x30
 #define R_UART_RX	0x30
 
+#define CONSOLE_T_CDNS_BASE	CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLY__
+
+#include <types.h>
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_cdns_t;
+
+/*
+ * Initialize a new Cadence console instance and register it with the console
+ * framework. The |console| pointer must point to storage that will be valid
+ * for the lifetime of the console, such as a global or static local variable.
+ * Its contents will be reinitialized from scratch.
+ */
+int console_cdns_register(uint64_t baseaddr, uint32_t clock, uint32_t baud,
+			  console_cdns_t *console);
+
+#endif /*__ASSEMBLY__*/
+
 #endif
diff --git a/include/drivers/console.h b/include/drivers/console.h
index da5cb8f..0629f57 100644
--- a/include/drivers/console.h
+++ b/include/drivers/console.h
@@ -7,14 +7,69 @@
 #ifndef __CONSOLE_H__
 #define __CONSOLE_H__
 
-#include <stdint.h>
+#include <utils_def.h>
 
-int console_init(uintptr_t base_addr,
-		unsigned int uart_clk, unsigned int baud_rate);
-void console_uninit(void);
+#define CONSOLE_T_NEXT			(U(0) * REGSZ)
+#define CONSOLE_T_FLAGS			(U(1) * REGSZ)
+#define CONSOLE_T_PUTC			(U(2) * REGSZ)
+#define CONSOLE_T_GETC			(U(3) * REGSZ)
+#define CONSOLE_T_FLUSH			(U(4) * REGSZ)
+#define CONSOLE_T_DRVDATA		(U(5) * REGSZ)
+
+#define CONSOLE_FLAG_BOOT		BIT(0)
+#define CONSOLE_FLAG_RUNTIME		BIT(1)
+#define CONSOLE_FLAG_CRASH		BIT(2)
+/* Bits 3 to 7 reserved for additional scopes in future expansion. */
+#define CONSOLE_FLAG_SCOPE_MASK		((U(1) << 8) - 1)
+/* Bits 8 to 31 reserved for non-scope use in future expansion. */
+
+/* Returned by getc callbacks when receive FIFO is empty. */
+#define ERROR_NO_PENDING_CHAR		(-1)
+/* Returned by console_xxx() if no registered console implements xxx. */
+#define ERROR_NO_VALID_CONSOLE		(-128)
+
+#ifndef __ASSEMBLY__
+
+#include <types.h>
+
+typedef struct console {
+	struct console *next;
+	u_register_t flags;
+	int (*putc)(int character, struct console *console);
+	int (*getc)(struct console *console);
+	int (*flush)(struct console *console);
+	/* Additional private driver data may follow here. */
+} console_t;
+#include <console_assertions.h>	/* offset macro assertions for console_t */
+
+/*
+ * NOTE: There is no publicly accessible console_register() function. Consoles
+ * are registered by directly calling the register function of a specific
+ * implementation, e.g. console_16550_register() from <uart_16550.h>. Consoles
+ * registered that way can be unregistered/reconfigured with below functions.
+ */
+/* Remove a single console_t instance from the console list. */
+int console_unregister(console_t *console);
+/* Set scope mask of a console that determines in what states it is active. */
+void console_set_scope(console_t *console, unsigned int scope);
+
+/* Switch to a new global console state (CONSOLE_FLAG_BOOT/RUNTIME/CRASH). */
+void console_switch_state(unsigned int new_state);
+/* Output a character on all consoles registered for the current state. */
 int console_putc(int c);
+/* Read a character (blocking) from any console registered for current state. */
 int console_getc(void);
+/* Flush all consoles registered for the current state. */
 int console_flush(void);
 
+#if !MULTI_CONSOLE_API
+/* DEPRECATED on AArch64 -- use console_<driver>_register() instead! */
+int console_init(uintptr_t base_addr,
+		 unsigned int uart_clk, unsigned int baud_rate) __deprecated;
+void console_uninit(void) __deprecated;
+#endif
+
+#endif /* __ASSEMBLY__ */
+
 #endif /* __CONSOLE_H__ */
 
diff --git a/include/drivers/console_assertions.h b/include/drivers/console_assertions.h
new file mode 100644
index 0000000..cedce86
--- /dev/null
+++ b/include/drivers/console_assertions.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CONSOLE_ASSERTIONS_H__
+#define __CONSOLE_ASSERTIONS_H__
+
+#include <cassert.h>
+
+/*
+ * This file contains some separate assertions about console_t, moved here to
+ * keep them out of the way. Should only be included from <console.h>.
+ */
+CASSERT(CONSOLE_T_NEXT == __builtin_offsetof(console_t, next),
+	assert_console_t_next_offset_mismatch);
+CASSERT(CONSOLE_T_FLAGS == __builtin_offsetof(console_t, flags),
+	assert_console_t_flags_offset_mismatch);
+CASSERT(CONSOLE_T_PUTC == __builtin_offsetof(console_t, putc),
+	assert_console_t_putc_offset_mismatch);
+CASSERT(CONSOLE_T_GETC == __builtin_offsetof(console_t, getc),
+	assert_console_t_getc_offset_mismatch);
+CASSERT(CONSOLE_T_FLUSH == __builtin_offsetof(console_t, flush),
+	assert_console_t_flush_offset_mismatch);
+CASSERT(CONSOLE_T_DRVDATA == sizeof(console_t),
+	assert_console_t_drvdata_offset_mismatch);
+
+#endif /* __CONSOLE_ASSERTIONS_H__ */
+
diff --git a/include/drivers/coreboot/cbmem_console.h b/include/drivers/coreboot/cbmem_console.h
new file mode 100644
index 0000000..4fca36f
--- /dev/null
+++ b/include/drivers/coreboot/cbmem_console.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __CBMEM_CONSOLE_H__
+#define __CBMEM_CONSOLE_H__
+
+#include <console.h>
+
+#define CONSOLE_T_CBMC_BASE	CONSOLE_T_DRVDATA
+#define CONSOLE_T_CBMC_SIZE	(CONSOLE_T_DRVDATA + REGSZ)
+
+#ifndef __ASSEMBLER__
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+	uint32_t size;
+} console_cbmc_t;
+
+int console_cbmc_register(uintptr_t base, console_cbmc_t *console);
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __CBMEM_CONSOLE_H__ */
diff --git a/include/drivers/ti/uart/uart_16550.h b/include/drivers/ti/uart/uart_16550.h
index f258d45..9eba41a 100644
--- a/include/drivers/ti/uart/uart_16550.h
+++ b/include/drivers/ti/uart/uart_16550.h
@@ -7,6 +7,8 @@
 #ifndef __UART_16550_H__
 #define __UART_16550_H__
 
+#include <console.h>
+
 /* UART16550 Registers */
 #define UARTTX			0x0
 #define UARTRX			0x0
@@ -67,4 +69,26 @@
 #define UARTLSR_RDR_BIT		(0)		/* Rx Data Ready Bit */
 #define UARTLSR_RDR		(1 << UARTLSR_RDR_BIT)	/* Rx Data Ready */
 
+#define CONSOLE_T_16550_BASE	CONSOLE_T_DRVDATA
+
+#ifndef __ASSEMBLY__
+
+#include <types.h>
+
+typedef struct {
+	console_t console;
+	uintptr_t base;
+} console_16550_t;
+
+/*
+ * Initialize a new 16550 console instance and register it with the console
+ * framework. The |console| pointer must point to storage that will be valid
+ * for the lifetime of the console, such as a global or static local variable.
+ * Its contents will be reinitialized from scratch.
+ */
+int console_16550_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
+			   console_16550_t *console);
+
+#endif /*__ASSEMBLY__*/
+
 #endif	/* __UART_16550_H__ */
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
index 4d2a5fc..134d534 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -426,6 +426,8 @@
 #define TLBIMVAA	p15, 0, c8, c7, 3
 #define TLBIMVAAIS	p15, 0, c8, c3, 3
 #define BPIALLIS	p15, 0, c7, c1, 6
+#define BPIALL		p15, 0, c7, c5, 6
+#define ICIALLU		p15, 0, c7, c5, 0
 #define HSCTLR		p15, 4, c1, c0, 0
 #define HCR		p15, 4, c1, c1, 0
 #define HCPTR		p15, 4, c1, c1, 2
diff --git a/include/lib/aarch32/smcc_helpers.h b/include/lib/aarch32/smcc_helpers.h
index 53f1aa4..ed3b722 100644
--- a/include/lib/aarch32/smcc_helpers.h
+++ b/include/lib/aarch32/smcc_helpers.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -22,7 +22,7 @@
 #define SMC_CTX_LR_MON		0x80
 #define SMC_CTX_SCR		0x84
 #define SMC_CTX_PMCR		0x88
-#define SMC_CTX_SIZE		0x8C
+#define SMC_CTX_SIZE		0x90
 
 #ifndef __ASSEMBLY__
 #include <cassert.h>
@@ -75,7 +75,13 @@
 	u_register_t lr_mon;
 	u_register_t scr;
 	u_register_t pmcr;
-} smc_ctx_t;
+	/*
+	 * The workaround for CVE-2017-5715 requires storing information in
+	 * the bottom 3 bits of the stack pointer.  Add a padding field to
+	 * force the size of the struct to be a multiple of 8.
+	 */
+	u_register_t pad;
+} smc_ctx_t __aligned(8);
 
 /*
  * Compile time assertions related to the 'smc_context' structure to
@@ -99,6 +105,7 @@
 CASSERT(SMC_CTX_SPSR_MON == __builtin_offsetof(smc_ctx_t, spsr_mon), \
 	assert_smc_ctx_spsr_mon_offset_mismatch);
 
+CASSERT((sizeof(smc_ctx_t) & 0x7) == 0, assert_smc_ctx_not_aligned);
 CASSERT(SMC_CTX_SIZE == sizeof(smc_ctx_t), assert_smc_ctx_size_mismatch);
 
 /* Convenience macros to return from SMC handler */
diff --git a/include/lib/coreboot.h b/include/lib/coreboot.h
new file mode 100644
index 0000000..4b1f200
--- /dev/null
+++ b/include/lib/coreboot.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __COREBOOT_H__
+#define __COREBOOT_H__
+
+#include <types.h>
+
+typedef struct {
+	uint32_t type;			/* always 2 (memory-mapped) on ARM */
+	uint32_t baseaddr;
+	uint32_t baud;
+	uint32_t regwidth;		/* in bytes, i.e. usually 4 */
+	uint32_t input_hertz;
+	uint32_t uart_pci_addr;		/* unused on current ARM systems */
+} coreboot_serial_t;
+extern coreboot_serial_t coreboot_serial;
+
+void coreboot_table_setup(void *base);
+
+#endif /* __COREBOOT_H__ */
diff --git a/include/lib/cpus/aarch32/cortex_a15.h b/include/lib/cpus/aarch32/cortex_a15.h
index 905c139..0f01a43 100644
--- a/include/lib/cpus/aarch32/cortex_a15.h
+++ b/include/lib/cpus/aarch32/cortex_a15.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,6 +15,7 @@
 /*******************************************************************************
  * CPU Auxiliary Control register specific definitions.
  ******************************************************************************/
+#define CORTEX_A15_ACTLR_INV_BTB_BIT	(1 << 0)
 #define CORTEX_A15_ACTLR_SMP_BIT	(1 << 6)
 
 #endif /* __CORTEX_A15_H__ */
diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h
index 185a1c1..bda3b07 100644
--- a/include/lib/utils_def.h
+++ b/include/lib/utils_def.h
@@ -16,7 +16,7 @@
 
 #define SIZE_FROM_LOG2_WORDS(n)		(4 << (n))
 
-#define BIT(nr)				(1ULL << (nr))
+#define BIT(nr)				(ULL(1) << (nr))
 
 /*
  * This variant of div_round_up can be used in macro definition but should not
@@ -84,6 +84,13 @@
 # define ULL(_x)	(_x##ull)
 #endif
 
+/* Register size of the current architecture. */
+#ifdef AARCH32
+#define REGSZ		U(4)
+#else
+#define REGSZ		U(8)
+#endif
+
 /*
  * Test for the current architecture version to be at least the version
  * expected.
diff --git a/include/services/secure_partition.h b/include/services/secure_partition.h
index 334f761..93df2a1 100644
--- a/include/services/secure_partition.h
+++ b/include/services/secure_partition.h
@@ -35,27 +35,27 @@
  * partition.
  */
 typedef struct secure_partition_mp_info {
-	u_register_t		mpidr;
-	unsigned int		linear_id;
-	unsigned int		flags;
+	uint64_t		mpidr;
+	uint32_t		linear_id;
+	uint32_t		flags;
 } secure_partition_mp_info_t;
 
 typedef struct secure_partition_boot_info {
 	param_header_t		h;
-	uintptr_t		sp_mem_base;
-	uintptr_t		sp_mem_limit;
-	uintptr_t		sp_image_base;
-	uintptr_t		sp_stack_base;
-	uintptr_t		sp_heap_base;
-	uintptr_t		sp_ns_comm_buf_base;
-	uintptr_t		sp_shared_buf_base;
-	size_t			sp_image_size;
-	size_t			sp_pcpu_stack_size;
-	size_t			sp_heap_size;
-	size_t			sp_ns_comm_buf_size;
-	size_t			sp_shared_buf_size;
-	unsigned int		num_sp_mem_regions;
-	unsigned int		num_cpus;
+	uint64_t		sp_mem_base;
+	uint64_t		sp_mem_limit;
+	uint64_t		sp_image_base;
+	uint64_t		sp_stack_base;
+	uint64_t		sp_heap_base;
+	uint64_t		sp_ns_comm_buf_base;
+	uint64_t		sp_shared_buf_base;
+	uint64_t		sp_image_size;
+	uint64_t		sp_pcpu_stack_size;
+	uint64_t		sp_heap_size;
+	uint64_t		sp_ns_comm_buf_size;
+	uint64_t		sp_shared_buf_size;
+	uint32_t		num_sp_mem_regions;
+	uint32_t		num_cpus;
 	secure_partition_mp_info_t	*mp_info;
 } secure_partition_boot_info_t;
 
diff --git a/lib/coreboot/coreboot.mk b/lib/coreboot/coreboot.mk
new file mode 100644
index 0000000..bbaa332
--- /dev/null
+++ b/lib/coreboot/coreboot.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+COREBOOT := 0
+$(eval $(call assert_boolean,COREBOOT))
+$(eval $(call add_define,COREBOOT))
+
+ifeq (${COREBOOT},1)
+
+ifneq (${ARCH},aarch64)
+$(error "coreboot only supports Trusted Firmware on AArch64.")
+endif
+
+BL31_SOURCES	+=	$(addprefix lib/coreboot/,	\
+			coreboot_table.c)
+
+BL31_SOURCES	+=	drivers/coreboot/cbmem_console/${ARCH}/cbmem_console.S
+
+INCLUDES	+=	-Iinclude/drivers/coreboot
+
+endif	# COREBOOT
diff --git a/lib/coreboot/coreboot_table.c b/lib/coreboot/coreboot_table.c
new file mode 100644
index 0000000..64f8879
--- /dev/null
+++ b/lib/coreboot/coreboot_table.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cbmem_console.h>
+#include <coreboot.h>
+#include <debug.h>
+#include <mmio.h>
+#include <string.h>
+#include <xlat_tables_v2.h>
+
+/*
+ * Structures describing coreboot's in-memory descriptor tables. See
+ * <coreboot>/src/commonlib/include/commonlib/coreboot_tables.h for
+ * canonical implementation.
+ */
+
+typedef struct {
+	char signature[4];
+	uint32_t header_bytes;
+	uint32_t header_checksum;
+	uint32_t table_bytes;
+	uint32_t table_checksum;
+	uint32_t table_entries;
+} cb_header_t;
+
+typedef enum {
+	CB_TAG_SERIAL = 0xf,
+	CB_TAG_CBMEM_CONSOLE = 0x17,
+} cb_tag_t;
+
+typedef struct {
+	uint32_t tag;
+	uint32_t size;
+	union {
+		coreboot_serial_t serial;
+		uint64_t uint64;
+	};
+} cb_entry_t;
+
+coreboot_serial_t coreboot_serial;
+
+/*
+ * The coreboot table is parsed before the MMU is enabled (i.e. with strongly
+ * ordered memory), so we cannot make unaligned accesses. The table entries
+ * immediately follow one another without padding, so nothing after the header
+ * is guaranteed to be naturally aligned. Therefore, we need to define safety
+ * functions that can read unaligned integers.
+ */
+static uint32_t read_le32(uint32_t *p)
+{
+	uintptr_t addr = (uintptr_t)p;
+	return mmio_read_8(addr)		|
+	       mmio_read_8(addr + 1) << 8	|
+	       mmio_read_8(addr + 2) << 16	|
+	       mmio_read_8(addr + 3) << 24;
+}
+static uint64_t read_le64(uint64_t *p)
+{
+	return read_le32((void *)p) | (uint64_t)read_le32((void *)p + 4) << 32;
+}
+
+static void expand_and_mmap(uintptr_t baseaddr, size_t size)
+{
+	uintptr_t pageaddr = round_down(baseaddr, PAGE_SIZE);
+	size_t expanded = round_up(baseaddr - pageaddr + size, PAGE_SIZE);
+	mmap_add_region(pageaddr, pageaddr, expanded,
+			MT_MEMORY | MT_RW | MT_NS | MT_EXECUTE_NEVER);
+}
+
+static void setup_cbmem_console(uintptr_t baseaddr)
+{
+	static console_cbmc_t console;
+	assert(!console.base);		/* should only have one CBMEM console */
+
+	/* CBMEM console structure stores its size in first header field. */
+	uint32_t size = *(uint32_t *)baseaddr;
+	expand_and_mmap(baseaddr, size);
+	console_cbmc_register(baseaddr, &console);
+	console_set_scope(&console.console, CONSOLE_FLAG_BOOT |
+					    CONSOLE_FLAG_RUNTIME |
+					    CONSOLE_FLAG_CRASH);
+}
+
+void coreboot_table_setup(void *base)
+{
+	cb_header_t *header = base;
+	void *ptr;
+	int i;
+
+	if (strncmp(header->signature, "LBIO", 4)) {
+		ERROR("coreboot table signature corrupt!\n");
+		return;
+	}
+
+	ptr = base + header->header_bytes;
+	for (i = 0; i < header->table_entries; i++) {
+		cb_entry_t *entry = ptr;
+
+		if (ptr - base >= header->header_bytes + header->table_bytes) {
+			ERROR("coreboot table exceeds its bounds!\n");
+			break;
+		}
+
+		switch (read_le32(&entry->tag)) {
+		case CB_TAG_SERIAL:
+			memcpy(&coreboot_serial, &entry->serial,
+			       sizeof(coreboot_serial));
+			break;
+		case CB_TAG_CBMEM_CONSOLE:
+			setup_cbmem_console(read_le64(&entry->uint64));
+			break;
+		default:
+			/* There are many tags TF doesn't need to care about. */
+			break;
+		}
+
+		ptr += read_le32(&entry->size);
+	}
+}
diff --git a/lib/cpus/aarch32/cortex_a15.S b/lib/cpus/aarch32/cortex_a15.S
index 0d5a116..b6c61ab 100644
--- a/lib/cpus/aarch32/cortex_a15.S
+++ b/lib/cpus/aarch32/cortex_a15.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -41,7 +41,46 @@
 	bx	lr
 endfunc cortex_a15_enable_smp
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A15. Must follow AAPCS.
+ */
+func cortex_a15_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a15, cve_2017_5715
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a15_errata_report
+#endif
+
 func cortex_a15_reset_func
+#if IMAGE_BL32 && WORKAROUND_CVE_2017_5715
+	ldcopr	r0, ACTLR
+	orr	r0, #CORTEX_A15_ACTLR_INV_BTB_BIT
+	stcopr	r0, ACTLR
+	ldr	r0, =workaround_icache_inv_runtime_exceptions
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	/* isb will be applied in the course of the reset func */
+#endif
 	b	cortex_a15_enable_smp
 endfunc cortex_a15_reset_func
 
diff --git a/lib/cpus/aarch32/cortex_a17.S b/lib/cpus/aarch32/cortex_a17.S
index 316d4f0..b84c126 100644
--- a/lib/cpus/aarch32/cortex_a17.S
+++ b/lib/cpus/aarch32/cortex_a17.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -35,7 +35,43 @@
 	bx	lr
 endfunc cortex_a17_enable_smp
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A17. Must follow AAPCS.
+ */
+func cortex_a17_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a17, cve_2017_5715
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a17_errata_report
+#endif
+
 func cortex_a17_reset_func
+#if IMAGE_BL32 && WORKAROUND_CVE_2017_5715
+	ldr	r0, =workaround_bpiall_runtime_exceptions
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	/* isb will be applied in the course of the reset func */
+#endif
 	b	cortex_a17_enable_smp
 endfunc cortex_a17_reset_func
 
diff --git a/lib/cpus/aarch32/cortex_a57.S b/lib/cpus/aarch32/cortex_a57.S
index 64a6d67..f446bff 100644
--- a/lib/cpus/aarch32/cortex_a57.S
+++ b/lib/cpus/aarch32/cortex_a57.S
@@ -332,6 +332,11 @@
 	b	cpu_rev_var_ls
 endfunc check_errata_859972
 
+func check_errata_cve_2017_5715
+	mov	r0, #ERRATA_MISSING
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
 	/* -------------------------------------------------
 	 * The CPU Ops reset function for Cortex-A57.
 	 * Shall clobber: r0-r6
@@ -519,6 +524,7 @@
 	report_errata ERRATA_A57_829520, cortex_a57, 829520
 	report_errata ERRATA_A57_833471, cortex_a57, 833471
 	report_errata ERRATA_A57_859972, cortex_a57, 859972
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a57, cve_2017_5715
 
 	pop	{r12, lr}
 	bx	lr
diff --git a/lib/cpus/aarch32/cortex_a72.S b/lib/cpus/aarch32/cortex_a72.S
index 35b9bc2..56e91f5 100644
--- a/lib/cpus/aarch32/cortex_a72.S
+++ b/lib/cpus/aarch32/cortex_a72.S
@@ -87,6 +87,10 @@
 	b		cpu_rev_var_ls
 endfunc check_errata_859971
 
+func check_errata_cve_2017_5715
+	mov	r0, #ERRATA_MISSING
+	bx	lr
+endfunc check_errata_cve_2017_5715
 
 	/* -------------------------------------------------
 	 * The CPU Ops reset function for Cortex-A72.
@@ -236,6 +240,7 @@
 	 * checking functions of each errata.
 	 */
 	report_errata ERRATA_A72_859971, cortex_a72, 859971
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a72, cve_2017_5715
 
 	pop	{r12, lr}
 	bx	lr
diff --git a/lib/cpus/aarch32/cortex_a9.S b/lib/cpus/aarch32/cortex_a9.S
index 4f30f84..1fb10b2 100644
--- a/lib/cpus/aarch32/cortex_a9.S
+++ b/lib/cpus/aarch32/cortex_a9.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -35,7 +35,43 @@
 	bx	lr
 endfunc cortex_a9_enable_smp
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	r0, #ERRATA_APPLIES
+#else
+	mov	r0, #ERRATA_MISSING
+#endif
+	bx	lr
+endfunc check_errata_cve_2017_5715
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A9. Must follow AAPCS.
+ */
+func cortex_a9_errata_report
+	push	{r12, lr}
+
+	bl	cpu_get_rev_var
+	mov	r4, r0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a9, cve_2017_5715
+
+	pop	{r12, lr}
+	bx	lr
+endfunc cortex_a9_errata_report
+#endif
+
 func cortex_a9_reset_func
+#if IMAGE_BL32 && WORKAROUND_CVE_2017_5715
+	ldr	r0, =workaround_bpiall_runtime_exceptions
+	stcopr	r0, VBAR
+	stcopr	r0, MVBAR
+	/* isb will be applied in the course of the reset func */
+#endif
 	b	cortex_a9_enable_smp
 endfunc cortex_a9_reset_func
 
diff --git a/lib/cpus/aarch64/cortex_a57.S b/lib/cpus/aarch64/cortex_a57.S
index 683be47..c82ebfc 100644
--- a/lib/cpus/aarch64/cortex_a57.S
+++ b/lib/cpus/aarch64/cortex_a57.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -328,6 +328,15 @@
 	b	cpu_rev_var_ls
 endfunc check_errata_859972
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2017_5715
+
 	/* -------------------------------------------------
 	 * The CPU Ops reset function for Cortex-A57.
 	 * Shall clobber: x0-x19
@@ -518,7 +527,7 @@
 	report_errata ERRATA_A57_829520, cortex_a57, 829520
 	report_errata ERRATA_A57_833471, cortex_a57, 833471
 	report_errata ERRATA_A57_859972, cortex_a57, 859972
-
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a57, cve_2017_5715
 
 	ldp	x8, x30, [sp], #16
 	ret
diff --git a/lib/cpus/aarch64/cortex_a72.S b/lib/cpus/aarch64/cortex_a72.S
index 93821b7..9633aa8 100644
--- a/lib/cpus/aarch64/cortex_a72.S
+++ b/lib/cpus/aarch64/cortex_a72.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -97,6 +97,15 @@
 	b	cpu_rev_var_ls
 endfunc check_errata_859971
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2017_5715
+
 	/* -------------------------------------------------
 	 * The CPU Ops reset function for Cortex-A72.
 	 * -------------------------------------------------
@@ -249,6 +258,7 @@
 	 * checking functions of each errata.
 	 */
 	report_errata ERRATA_A72_859971, cortex_a72, 859971
+	report_errata WORKAROUND_CVE_2017_5715, cortex_a72, cve_2017_5715
 
 	ldp	x8, x30, [sp], #16
 	ret
diff --git a/lib/cpus/aarch64/cortex_a73.S b/lib/cpus/aarch64/cortex_a73.S
index c43f07e..11680a0 100644
--- a/lib/cpus/aarch64/cortex_a73.S
+++ b/lib/cpus/aarch64/cortex_a73.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -114,6 +114,36 @@
 	b	cortex_a73_disable_smp
 endfunc cortex_a73_cluster_pwr_dwn
 
+func check_errata_cve_2017_5715
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+endfunc check_errata_cve_2017_5715
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A75. Must follow AAPCS.
+ */
+func cortex_a73_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 WORKAROUND_CVE_2017_5715, cortex_a73, cve_2017_5715
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a73_errata_report
+#endif
+
 	/* ---------------------------------------------
 	 * This function provides cortex_a73 specific
 	 * register information for crash reporting.
diff --git a/lib/cpus/aarch64/cortex_a75.S b/lib/cpus/aarch64/cortex_a75.S
index e66ad06..946f988 100644
--- a/lib/cpus/aarch64/cortex_a75.S
+++ b/lib/cpus/aarch64/cortex_a75.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -151,6 +151,27 @@
 	ret
 endfunc cortex_a75_reset_func
 
+func check_errata_cve_2017_5715
+	mrs	x0, id_aa64pfr0_el1
+	ubfx	x0, x0, #ID_AA64PFR0_CSV2_SHIFT, #ID_AA64PFR0_CSV2_LENGTH
+	/*
+	 * If the field equals to 1 then branch targets trained in one
+	 * context cannot affect speculative execution in a different context.
+	 */
+	cmp	x0, #1
+	beq	1f
+
+#if WORKAROUND_CVE_2017_5715
+	mov	x0, #ERRATA_APPLIES
+#else
+	mov	x0, #ERRATA_MISSING
+#endif
+	ret
+1:
+	mov	x0, #ERRATA_NOT_APPLIES
+	ret
+endfunc check_errata_cve_2017_5715
+
 	/* ---------------------------------------------
 	 * HW will do the cache maintenance while powering down
 	 * ---------------------------------------------
@@ -167,6 +188,27 @@
 	ret
 endfunc cortex_a75_core_pwr_dwn
 
+#if REPORT_ERRATA
+/*
+ * Errata printing function for Cortex A75. Must follow AAPCS.
+ */
+func cortex_a75_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 WORKAROUND_CVE_2017_5715, cortex_a75, cve_2017_5715
+
+	ldp	x8, x30, [sp], #16
+	ret
+endfunc cortex_a75_errata_report
+#endif
+
 	/* ---------------------------------------------
 	 * This function provides cortex_a75 specific
 	 * register information for crash reporting.
diff --git a/lib/cpus/errata_report.c b/lib/cpus/errata_report.c
index 182679d..c679336 100644
--- a/lib/cpus/errata_report.c
+++ b/lib/cpus/errata_report.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -27,7 +27,7 @@
 #endif
 
 /* Errata format: BL stage, CPU, errata ID, message */
-#define ERRATA_FORMAT	"%s: %s: errata workaround for %s was %s\n"
+#define ERRATA_FORMAT	"%s: %s: CPU workaround for %s was %s\n"
 
 /*
  * Returns whether errata needs to be reported. Passed arguments are private to
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 643890f..a80a491 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -34,6 +34,10 @@
 # The platform Makefile is free to override this value.
 COLD_BOOT_SINGLE_CPU		:= 0
 
+# Flag to compile in coreboot support code. Exclude by default. The coreboot
+# Makefile system will set this when compiling TF as part of a coreboot image.
+COREBOOT			:= 0
+
 # For Chain of Trust
 CREATE_KEYS			:= 1
 
@@ -94,6 +98,10 @@
 # Flag to enable new version of image loading
 LOAD_IMAGE_V2			:= 0
 
+# Use the new console API that allows registering more than one console instance
+# at once. Use = instead of := to dynamically default to ERROR_DEPRECATED.
+MULTI_CONSOLE_API		= $(ERROR_DEPRECATED)
+
 # NS timer register save and restore
 NS_TIMER_SWITCH			:= 0
 
diff --git a/plat/common/aarch64/plat_common.c b/plat/common/aarch64/plat_common.c
index a87e7c6..cfc0c4f 100644
--- a/plat/common/aarch64/plat_common.c
+++ b/plat/common/aarch64/plat_common.c
@@ -39,11 +39,11 @@
 
 void bl31_plat_runtime_setup(void)
 {
-	/*
-	 * Finish the use of console driver in BL31 so that any runtime logs
-	 * from BL31 will be suppressed.
-	 */
+#if MULTI_CONSOLE_API
+	console_switch_state(CONSOLE_FLAG_RUNTIME);
+#else
 	console_uninit();
+#endif
 }
 
 #if !ENABLE_PLAT_COMPAT
diff --git a/plat/common/aarch64/platform_helpers.S b/plat/common/aarch64/platform_helpers.S
index 797a936..8526752 100644
--- a/plat/common/aarch64/platform_helpers.S
+++ b/plat/common/aarch64/platform_helpers.S
@@ -6,6 +6,7 @@
 
 #include <arch.h>
 #include <asm_macros.S>
+#include <console.h>
 #include <platform_def.h>
 
 	.weak	plat_report_exception
@@ -56,33 +57,78 @@
 	ret
 endfunc plat_report_exception
 
+#if MULTI_CONSOLE_API
 	/* -----------------------------------------------------
-	 * Placeholder function which should be redefined by
-	 * each platform.
+	 * int plat_crash_console_init(void)
+	 * Use normal console by default. Switch it to crash
+	 * mode so serial consoles become active again.
+	 * NOTE: This default implementation will only work for
+	 * crashes that occur after a normal console (marked
+	 * valid for the crash state) has been registered with
+	 * the console framework. To debug crashes that occur
+	 * earlier, the platform has to override these functions
+	 * with an implementation that initializes a console
+	 * driver with hardcoded parameters. See
+	 * docs/porting-guide.rst for more information.
 	 * -----------------------------------------------------
 	 */
 func plat_crash_console_init
+#if defined(IMAGE_BL1)
+	/*
+	 * BL1 code can possibly crash so early that the data segment is not yet
+	 * accessible. Don't risk undefined behavior by trying to run the normal
+	 * console framework. Platforms that want to debug BL1 will need to
+	 * override this with custom functions that can run from registers only.
+	 */
 	mov	x0, #0
 	ret
+#else	/* IMAGE_BL1 */
+	mov	x3, x30
+	mov	x0, #CONSOLE_FLAG_CRASH
+	bl	console_switch_state
+	mov	x0, #1
+	ret	x3
+#endif
 endfunc plat_crash_console_init
 
 	/* -----------------------------------------------------
-	 * Placeholder function which should be redefined by
-	 * each platform.
+	 * void plat_crash_console_putc(int character)
+	 * Output through the normal console by default.
 	 * -----------------------------------------------------
 	 */
 func plat_crash_console_putc
-	ret
+	b	console_putc
 endfunc plat_crash_console_putc
 
 	/* -----------------------------------------------------
-	 * Placeholder function which should be redefined by
-	 * each platform.
+	 * void plat_crash_console_flush(void)
+	 * Flush normal console by default.
+	 * -----------------------------------------------------
+	 */
+func plat_crash_console_flush
+	b	console_flush
+endfunc plat_crash_console_flush
+
+#else	/* MULTI_CONSOLE_API */
+
+	/* -----------------------------------------------------
+	 * In the old API these are all no-op stubs that need to
+	 * be overridden by the platform to be useful.
 	 * -----------------------------------------------------
 	 */
+func plat_crash_console_init
+	mov	x0, #0
+	ret
+endfunc plat_crash_console_init
+
+func plat_crash_console_putc
+	ret
+endfunc plat_crash_console_putc
+
 func plat_crash_console_flush
 	ret
 endfunc plat_crash_console_flush
+#endif
 
 	/* -----------------------------------------------------
 	 * Placeholder function which should be redefined by
diff --git a/plat/hisilicon/hikey960/hikey960_bl31_setup.c b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
index f685f9c..f0d15a3 100644
--- a/plat/hisilicon/hikey960/hikey960_bl31_setup.c
+++ b/plat/hisilicon/hikey960/hikey960_bl31_setup.c
@@ -16,6 +16,8 @@
 #include <gicv2.h>
 #include <hi3660.h>
 #include <hisi_ipc.h>
+#include <interrupt_mgmt.h>
+#include <platform.h>
 #include <platform_def.h>
 
 #include "hikey960_def.h"
@@ -167,6 +169,37 @@
 	hisi_ipc_init();
 }
 
+#ifdef SPD_none
+static uint64_t hikey_debug_fiq_handler(uint32_t id,
+					uint32_t flags,
+					void *handle,
+					void *cookie)
+{
+	int intr, intr_raw;
+
+	/* Acknowledge interrupt */
+	intr_raw = plat_ic_acknowledge_interrupt();
+	intr = plat_ic_get_interrupt_id(intr_raw);
+	ERROR("Invalid interrupt: intr=%d\n", intr);
+	console_flush();
+	panic();
+
+	return 0;
+}
+#endif
+
 void bl31_plat_runtime_setup(void)
 {
+#ifdef SPD_none
+	uint32_t flags;
+	int32_t rc;
+
+	flags = 0;
+	set_interrupt_rm_flag(flags, NON_SECURE);
+	rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+					     hikey_debug_fiq_handler,
+					     flags);
+	if (rc != 0)
+		panic();
+#endif
 }
diff --git a/plat/hisilicon/poplar/bl1_plat_setup.c b/plat/hisilicon/poplar/bl1_plat_setup.c
index c65e29e..7d6f10c 100644
--- a/plat/hisilicon/poplar/bl1_plat_setup.c
+++ b/plat/hisilicon/poplar/bl1_plat_setup.c
@@ -9,6 +9,8 @@
 #include <bl_common.h>
 #include <console.h>
 #include <debug.h>
+#include <dw_mmc.h>
+#include <emmc.h>
 #include <errno.h>
 #include <generic_delay_timer.h>
 #include <mmio.h>
@@ -71,6 +73,9 @@
 void bl1_platform_setup(void)
 {
 	int i;
+#if !POPLAR_RECOVERY
+	dw_mmc_params_t params = EMMC_INIT_PARAMS(POPLAR_EMMC_DESC_BASE);
+#endif
 
 	generic_delay_timer_init();
 
@@ -78,6 +83,12 @@
 	for (i = 0; i < GPIO_MAX; i++)
 		pl061_gpio_register(GPIO_BASE(i), i);
 
+#if !POPLAR_RECOVERY
+	/* SoC-specific emmc register are initialized/configured by bootrom */
+	INFO("BL1: initializing emmc\n");
+	dw_mmc_init(&params);
+#endif
+
 	plat_io_setup();
 }
 
diff --git a/plat/hisilicon/poplar/bl2_plat_setup.c b/plat/hisilicon/poplar/bl2_plat_setup.c
index db507c3..7edfab7 100644
--- a/plat/hisilicon/poplar/bl2_plat_setup.c
+++ b/plat/hisilicon/poplar/bl2_plat_setup.c
@@ -9,6 +9,8 @@
 #include <bl_common.h>
 #include <console.h>
 #include <debug.h>
+#include <dw_mmc.h>
+#include <emmc.h>
 #include <errno.h>
 #include <generic_delay_timer.h>
 #include <mmio.h>
@@ -181,12 +183,24 @@
 
 void bl2_early_platform_setup(meminfo_t *mem_layout)
 {
+#if !POPLAR_RECOVERY
+	dw_mmc_params_t params = EMMC_INIT_PARAMS(POPLAR_EMMC_DESC_BASE);
+#endif
+
 	console_init(PL011_UART0_BASE, PL011_UART0_CLK_IN_HZ, PL011_BAUDRATE);
 
 	/* Enable arch timer */
 	generic_delay_timer_init();
 
 	bl2_tzram_layout = *mem_layout;
+
+#if !POPLAR_RECOVERY
+	/* SoC-specific emmc register are initialized/configured by bootrom */
+	INFO("BL2: initializing emmc\n");
+	dw_mmc_init(&params);
+#endif
+
+	plat_io_setup();
 }
 
 void bl2_plat_arch_setup(void)
@@ -201,7 +215,6 @@
 
 void bl2_platform_setup(void)
 {
-	plat_io_setup();
 }
 
 unsigned long plat_get_ns_image_entrypoint(void)
diff --git a/plat/hisilicon/poplar/include/hi3798cv200.h b/plat/hisilicon/poplar/include/hi3798cv200.h
index 540d0aa..125b048 100644
--- a/plat/hisilicon/poplar/include/hi3798cv200.h
+++ b/plat/hisilicon/poplar/include/hi3798cv200.h
@@ -7,6 +7,8 @@
 #ifndef __HI3798cv200_H__
 #define __HI3798cv200_H__
 
+#include <utils_def.h>
+
 /* PL011 */
 #define PL011_UART0_BASE		(0xF8B00000)
 #define PL011_BAUDRATE			(115200)
@@ -63,11 +65,11 @@
 #define EMMC_CLK_50M			(1 << 8)
 #define EMMC_CLK_25M			(2 << 8)
 
-#define EMMC_DESC_SIZE			(0xF0000)
+#define EMMC_DESC_SIZE			U(0x00100000) /* 1MB */
 #define EMMC_INIT_PARAMS(base)				\
 	{	.bus_width = EMMC_BUS_WIDTH_8,		\
 		.clk_rate = 25 * 1000 * 1000,		\
-		.desc_base = (base) - EMMC_DESC_SIZE,	\
+		.desc_base = (base),	\
 		.desc_size = EMMC_DESC_SIZE,		\
 		.flags =  EMMC_FLAG_CMD23,		\
 		.reg_base = REG_BASE_MCI,		\
diff --git a/plat/hisilicon/poplar/include/platform_def.h b/plat/hisilicon/poplar/include/platform_def.h
index 3d1ad9b..c0f8371 100644
--- a/plat/hisilicon/poplar/include/platform_def.h
+++ b/plat/hisilicon/poplar/include/platform_def.h
@@ -12,6 +12,7 @@
 #include <gic_common.h>
 #include <interrupt_props.h>
 #include <tbbr/tbbr_img_def.h>
+#include <utils_def.h>
 #include "hi3798cv200.h"
 #include "poplar_layout.h"		/* BL memory region sizes, etc */
 
@@ -53,13 +54,12 @@
 #define POPLAR_DRAM_ID	1
 
 /*
- * DDR for OP-TEE (28MB from 0x02200000 -0x04000000) is divided in several
+ * DDR for OP-TEE (26MB from 0x02400000 -0x04000000) is divided in several
  * regions:
  *   - Secure DDR (default is the top 16MB) used by OP-TEE
  *   - Non-secure DDR (4MB) reserved for OP-TEE's future use
  *   - Secure DDR (4MB aligned on 4MB) for OP-TEE's "Secure Data Path" feature
  *   - Non-secure DDR used by OP-TEE (shared memory and padding) (4MB)
- *   - Non-secure DDR (2MB) reserved for OP-TEE's future use
  */
 #define DDR_SEC_SIZE			0x01000000
 #define DDR_SEC_BASE			0x03000000
@@ -96,6 +96,11 @@
 #endif /* SPD_none */
 #endif
 
+#define POPLAR_EMMC_DATA_BASE U(0x02200000)
+#define POPLAR_EMMC_DATA_SIZE EMMC_DESC_SIZE
+#define POPLAR_EMMC_DESC_BASE (POPLAR_EMMC_DATA_BASE + POPLAR_EMMC_DATA_SIZE)
+#define POPLAR_EMMC_DESC_SIZE EMMC_DESC_SIZE
+
 #define PLAT_POPLAR_NS_IMAGE_OFFSET	0x37000000
 
 /* Page table and MMU setup constants */
diff --git a/plat/hisilicon/poplar/include/poplar_layout.h b/plat/hisilicon/poplar/include/poplar_layout.h
index e0b5618..9ce0434 100644
--- a/plat/hisilicon/poplar/include/poplar_layout.h
+++ b/plat/hisilicon/poplar/include/poplar_layout.h
@@ -12,8 +12,8 @@
  */
 
 /*
- * When Poplar is powered on, boot ROM loads the initial content of
- * boot media into low memory, verifies it, and begins executing it
+ * When Poplar is powered on, boot ROM verifies the initial content of
+ * boot media, loads it into low memory, and begins executing it
  * in 32-bit mode.  The image loaded is "l-loader.bin", which contains
  * a small amount code along with an embedded ARM Trusted Firmware
  * BL1 image.  The main purpose of "l-loader" is to prepare the
@@ -78,12 +78,36 @@
 #define BL1_OFFSET			0x0000D000	/* page multiple */
 #define FIP_BASE			0x02040000
 
+/*
+ * FIP_BASE_EMMC = 0x40000 - 0x1000
+ * = fip.bin offset - l-loader text offset
+ * in l-loader.bin
+ */
+#define FIP_BASE_EMMC			0x0003f000
+
 #define BL1_RO_SIZE			0x00008000	/* page multiple */
 #define BL1_RW_SIZE			0x00008000	/* page multiple */
 #define BL1_SIZE			(BL1_RO_SIZE + BL1_RW_SIZE)
 #define BL2_SIZE			0x0000c000	/* page multiple */
 #define BL31_SIZE			0x00014000
+#if !POPLAR_RECOVERY
+/*
+ * emmc partition1 4096KB
+ * - l-loader.bin 1984KB
+ * |- l-loader + bl1.bin 256KB
+ * |- fip.bin 1728KB (0x001b0000)
+ * - u-boot persistent data 64KB
+ * - uefi persistent data 2048KB
+ */
+#define FIP_SIZE			0x001b0000  /* absolute max */
+#else
+/*
+ * same as above, but bootrom can only load an image (l-loader.bin) of
+ * 1024KB max, so after deducting the size of l-loader + bl1.bin (256KB),
+ * that leaves 768KB (0x000c0000) for fip.bin
+ */
 #define FIP_SIZE			0x000c0000  /* absolute max */
+#endif
 
      /* BL1_OFFSET */			/* (Defined above) */
 #define BL1_BASE			(LLOADER_TEXT_BASE + BL1_OFFSET)
diff --git a/plat/hisilicon/poplar/plat_storage.c b/plat/hisilicon/poplar/plat_storage.c
index ab94cba..468e229 100644
--- a/plat/hisilicon/poplar/plat_storage.c
+++ b/plat/hisilicon/poplar/plat_storage.c
@@ -7,6 +7,7 @@
 #include <arch_helpers.h>
 #include <assert.h>
 #include <debug.h>
+#include <emmc.h>
 #include <firmware_image_package.h>
 #include <io_block.h>
 #include <io_driver.h>
@@ -21,19 +22,41 @@
 #include <utils.h>
 #include "platform_def.h"
 
-static const io_dev_connector_t *mmap_dev_con;
-static const io_dev_connector_t *fip_dev_con;
+#if !POPLAR_RECOVERY
+static const io_dev_connector_t *emmc_dev_con;
+static uintptr_t emmc_dev_handle;
+static int open_emmc(const uintptr_t spec);
 
-static uintptr_t mmap_dev_handle;
-static uintptr_t fip_dev_handle;
+static const io_block_spec_t emmc_fip_spec = {
+	.offset		= FIP_BASE_EMMC,
+	.length		= FIP_SIZE
+};
 
+static const io_block_dev_spec_t emmc_dev_spec = {
+	.buffer		= {
+		.offset	= POPLAR_EMMC_DATA_BASE,
+		.length	= POPLAR_EMMC_DATA_SIZE,
+	},
+	.ops		= {
+		.read	= emmc_read_blocks,
+		.write	= emmc_write_blocks,
+	},
+	.block_size	= EMMC_BLOCK_SIZE,
+};
+#else
+static const io_dev_connector_t *mmap_dev_con;
+static uintptr_t mmap_dev_handle;
 static int open_mmap(const uintptr_t spec);
-static int open_fip(const uintptr_t spec);
 
 static const io_block_spec_t loader_fip_spec = {
 	.offset		= FIP_BASE,
 	.length		= FIP_SIZE
 };
+#endif
+
+static const io_dev_connector_t *fip_dev_con;
+static uintptr_t fip_dev_handle;
+static int open_fip(const uintptr_t spec);
 
 static const io_uuid_spec_t bl2_uuid_spec = {
 	.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
@@ -58,11 +81,19 @@
 };
 
 static const struct plat_io_policy policies[] = {
+#if !POPLAR_RECOVERY
+	[FIP_IMAGE_ID] = {
+		&emmc_dev_handle,
+		(uintptr_t)&emmc_fip_spec,
+		open_emmc
+	},
+#else
 	[FIP_IMAGE_ID] = {
 		&mmap_dev_handle,
 		(uintptr_t)&loader_fip_spec,
 		open_mmap
 	},
+#endif
 	[BL2_IMAGE_ID] = {
 		&fip_dev_handle,
 		(uintptr_t)&bl2_uuid_spec,
@@ -85,6 +116,28 @@
 	},
 };
 
+#if !POPLAR_RECOVERY
+static int open_emmc(const uintptr_t spec)
+{
+	int result;
+	uintptr_t local_image_handle;
+
+	result = io_dev_init(emmc_dev_handle, (uintptr_t)NULL);
+	if (result == 0) {
+		result = io_open(emmc_dev_handle, spec, &local_image_handle);
+		if (result == 0) {
+			INFO("Using eMMC\n");
+			io_close(local_image_handle);
+		} else {
+			ERROR("error opening emmc\n");
+		}
+	} else {
+		ERROR("error initializing emmc\n");
+	}
+
+	return result;
+}
+#else
 static int open_mmap(const uintptr_t spec)
 {
 	int result;
@@ -94,11 +147,18 @@
 	if (result == 0) {
 		result = io_open(mmap_dev_handle, spec, &local_image_handle);
 		if (result == 0) {
+			INFO("Using mmap\n");
 			io_close(local_image_handle);
+		} else {
+			ERROR("error opening mmap\n");
 		}
+	} else {
+		ERROR("error initializing mmap\n");
 	}
+
 	return result;
 }
+#endif
 
 static int open_fip(const uintptr_t spec)
 {
@@ -109,12 +169,13 @@
 	if (result == 0) {
 		result = io_open(fip_dev_handle, spec, &local_image_handle);
 		if (result == 0) {
+			INFO("Using FIP\n");
 			io_close(local_image_handle);
 		} else {
-			VERBOSE("error opening fip\n");
+			ERROR("error opening fip\n");
 		}
 	} else {
-		VERBOSE("error initializing fip\n");
+		ERROR("error initializing fip\n");
 	}
 
 	return result;
@@ -142,17 +203,31 @@
 {
 	int result;
 
+#if !POPLAR_RECOVERY
+	result = register_io_dev_block(&emmc_dev_con);
+#else
 	result = register_io_dev_memmap(&mmap_dev_con);
+#endif
 	assert(result == 0);
 
 	result = register_io_dev_fip(&fip_dev_con);
 	assert(result == 0);
 
+#if !POPLAR_RECOVERY
+	result = io_dev_open(fip_dev_con, (uintptr_t)NULL,
+				&fip_dev_handle);
+#else
 	result = io_dev_open(fip_dev_con, (uintptr_t)&loader_fip_spec,
 				&fip_dev_handle);
+#endif
 	assert(result == 0);
 
+#if !POPLAR_RECOVERY
+	result = io_dev_open(emmc_dev_con, (uintptr_t)&emmc_dev_spec,
+				&emmc_dev_handle);
+#else
 	result = io_dev_open(mmap_dev_con, (uintptr_t)NULL, &mmap_dev_handle);
+#endif
 	assert(result == 0);
 
 	(void) result;
diff --git a/plat/hisilicon/poplar/platform.mk b/plat/hisilicon/poplar/platform.mk
index 818e311..2dbbac6 100644
--- a/plat/hisilicon/poplar/platform.mk
+++ b/plat/hisilicon/poplar/platform.mk
@@ -15,6 +15,9 @@
 endif
 $(eval $(call add_define,POPLAR_TSP_RAM_LOCATION_ID))
 
+POPLAR_RECOVERY		:= 0
+$(eval $(call add_define,POPLAR_RECOVERY))
+
 NEED_BL33			:= yes
 
 COLD_BOOT_SINGLE_CPU		:= 1
@@ -36,6 +39,7 @@
 			-Iinclude/plat/arm/common/		\
 			-Iplat/hisilicon/poplar			\
 			-Iinclude/common/tbbr			\
+			-Iinclude/drivers/synopsys		\
 			-Iinclude/drivers/io
 
 PLAT_BL_COMMON_SOURCES	:=						\
@@ -54,6 +58,8 @@
 BL1_SOURCES	+=							\
 		lib/cpus/aarch64/cortex_a53.S				\
 		drivers/arm/pl061/pl061_gpio.c				\
+		drivers/emmc/emmc.c					\
+		drivers/synopsys/emmc/dw_mmc.c				\
 		drivers/io/io_storage.c					\
 		drivers/io/io_block.c					\
 		drivers/gpio/gpio.c					\
@@ -65,6 +71,8 @@
 
 BL2_SOURCES	+=      						\
 		drivers/arm/pl061/pl061_gpio.c				\
+		drivers/emmc/emmc.c					\
+		drivers/synopsys/emmc/dw_mmc.c				\
 		drivers/io/io_storage.c					\
 		drivers/io/io_block.c					\
 		drivers/io/io_fip.c					\
diff --git a/plat/rockchip/common/aarch64/plat_helpers.S b/plat/rockchip/common/aarch64/plat_helpers.S
index abfb5a7..f415f87 100644
--- a/plat/rockchip/common/aarch64/plat_helpers.S
+++ b/plat/rockchip/common/aarch64/plat_helpers.S
@@ -19,10 +19,9 @@
 	.globl	plat_secondary_cold_boot_setup
 	.globl	plat_report_exception
 	.globl	platform_is_primary_cpu
-	.globl	plat_crash_console_init
-	.globl	plat_crash_console_putc
 	.globl	plat_my_core_pos
 	.globl	plat_reset_handler
+	.globl	plat_panic_handler
 
 	/*
 	 * void plat_reset_handler(void);
@@ -82,30 +81,17 @@
 endfunc platform_is_primary_cpu
 
 	/* --------------------------------------------------------------------
-	 * int plat_crash_console_init(void)
-	 * Function to initialize the crash console
-	 * without a C Runtime to print crash report.
-	 * Clobber list : x0, x1, x2
+	 * void plat_panic_handler(void)
+	 * Call system reset function on panic. Set up an emergency stack so we
+	 * can run C functions (it only needs to last for a few calls until we
+	 * reboot anyway).
 	 * --------------------------------------------------------------------
 	 */
-func plat_crash_console_init
-	mov_imm	x0, PLAT_RK_UART_BASE
-	mov_imm	x1, PLAT_RK_UART_CLOCK
-	mov_imm	x2, PLAT_RK_UART_BAUDRATE
-	b	console_core_init
-endfunc plat_crash_console_init
-
-	/* --------------------------------------------------------------------
-	 * int plat_crash_console_putc(void)
-	 * Function to print a character on the crash
-	 * console without a C Runtime.
-	 * Clobber list : x1, x2
-	 * --------------------------------------------------------------------
-	 */
-func plat_crash_console_putc
-	mov_imm x1, PLAT_RK_UART_BASE
-	b	console_core_putc
-endfunc plat_crash_console_putc
+func plat_panic_handler
+	msr	spsel, #0
+	bl	plat_set_my_stack
+	b	rockchip_soc_soft_reset
+endfunc plat_panic_handler
 
 	/* --------------------------------------------------------------------
 	 * void platform_cpu_warmboot (void);
diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c
index 292f0dd..6199eda 100644
--- a/plat/rockchip/common/bl31_plat_setup.c
+++ b/plat/rockchip/common/bl31_plat_setup.c
@@ -8,12 +8,14 @@
 #include <assert.h>
 #include <bl_common.h>
 #include <console.h>
+#include <coreboot.h>
 #include <debug.h>
 #include <generic_delay_timer.h>
 #include <mmio.h>
 #include <plat_private.h>
 #include <platform.h>
 #include <platform_def.h>
+#include <uart_16550.h>
 
 /*******************************************************************************
  * Declarations of linker defined symbols which will help us find the layout
@@ -69,8 +71,20 @@
 void bl31_early_platform_setup(bl31_params_t *from_bl2,
 			       void *plat_params_from_bl2)
 {
-	console_init(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK,
-		     PLAT_RK_UART_BAUDRATE);
+	static console_16550_t console;
+
+	params_early_setup(plat_params_from_bl2);
+
+#if COREBOOT
+	if (coreboot_serial.type)
+		console_16550_register(coreboot_serial.baseaddr,
+				       coreboot_serial.input_hertz,
+				       coreboot_serial.baud,
+				       &console);
+#else
+	console_16550_register(PLAT_RK_UART_BASE, PLAT_RK_UART_CLOCK,
+			       PLAT_RK_UART_BAUDRATE, &console);
+#endif
 
 	VERBOSE("bl31_setup\n");
 
@@ -82,9 +96,6 @@
 
 	bl32_ep_info = *from_bl2->bl32_ep_info;
 	bl33_ep_info = *from_bl2->bl33_ep_info;
-
-	/* there may have some board sepcific message need to initialize */
-	params_early_setup(plat_params_from_bl2);
 }
 
 /*******************************************************************************
diff --git a/plat/rockchip/common/include/plat_macros.S b/plat/rockchip/common/include/plat_macros.S
index be1a9fa..6b3cb6a 100644
--- a/plat/rockchip/common/include/plat_macros.S
+++ b/plat/rockchip/common/include/plat_macros.S
@@ -38,14 +38,14 @@
 	 * The below utility macro prints out relevant GIC
 	 * and CCI registers whenever an unhandled
 	 * exception is taken in BL31.
-	 * Expects: GICD base in x16, GICC base in x17
+	 * Expects: GICD base in x26, GICC base in x27
 	 * Clobbers: x0 - x10, sp
 	 * ---------------------------------------------
 	 */
 	.macro plat_crash_print_regs
 
-	mov_imm	x16, PLAT_RK_GICD_BASE
-	mov_imm	x17, PLAT_RK_GICC_BASE
+	mov_imm	x26, PLAT_RK_GICD_BASE
+	mov_imm	x27, PLAT_RK_GICC_BASE
 
 	/* Check for GICv3 system register access */
 	mrs	x7, id_aa64pfr0_el1
@@ -72,19 +72,19 @@
 	/* Load the gicc reg list to x6 */
 	adr	x6, gicc_regs
 	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
-	ldr	w8, [x17, #GICC_HPPIR]
-	ldr	w9, [x17, #GICC_AHPPIR]
-	ldr	w10, [x17, #GICC_CTLR]
+	ldr	w8, [x27, #GICC_HPPIR]
+	ldr	w9, [x27, #GICC_AHPPIR]
+	ldr	w10, [x27, #GICC_CTLR]
 	/* Store to the crash buf and print to console */
 	bl	str_in_crash_buf_print
 
 print_gic_common:
 	/* Print the GICD_ISPENDR regs */
-	add	x7, x16, #GICD_ISPENDR
+	add	x7, x26, #GICD_ISPENDR
 	adr	x4, gicd_pend_reg
 	bl	asm_print_str
 gicd_ispendr_loop:
-	sub	x4, x7, x16
+	sub	x4, x7, x26
 	cmp	x4, #0x280
 	b.eq	exit_print_gic_regs
 	bl	asm_print_hex
diff --git a/plat/rockchip/common/include/plat_params.h b/plat/rockchip/common/include/plat_params.h
index aa13f87..7109907 100644
--- a/plat/rockchip/common/include/plat_params.h
+++ b/plat/rockchip/common/include/plat_params.h
@@ -56,6 +56,7 @@
 	PARAM_POWEROFF,
 	PARAM_SUSPEND_GPIO,
 	PARAM_SUSPEND_APIO,
+	PARAM_COREBOOT_TABLE,
 };
 
 struct apio_info {
@@ -89,4 +90,9 @@
 	struct apio_info apio;
 };
 
+struct bl31_u64_param {
+	struct bl31_plat_param h;
+	uint64_t value;
+};
+
 #endif /* __PLAT_PARAMS_H__ */
diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c
index b37acb7..65afe87 100644
--- a/plat/rockchip/common/params_setup.c
+++ b/plat/rockchip/common/params_setup.c
@@ -8,6 +8,7 @@
 #include <assert.h>
 #include <bl_common.h>
 #include <console.h>
+#include <coreboot.h>
 #include <debug.h>
 #include <gpio.h>
 #include <mmio.h>
@@ -84,6 +85,12 @@
 			       sizeof(struct bl31_apio_param));
 			suspend_apio = &param_apio.apio;
 			break;
+#if COREBOOT
+		case PARAM_COREBOOT_TABLE:
+			coreboot_table_setup((void *)
+				((struct bl31_u64_param *)bl2_param)->value);
+			break;
+#endif
 		default:
 			ERROR("not expected type found %ld\n",
 			      bl2_param->type);
diff --git a/plat/rockchip/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk
index 5de4680..6e4d5b4 100644
--- a/plat/rockchip/rk3328/platform.mk
+++ b/plat/rockchip/rk3328/platform.mk
@@ -49,6 +49,9 @@
 				${RK_PLAT_SOC}/drivers/soc/soc.c
 
 ENABLE_PLAT_COMPAT 	:=	0
+MULTI_CONSOLE_API	:=	1
+
+include lib/coreboot/coreboot.mk
 
 $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
 $(eval $(call add_define,PLAT_SKIP_OPTEE_S_EL1_INT_REGISTER))
diff --git a/plat/rockchip/rk3368/platform.mk b/plat/rockchip/rk3368/platform.mk
index d3c6eef..ad204e9 100644
--- a/plat/rockchip/rk3368/platform.mk
+++ b/plat/rockchip/rk3368/platform.mk
@@ -49,6 +49,9 @@
 				${RK_PLAT_SOC}/drivers/ddr/ddr_rk3368.c		\
 
 ENABLE_PLAT_COMPAT	:=	0
+MULTI_CONSOLE_API	:=	1
+
+include lib/coreboot/coreboot.mk
 
 $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
 
diff --git a/plat/rockchip/rk3399/platform.mk b/plat/rockchip/rk3399/platform.mk
index 33b9723..9e369e4 100644
--- a/plat/rockchip/rk3399/platform.mk
+++ b/plat/rockchip/rk3399/platform.mk
@@ -64,6 +64,9 @@
 			${RK_PLAT_SOC}/drivers/dram/suspend.c
 
 ENABLE_PLAT_COMPAT	:=	0
+MULTI_CONSOLE_API	:=	1
+
+include lib/coreboot/coreboot.mk
 
 $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))