Merge pull request #1568 from soby-mathew/sm/fix_ares_err_report

Fix the Cortex-ares errata reporting function name
diff --git a/drivers/allwinner/sunxi_i2c.c b/drivers/allwinner/sunxi_i2c.c
new file mode 100644
index 0000000..cc91ca5
--- /dev/null
+++ b/drivers/allwinner/sunxi_i2c.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/* This driver provides I2C support for Allwinner sunXi SoCs */
+
+#include <mmio.h>
+
+#define CONFIG_SYS_TCLK			24000000
+#define CONFIG_SYS_I2C_SPEED		100000
+#define CONFIG_SYS_I2C_SLAVE		0
+
+#define I2C_INTERRUPT_CLEAR_INVERTED
+
+struct  mentor_i2c_regs {
+	uint32_t slave_address;
+	uint32_t xtnd_slave_addr;
+	uint32_t data;
+	uint32_t control;
+	uint32_t status;
+	uint32_t baudrate;
+	uint32_t soft_reset;
+};
+
+#include "../mentor/i2c/mi2cv.c"
diff --git a/drivers/marvell/i2c/a8k_i2c.c b/drivers/marvell/i2c/a8k_i2c.c
index 72a7731..1c0f922 100644
--- a/drivers/marvell/i2c/a8k_i2c.c
+++ b/drivers/marvell/i2c/a8k_i2c.c
@@ -7,57 +7,22 @@
 
 /* This driver provides I2C support for Marvell A8K and compatible SoCs */
 
-#include <a8k_i2c.h>
-#include <debug.h>
-#include <delay_timer.h>
-#include <errno.h>
 #include <mmio.h>
-#include <mvebu_def.h>
-
-#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
-#define DEBUG_I2C
-#endif
 
 #define CONFIG_SYS_TCLK			250000000
 #define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_SYS_I2C_SLAVE		0x0
-#define I2C_TIMEOUT_VALUE		0x500
-#define I2C_MAX_RETRY_CNT		1000
-#define I2C_CMD_WRITE			0x0
-#define I2C_CMD_READ			0x1
-
-#define I2C_DATA_ADDR_7BIT_OFFS		0x1
-#define I2C_DATA_ADDR_7BIT_MASK		(0xFF << I2C_DATA_ADDR_7BIT_OFFS)
-
-#define I2C_CONTROL_ACK			0x00000004
-#define I2C_CONTROL_IFLG		0x00000008
-#define I2C_CONTROL_STOP		0x00000010
-#define I2C_CONTROL_START		0x00000020
-#define I2C_CONTROL_TWSIEN		0x00000040
-#define I2C_CONTROL_INTEN		0x00000080
 
-#define I2C_STATUS_START			0x08
-#define I2C_STATUS_REPEATED_START		0x10
-#define I2C_STATUS_ADDR_W_ACK			0x18
-#define I2C_STATUS_DATA_W_ACK			0x28
-#define I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER	0x38
-#define I2C_STATUS_ADDR_R_ACK			0x40
-#define I2C_STATUS_DATA_R_ACK			0x50
-#define I2C_STATUS_DATA_R_NAK			0x58
-#define I2C_STATUS_LOST_ARB_GENERAL_CALL	0x78
-#define I2C_STATUS_IDLE				0xF8
+#define I2C_CAN_UNSTUCK
 
-#define I2C_UNSTUCK_TRIGGER			0x1
-#define I2C_UNSTUCK_ONGOING			0x2
-#define I2C_UNSTUCK_ERROR			0x4
-struct  marvell_i2c_regs {
+struct  mentor_i2c_regs {
 	uint32_t slave_address;
 	uint32_t data;
 	uint32_t control;
 	union {
 		uint32_t status;	/* when reading */
 		uint32_t baudrate;	/* when writing */
-	} u;
+	};
 	uint32_t xtnd_slave_addr;
 	uint32_t reserved[2];
 	uint32_t soft_reset;
@@ -65,549 +30,4 @@
 	uint32_t unstuck;
 };
 
-static struct marvell_i2c_regs *base;
-
-static int marvell_i2c_lost_arbitration(uint32_t *status)
-{
-	*status = mmio_read_32((uintptr_t)&base->u.status);
-	if ((*status == I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER) ||
-	    (*status == I2C_STATUS_LOST_ARB_GENERAL_CALL))
-		return -EAGAIN;
-
-	return 0;
-}
-
-static void marvell_i2c_interrupt_clear(void)
-{
-	uint32_t reg;
-
-	reg = mmio_read_32((uintptr_t)&base->control);
-	reg &= ~(I2C_CONTROL_IFLG);
-	mmio_write_32((uintptr_t)&base->control, reg);
-	/* Wait for 1 us for the clear to take effect */
-	udelay(1);
-}
-
-static int marvell_i2c_interrupt_get(void)
-{
-	uint32_t reg;
-
-	/* get the interrupt flag bit */
-	reg = mmio_read_32((uintptr_t)&base->control);
-	reg &= I2C_CONTROL_IFLG;
-	return reg && I2C_CONTROL_IFLG;
-}
-
-static int marvell_i2c_wait_interrupt(void)
-{
-	uint32_t timeout = 0;
-
-	while (!marvell_i2c_interrupt_get() && (timeout++ < I2C_TIMEOUT_VALUE))
-		;
-	if (timeout >= I2C_TIMEOUT_VALUE)
-		return -ETIMEDOUT;
-
-	return 0;
-}
-
-static int marvell_i2c_start_bit_set(void)
-{
-	int is_int_flag = 0;
-	uint32_t status;
-
-	if (marvell_i2c_interrupt_get())
-		is_int_flag = 1;
-
-	/* set start bit */
-	mmio_write_32((uintptr_t)&base->control,
-		      mmio_read_32((uintptr_t)&base->control) |
-		      I2C_CONTROL_START);
-
-	/* in case that the int flag was set before i.e. repeated start bit */
-	if (is_int_flag) {
-		VERBOSE("%s: repeated start Bit\n", __func__);
-		marvell_i2c_interrupt_clear();
-	}
-
-	if (marvell_i2c_wait_interrupt()) {
-		ERROR("Start clear bit timeout\n");
-		return -ETIMEDOUT;
-	}
-
-	/* check that start bit went down */
-	if ((mmio_read_32((uintptr_t)&base->control) &
-	    I2C_CONTROL_START) != 0) {
-		ERROR("Start bit didn't went down\n");
-		return -EPERM;
-	}
-
-	/* check the status */
-	if (marvell_i2c_lost_arbitration(&status)) {
-		ERROR("%s - %d: Lost arbitration, got status %x\n",
-		      __func__, __LINE__, status);
-		return -EAGAIN;
-	}
-	if ((status != I2C_STATUS_START) &&
-	    (status != I2C_STATUS_REPEATED_START)) {
-		ERROR("Got status %x after enable start bit.\n", status);
-		return -EPERM;
-	}
-
-	return 0;
-}
-
-static int marvell_i2c_stop_bit_set(void)
-{
-	int timeout;
-	uint32_t status;
-
-	/* Generate stop bit */
-	mmio_write_32((uintptr_t)&base->control,
-		      mmio_read_32((uintptr_t)&base->control) |
-		      I2C_CONTROL_STOP);
-	marvell_i2c_interrupt_clear();
-
-	timeout = 0;
-	/* Read control register, check the control stop bit */
-	while ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) &&
-	       (timeout++ < I2C_TIMEOUT_VALUE))
-		;
-	if (timeout >= I2C_TIMEOUT_VALUE) {
-		ERROR("Stop bit didn't went down\n");
-		return -ETIMEDOUT;
-	}
-
-	/* check that stop bit went down */
-	if ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) != 0) {
-		ERROR("Stop bit didn't went down\n");
-		return -EPERM;
-	}
-
-	/* check the status */
-	if (marvell_i2c_lost_arbitration(&status)) {
-		ERROR("%s - %d: Lost arbitration, got status %x\n",
-		      __func__, __LINE__, status);
-		return -EAGAIN;
-	}
-	if (status != I2C_STATUS_IDLE) {
-		ERROR("Got status %x after enable stop bit.\n", status);
-		return -EPERM;
-	}
-
-	return 0;
-}
-
-static int marvell_i2c_address_set(uint8_t chain, int command)
-{
-	uint32_t reg, status;
-
-	reg = (chain << I2C_DATA_ADDR_7BIT_OFFS) & I2C_DATA_ADDR_7BIT_MASK;
-	reg |= command;
-	mmio_write_32((uintptr_t)&base->data, reg);
-	udelay(1);
-
-	marvell_i2c_interrupt_clear();
-
-	if (marvell_i2c_wait_interrupt()) {
-		ERROR("Start clear bit timeout\n");
-		return -ETIMEDOUT;
-	}
-
-	/* check the status */
-	if (marvell_i2c_lost_arbitration(&status)) {
-		ERROR("%s - %d: Lost arbitration, got status %x\n",
-		      __func__, __LINE__, status);
-		return -EAGAIN;
-	}
-	if (((status != I2C_STATUS_ADDR_R_ACK) && (command == I2C_CMD_READ)) ||
-	   ((status != I2C_STATUS_ADDR_W_ACK) && (command == I2C_CMD_WRITE))) {
-		/* only in debug, since in boot we try to read the SPD
-		 * of both DRAM, and we don't want error messages in cas
-		 * DIMM doesn't exist.
-		 */
-		INFO("%s: ERROR - status %x addr in %s mode.\n", __func__,
-		     status, (command == I2C_CMD_WRITE) ? "Write" : "Read");
-		return -EPERM;
-	}
-
-	return 0;
-}
-
-/*
- * The I2C module contains a clock divider to generate the SCL clock.
- * This function calculates and sets the <N> and <M> fields in the I2C Baud
- * Rate Register (t=01) to obtain given 'requested_speed'.
- * The requested_speed will be equal to:
- * CONFIG_SYS_TCLK / (10 * (M + 1) * (2 << N))
- * Where M is the value represented by bits[6:3] and N is the value represented
- * by bits[2:0] of "I2C Baud Rate Register".
- * Therefore max M which can be set is 16 (2^4) and max N is 8 (2^3). So the
- * lowest possible baudrate is:
- * CONFIG_SYS_TCLK/(10 * (16 +1) * (2 << 8), which equals to:
- * CONFIG_SYS_TCLK/87040. Assuming that CONFIG_SYS_TCLK=250MHz, the lowest
- * possible frequency is ~2,872KHz.
- */
-static unsigned int marvell_i2c_bus_speed_set(unsigned int requested_speed)
-{
-	unsigned int n, m, freq, margin, min_margin = 0xffffffff;
-	unsigned int actual_n = 0, actual_m = 0;
-	int val;
-
-	/* Calculate N and M for the TWSI clock baud rate */
-	for (n = 0; n < 8; n++) {
-		for (m = 0; m < 16; m++) {
-			freq = CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
-			val = requested_speed - freq;
-			margin = (val > 0) ? val : -val;
-
-			if ((freq <= requested_speed) &&
-			    (margin < min_margin)) {
-				min_margin = margin;
-				actual_n = n;
-				actual_m = m;
-			}
-		}
-	}
-	VERBOSE("%s: actual_n = %u, actual_m = %u\n",
-		__func__, actual_n, actual_m);
-	/* Set the baud rate */
-	mmio_write_32((uintptr_t)&base->u.baudrate, (actual_m << 3) | actual_n);
-
-	return 0;
-}
-
-#ifdef DEBUG_I2C
-static int marvell_i2c_probe(uint8_t chip)
-{
-	int ret = 0;
-
-	ret = marvell_i2c_start_bit_set();
-	if (ret != 0) {
-		marvell_i2c_stop_bit_set();
-		ERROR("%s - %d: %s", __func__, __LINE__,
-		      "marvell_i2c_start_bit_set failed\n");
-		return -EPERM;
-	}
-
-	ret = marvell_i2c_address_set(chip, I2C_CMD_WRITE);
-	if (ret != 0) {
-		marvell_i2c_stop_bit_set();
-		ERROR("%s - %d: %s", __func__, __LINE__,
-		      "marvell_i2c_address_set failed\n");
-		return -EPERM;
-	}
-
-	marvell_i2c_stop_bit_set();
-
-	VERBOSE("%s: successful I2C probe\n", __func__);
-
-	return ret;
-}
-#endif
-
-/* regular i2c transaction */
-static int marvell_i2c_data_receive(uint8_t *p_block, uint32_t block_size)
-{
-	uint32_t reg, status, block_size_read = block_size;
-
-	/* Wait for cause interrupt */
-	if (marvell_i2c_wait_interrupt()) {
-		ERROR("Start clear bit timeout\n");
-		return -ETIMEDOUT;
-	}
-	while (block_size_read) {
-		if (block_size_read == 1) {
-			reg = mmio_read_32((uintptr_t)&base->control);
-			reg &= ~(I2C_CONTROL_ACK);
-			mmio_write_32((uintptr_t)&base->control, reg);
-		}
-		marvell_i2c_interrupt_clear();
-
-		if (marvell_i2c_wait_interrupt()) {
-			ERROR("Start clear bit timeout\n");
-			return -ETIMEDOUT;
-		}
-		/* check the status */
-		if (marvell_i2c_lost_arbitration(&status)) {
-			ERROR("%s - %d: Lost arbitration, got status %x\n",
-			      __func__, __LINE__, status);
-			return -EAGAIN;
-		}
-		if ((status != I2C_STATUS_DATA_R_ACK) &&
-		    (block_size_read != 1)) {
-			ERROR("Status %x in read transaction\n", status);
-			return -EPERM;
-		}
-		if ((status != I2C_STATUS_DATA_R_NAK) &&
-		    (block_size_read == 1)) {
-			ERROR("Status %x in Rd Terminate\n", status);
-			return -EPERM;
-		}
-
-		/* read the data */
-		*p_block = (uint8_t) mmio_read_32((uintptr_t)&base->data);
-		VERBOSE("%s: place %d read %x\n", __func__,
-			block_size - block_size_read, *p_block);
-		p_block++;
-		block_size_read--;
-	}
-
-	return 0;
-}
-
-static int marvell_i2c_data_transmit(uint8_t *p_block, uint32_t block_size)
-{
-	uint32_t status, block_size_write = block_size;
-
-	if (marvell_i2c_wait_interrupt()) {
-		ERROR("Start clear bit timeout\n");
-		return -ETIMEDOUT;
-	}
-
-	while (block_size_write) {
-		/* write the data */
-		mmio_write_32((uintptr_t)&base->data, (uint32_t) *p_block);
-		VERBOSE("%s: index = %d, data = %x\n", __func__,
-			block_size - block_size_write, *p_block);
-		p_block++;
-		block_size_write--;
-
-		marvell_i2c_interrupt_clear();
-
-		if (marvell_i2c_wait_interrupt()) {
-			ERROR("Start clear bit timeout\n");
-			return -ETIMEDOUT;
-		}
-
-		/* check the status */
-		if (marvell_i2c_lost_arbitration(&status)) {
-			ERROR("%s - %d: Lost arbitration, got status %x\n",
-			      __func__, __LINE__, status);
-			return -EAGAIN;
-		}
-		if (status != I2C_STATUS_DATA_W_ACK) {
-			ERROR("Status %x in write transaction\n", status);
-			return -EPERM;
-		}
-	}
-
-	return 0;
-}
-
-static int marvell_i2c_target_offset_set(uint8_t chip, uint32_t addr, int alen)
-{
-	uint8_t off_block[2];
-	uint32_t off_size;
-
-	if (alen == 2) { /* 2-byte addresses support */
-		off_block[0] = (addr >> 8) & 0xff;
-		off_block[1] = addr & 0xff;
-		off_size = 2;
-	} else { /* 1-byte addresses support */
-		off_block[0] = addr & 0xff;
-		off_size = 1;
-	}
-	VERBOSE("%s: off_size = %x addr1 = %x addr2 = %x\n", __func__,
-		off_size, off_block[0], off_block[1]);
-	return marvell_i2c_data_transmit(off_block, off_size);
-}
-
-static int marvell_i2c_unstuck(int ret)
-{
-	uint32_t v;
-
-	if (ret != -ETIMEDOUT)
-		return ret;
-	VERBOSE("Trying to \"unstuck i2c\"... ");
-	i2c_init(base);
-	mmio_write_32((uintptr_t)&base->unstuck, I2C_UNSTUCK_TRIGGER);
-	do {
-		v = mmio_read_32((uintptr_t)&base->unstuck);
-	} while (v & I2C_UNSTUCK_ONGOING);
-
-	if (v & I2C_UNSTUCK_ERROR) {
-		VERBOSE("failed - soft reset i2c\n");
-		ret = -EPERM;
-	} else {
-		VERBOSE("ok\n");
-		i2c_init(base);
-		ret = -EAGAIN;
-	}
-	return ret;
-}
-
-/*
- * API Functions
- */
-void i2c_init(void *i2c_base)
-{
-	/* For I2C speed and slave address, now we do not set them since
-	 * we just provide the working speed and slave address in mvebu_def.h
-	 * for i2c_init
-	 */
-	base = (struct marvell_i2c_regs *)i2c_base;
-
-	/* Reset the I2C logic */
-	mmio_write_32((uintptr_t)&base->soft_reset, 0);
-
-	udelay(200);
-
-	marvell_i2c_bus_speed_set(CONFIG_SYS_I2C_SPEED);
-
-	/* Enable the I2C and slave */
-	mmio_write_32((uintptr_t)&base->control,
-		      I2C_CONTROL_TWSIEN | I2C_CONTROL_ACK);
-
-	/* set the I2C slave address */
-	mmio_write_32((uintptr_t)&base->xtnd_slave_addr, 0);
-	mmio_write_32((uintptr_t)&base->slave_address, CONFIG_SYS_I2C_SLAVE);
-
-	/* unmask I2C interrupt */
-	mmio_write_32((uintptr_t)&base->control,
-		      mmio_read_32((uintptr_t)&base->control) |
-		      I2C_CONTROL_INTEN);
-
-	udelay(10);
-}
-
-/*
- * i2c_read: - Read multiple bytes from an i2c device
- *
- * The higher level routines take into account that this function is only
- * called with len < page length of the device (see configuration file)
- *
- * @chip:	address of the chip which is to be read
- * @addr:	i2c data address within the chip
- * @alen:	length of the i2c data address (1..2 bytes)
- * @buffer:	where to write the data
- * @len:	how much byte do we want to read
- * @return:	0 in case of success
- */
-int i2c_read(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
-{
-	int ret = 0;
-	uint32_t counter = 0;
-
-#ifdef DEBUG_I2C
-	marvell_i2c_probe(chip);
-#endif
-
-	do {
-		if (ret != -EAGAIN && ret) {
-			ERROR("i2c transaction failed, after %d retries\n",
-			      counter);
-			marvell_i2c_stop_bit_set();
-			return ret;
-		}
-
-		/* wait for 1 us for the interrupt clear to take effect */
-		if (counter > 0)
-			udelay(1);
-		counter++;
-
-		ret = marvell_i2c_start_bit_set();
-		if (ret) {
-			ret = marvell_i2c_unstuck(ret);
-			continue;
-		}
-
-		/* if EEPROM device */
-		if (alen != 0) {
-			ret = marvell_i2c_address_set(chip, I2C_CMD_WRITE);
-			if (ret)
-				continue;
-
-			ret = marvell_i2c_target_offset_set(chip, addr, alen);
-			if (ret)
-				continue;
-			ret = marvell_i2c_start_bit_set();
-			if (ret)
-				continue;
-		}
-
-		ret =  marvell_i2c_address_set(chip, I2C_CMD_READ);
-		if (ret)
-			continue;
-
-		ret = marvell_i2c_data_receive(buffer, len);
-		if (ret)
-			continue;
-
-		ret =  marvell_i2c_stop_bit_set();
-	} while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
-
-	if (counter == I2C_MAX_RETRY_CNT) {
-		ERROR("I2C transactions failed, got EAGAIN %d times\n",
-		      I2C_MAX_RETRY_CNT);
-		ret = -EPERM;
-	}
-	mmio_write_32((uintptr_t)&base->control,
-		      mmio_read_32((uintptr_t)&base->control) |
-		      I2C_CONTROL_ACK);
-
-	udelay(1);
-	return ret;
-}
-
-/*
- * i2c_write: -  Write multiple bytes to an i2c device
- *
- * The higher level routines take into account that this function is only
- * called with len < page length of the device (see configuration file)
- *
- * @chip:	address of the chip which is to be written
- * @addr:	i2c data address within the chip
- * @alen:	length of the i2c data address (1..2 bytes)
- * @buffer:	where to find the data to be written
- * @len:	how much byte do we want to read
- * @return:	0 in case of success
- */
-int i2c_write(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
-{
-	int ret = 0;
-	uint32_t counter = 0;
-
-	do {
-		if (ret != -EAGAIN && ret) {
-			ERROR("i2c transaction failed\n");
-			marvell_i2c_stop_bit_set();
-			return ret;
-		}
-		/* wait for 1 us for the interrupt clear to take effect */
-		if (counter > 0)
-			udelay(1);
-		counter++;
-
-		ret = marvell_i2c_start_bit_set();
-		if (ret) {
-			ret = marvell_i2c_unstuck(ret);
-			continue;
-		}
-
-		ret = marvell_i2c_address_set(chip, I2C_CMD_WRITE);
-		if (ret)
-			continue;
-
-		/* if EEPROM device */
-		if (alen != 0) {
-			ret = marvell_i2c_target_offset_set(chip, addr, alen);
-			if (ret)
-				continue;
-		}
-
-		ret = marvell_i2c_data_transmit(buffer, len);
-		if (ret)
-			continue;
-
-		ret = marvell_i2c_stop_bit_set();
-	} while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
-
-	if (counter == I2C_MAX_RETRY_CNT) {
-		ERROR("I2C transactions failed, got EAGAIN %d times\n",
-		      I2C_MAX_RETRY_CNT);
-		ret = -EPERM;
-	}
-
-	udelay(1);
-	return ret;
-}
+#include "../../mentor/i2c/mi2cv.c"
diff --git a/drivers/mentor/i2c/mi2cv.c b/drivers/mentor/i2c/mi2cv.c
new file mode 100644
index 0000000..1b73e6f
--- /dev/null
+++ b/drivers/mentor/i2c/mi2cv.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+/*
+ * This driver is for Mentor Graphics Inventra MI2CV IP core, which is used
+ * for Marvell and Allwinner SoCs in ATF.
+ */
+
+#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <mentor/mi2cv.h>
+#include <mmio.h>
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+#define DEBUG_I2C
+#endif
+
+#define I2C_TIMEOUT_VALUE		0x500
+#define I2C_MAX_RETRY_CNT		1000
+#define I2C_CMD_WRITE			0x0
+#define I2C_CMD_READ			0x1
+
+#define I2C_DATA_ADDR_7BIT_OFFS		0x1
+#define I2C_DATA_ADDR_7BIT_MASK		(0xFF << I2C_DATA_ADDR_7BIT_OFFS)
+
+#define I2C_CONTROL_ACK			0x00000004
+#define I2C_CONTROL_IFLG		0x00000008
+#define I2C_CONTROL_STOP		0x00000010
+#define I2C_CONTROL_START		0x00000020
+#define I2C_CONTROL_TWSIEN		0x00000040
+#define I2C_CONTROL_INTEN		0x00000080
+
+#define I2C_STATUS_START			0x08
+#define I2C_STATUS_REPEATED_START		0x10
+#define I2C_STATUS_ADDR_W_ACK			0x18
+#define I2C_STATUS_DATA_W_ACK			0x28
+#define I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER	0x38
+#define I2C_STATUS_ADDR_R_ACK			0x40
+#define I2C_STATUS_DATA_R_ACK			0x50
+#define I2C_STATUS_DATA_R_NAK			0x58
+#define I2C_STATUS_LOST_ARB_GENERAL_CALL	0x78
+#define I2C_STATUS_IDLE				0xF8
+
+#define I2C_UNSTUCK_TRIGGER			0x1
+#define I2C_UNSTUCK_ONGOING			0x2
+#define I2C_UNSTUCK_ERROR			0x4
+
+static struct mentor_i2c_regs *base;
+
+static int mentor_i2c_lost_arbitration(uint32_t *status)
+{
+	*status = mmio_read_32((uintptr_t)&base->status);
+	if ((*status == I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER) ||
+	    (*status == I2C_STATUS_LOST_ARB_GENERAL_CALL))
+		return -EAGAIN;
+
+	return 0;
+}
+
+static void mentor_i2c_interrupt_clear(void)
+{
+	uint32_t reg;
+
+	reg = mmio_read_32((uintptr_t)&base->control);
+#ifndef I2C_INTERRUPT_CLEAR_INVERTED
+	reg &= ~(I2C_CONTROL_IFLG);
+#else
+	reg |= I2C_CONTROL_IFLG;
+#endif
+	mmio_write_32((uintptr_t)&base->control, reg);
+	/* Wait for 1 us for the clear to take effect */
+	udelay(1);
+}
+
+static int mentor_i2c_interrupt_get(void)
+{
+	uint32_t reg;
+
+	/* get the interrupt flag bit */
+	reg = mmio_read_32((uintptr_t)&base->control);
+	reg &= I2C_CONTROL_IFLG;
+	return reg && I2C_CONTROL_IFLG;
+}
+
+static int mentor_i2c_wait_interrupt(void)
+{
+	uint32_t timeout = 0;
+
+	while (!mentor_i2c_interrupt_get() && (timeout++ < I2C_TIMEOUT_VALUE))
+		;
+	if (timeout >= I2C_TIMEOUT_VALUE)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int mentor_i2c_start_bit_set(void)
+{
+	int is_int_flag = 0;
+	uint32_t status;
+
+	if (mentor_i2c_interrupt_get())
+		is_int_flag = 1;
+
+	/* set start bit */
+	mmio_write_32((uintptr_t)&base->control,
+		      mmio_read_32((uintptr_t)&base->control) |
+		      I2C_CONTROL_START);
+
+	/* in case that the int flag was set before i.e. repeated start bit */
+	if (is_int_flag) {
+		VERBOSE("%s: repeated start Bit\n", __func__);
+		mentor_i2c_interrupt_clear();
+	}
+
+	if (mentor_i2c_wait_interrupt()) {
+		ERROR("Start clear bit timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	/* check that start bit went down */
+	if ((mmio_read_32((uintptr_t)&base->control) &
+	    I2C_CONTROL_START) != 0) {
+		ERROR("Start bit didn't went down\n");
+		return -EPERM;
+	}
+
+	/* check the status */
+	if (mentor_i2c_lost_arbitration(&status)) {
+		ERROR("%s - %d: Lost arbitration, got status %x\n",
+		      __func__, __LINE__, status);
+		return -EAGAIN;
+	}
+	if ((status != I2C_STATUS_START) &&
+	    (status != I2C_STATUS_REPEATED_START)) {
+		ERROR("Got status %x after enable start bit.\n", status);
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+static int mentor_i2c_stop_bit_set(void)
+{
+	int timeout;
+	uint32_t status;
+
+	/* Generate stop bit */
+	mmio_write_32((uintptr_t)&base->control,
+		      mmio_read_32((uintptr_t)&base->control) |
+		      I2C_CONTROL_STOP);
+	mentor_i2c_interrupt_clear();
+
+	timeout = 0;
+	/* Read control register, check the control stop bit */
+	while ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) &&
+	       (timeout++ < I2C_TIMEOUT_VALUE))
+		;
+	if (timeout >= I2C_TIMEOUT_VALUE) {
+		ERROR("Stop bit didn't went down\n");
+		return -ETIMEDOUT;
+	}
+
+	/* check that stop bit went down */
+	if ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) != 0) {
+		ERROR("Stop bit didn't went down\n");
+		return -EPERM;
+	}
+
+	/* check the status */
+	if (mentor_i2c_lost_arbitration(&status)) {
+		ERROR("%s - %d: Lost arbitration, got status %x\n",
+		      __func__, __LINE__, status);
+		return -EAGAIN;
+	}
+	if (status != I2C_STATUS_IDLE) {
+		ERROR("Got status %x after enable stop bit.\n", status);
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+static int mentor_i2c_address_set(uint8_t chain, int command)
+{
+	uint32_t reg, status;
+
+	reg = (chain << I2C_DATA_ADDR_7BIT_OFFS) & I2C_DATA_ADDR_7BIT_MASK;
+	reg |= command;
+	mmio_write_32((uintptr_t)&base->data, reg);
+	udelay(1);
+
+	mentor_i2c_interrupt_clear();
+
+	if (mentor_i2c_wait_interrupt()) {
+		ERROR("Start clear bit timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	/* check the status */
+	if (mentor_i2c_lost_arbitration(&status)) {
+		ERROR("%s - %d: Lost arbitration, got status %x\n",
+		      __func__, __LINE__, status);
+		return -EAGAIN;
+	}
+	if (((status != I2C_STATUS_ADDR_R_ACK) && (command == I2C_CMD_READ)) ||
+	   ((status != I2C_STATUS_ADDR_W_ACK) && (command == I2C_CMD_WRITE))) {
+		/* only in debug, since in boot we try to read the SPD
+		 * of both DRAM, and we don't want error messages in cas
+		 * DIMM doesn't exist.
+		 */
+		INFO("%s: ERROR - status %x addr in %s mode.\n", __func__,
+		     status, (command == I2C_CMD_WRITE) ? "Write" : "Read");
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+/*
+ * The I2C module contains a clock divider to generate the SCL clock.
+ * This function calculates and sets the <N> and <M> fields in the I2C Baud
+ * Rate Register (t=01) to obtain given 'requested_speed'.
+ * The requested_speed will be equal to:
+ * CONFIG_SYS_TCLK / (10 * (M + 1) * (2 << N))
+ * Where M is the value represented by bits[6:3] and N is the value represented
+ * by bits[2:0] of "I2C Baud Rate Register".
+ * Therefore max M which can be set is 16 (2^4) and max N is 8 (2^3). So the
+ * lowest possible baudrate is:
+ * CONFIG_SYS_TCLK/(10 * (16 +1) * (2 << 8), which equals to:
+ * CONFIG_SYS_TCLK/87040. Assuming that CONFIG_SYS_TCLK=250MHz, the lowest
+ * possible frequency is ~2,872KHz.
+ */
+static unsigned int mentor_i2c_bus_speed_set(unsigned int requested_speed)
+{
+	unsigned int n, m, freq, margin, min_margin = 0xffffffff;
+	unsigned int actual_n = 0, actual_m = 0;
+	int val;
+
+	/* Calculate N and M for the TWSI clock baud rate */
+	for (n = 0; n < 8; n++) {
+		for (m = 0; m < 16; m++) {
+			freq = CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n));
+			val = requested_speed - freq;
+			margin = (val > 0) ? val : -val;
+
+			if ((freq <= requested_speed) &&
+			    (margin < min_margin)) {
+				min_margin = margin;
+				actual_n = n;
+				actual_m = m;
+			}
+		}
+	}
+	VERBOSE("%s: actual_n = %u, actual_m = %u\n",
+		__func__, actual_n, actual_m);
+	/* Set the baud rate */
+	mmio_write_32((uintptr_t)&base->baudrate, (actual_m << 3) | actual_n);
+
+	return 0;
+}
+
+#ifdef DEBUG_I2C
+static int mentor_i2c_probe(uint8_t chip)
+{
+	int ret = 0;
+
+	ret = mentor_i2c_start_bit_set();
+	if (ret != 0) {
+		mentor_i2c_stop_bit_set();
+		ERROR("%s - %d: %s", __func__, __LINE__,
+		      "mentor_i2c_start_bit_set failed\n");
+		return -EPERM;
+	}
+
+	ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
+	if (ret != 0) {
+		mentor_i2c_stop_bit_set();
+		ERROR("%s - %d: %s", __func__, __LINE__,
+		      "mentor_i2c_address_set failed\n");
+		return -EPERM;
+	}
+
+	mentor_i2c_stop_bit_set();
+
+	VERBOSE("%s: successful I2C probe\n", __func__);
+
+	return ret;
+}
+#endif
+
+/* regular i2c transaction */
+static int mentor_i2c_data_receive(uint8_t *p_block, uint32_t block_size)
+{
+	uint32_t reg, status, block_size_read = block_size;
+
+	/* Wait for cause interrupt */
+	if (mentor_i2c_wait_interrupt()) {
+		ERROR("Start clear bit timeout\n");
+		return -ETIMEDOUT;
+	}
+	while (block_size_read) {
+		if (block_size_read == 1) {
+			reg = mmio_read_32((uintptr_t)&base->control);
+			reg &= ~(I2C_CONTROL_ACK);
+			mmio_write_32((uintptr_t)&base->control, reg);
+		}
+		mentor_i2c_interrupt_clear();
+
+		if (mentor_i2c_wait_interrupt()) {
+			ERROR("Start clear bit timeout\n");
+			return -ETIMEDOUT;
+		}
+		/* check the status */
+		if (mentor_i2c_lost_arbitration(&status)) {
+			ERROR("%s - %d: Lost arbitration, got status %x\n",
+			      __func__, __LINE__, status);
+			return -EAGAIN;
+		}
+		if ((status != I2C_STATUS_DATA_R_ACK) &&
+		    (block_size_read != 1)) {
+			ERROR("Status %x in read transaction\n", status);
+			return -EPERM;
+		}
+		if ((status != I2C_STATUS_DATA_R_NAK) &&
+		    (block_size_read == 1)) {
+			ERROR("Status %x in Rd Terminate\n", status);
+			return -EPERM;
+		}
+
+		/* read the data */
+		*p_block = (uint8_t) mmio_read_32((uintptr_t)&base->data);
+		VERBOSE("%s: place %d read %x\n", __func__,
+			block_size - block_size_read, *p_block);
+		p_block++;
+		block_size_read--;
+	}
+
+	return 0;
+}
+
+static int mentor_i2c_data_transmit(uint8_t *p_block, uint32_t block_size)
+{
+	uint32_t status, block_size_write = block_size;
+
+	if (mentor_i2c_wait_interrupt()) {
+		ERROR("Start clear bit timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	while (block_size_write) {
+		/* write the data */
+		mmio_write_32((uintptr_t)&base->data, (uint32_t) *p_block);
+		VERBOSE("%s: index = %d, data = %x\n", __func__,
+			block_size - block_size_write, *p_block);
+		p_block++;
+		block_size_write--;
+
+		mentor_i2c_interrupt_clear();
+
+		if (mentor_i2c_wait_interrupt()) {
+			ERROR("Start clear bit timeout\n");
+			return -ETIMEDOUT;
+		}
+
+		/* check the status */
+		if (mentor_i2c_lost_arbitration(&status)) {
+			ERROR("%s - %d: Lost arbitration, got status %x\n",
+			      __func__, __LINE__, status);
+			return -EAGAIN;
+		}
+		if (status != I2C_STATUS_DATA_W_ACK) {
+			ERROR("Status %x in write transaction\n", status);
+			return -EPERM;
+		}
+	}
+
+	return 0;
+}
+
+static int mentor_i2c_target_offset_set(uint8_t chip, uint32_t addr, int alen)
+{
+	uint8_t off_block[2];
+	uint32_t off_size;
+
+	if (alen == 2) { /* 2-byte addresses support */
+		off_block[0] = (addr >> 8) & 0xff;
+		off_block[1] = addr & 0xff;
+		off_size = 2;
+	} else { /* 1-byte addresses support */
+		off_block[0] = addr & 0xff;
+		off_size = 1;
+	}
+	VERBOSE("%s: off_size = %x addr1 = %x addr2 = %x\n", __func__,
+		off_size, off_block[0], off_block[1]);
+	return mentor_i2c_data_transmit(off_block, off_size);
+}
+
+#ifdef I2C_CAN_UNSTUCK
+static int mentor_i2c_unstuck(int ret)
+{
+	uint32_t v;
+
+	if (ret != -ETIMEDOUT)
+		return ret;
+	VERBOSE("Trying to \"unstuck i2c\"... ");
+	i2c_init(base);
+	mmio_write_32((uintptr_t)&base->unstuck, I2C_UNSTUCK_TRIGGER);
+	do {
+		v = mmio_read_32((uintptr_t)&base->unstuck);
+	} while (v & I2C_UNSTUCK_ONGOING);
+
+	if (v & I2C_UNSTUCK_ERROR) {
+		VERBOSE("failed - soft reset i2c\n");
+		ret = -EPERM;
+	} else {
+		VERBOSE("ok\n");
+		i2c_init(base);
+		ret = -EAGAIN;
+	}
+	return ret;
+}
+#else
+static int mentor_i2c_unstuck(int ret)
+{
+	VERBOSE("Cannot \"unstuck i2c\" - soft reset i2c\n");
+	return -EPERM;
+}
+#endif
+
+/*
+ * API Functions
+ */
+void i2c_init(void *i2c_base)
+{
+	/* For I2C speed and slave address, now we do not set them since
+	 * we just provide the working speed and slave address otherwhere
+	 * for i2c_init
+	 */
+	base = (struct mentor_i2c_regs *)i2c_base;
+
+	/* Reset the I2C logic */
+	mmio_write_32((uintptr_t)&base->soft_reset, 0);
+
+	udelay(200);
+
+	mentor_i2c_bus_speed_set(CONFIG_SYS_I2C_SPEED);
+
+	/* Enable the I2C and slave */
+	mmio_write_32((uintptr_t)&base->control,
+		      I2C_CONTROL_TWSIEN | I2C_CONTROL_ACK);
+
+	/* set the I2C slave address */
+	mmio_write_32((uintptr_t)&base->xtnd_slave_addr, 0);
+	mmio_write_32((uintptr_t)&base->slave_address, CONFIG_SYS_I2C_SLAVE);
+
+	/* unmask I2C interrupt */
+	mmio_write_32((uintptr_t)&base->control,
+		      mmio_read_32((uintptr_t)&base->control) |
+		      I2C_CONTROL_INTEN);
+
+	udelay(10);
+}
+
+/*
+ * i2c_read: - Read multiple bytes from an i2c device
+ *
+ * The higher level routines take into account that this function is only
+ * called with len < page length of the device (see configuration file)
+ *
+ * @chip:	address of the chip which is to be read
+ * @addr:	i2c data address within the chip
+ * @alen:	length of the i2c data address (1..2 bytes)
+ * @buffer:	where to write the data
+ * @len:	how much byte do we want to read
+ * @return:	0 in case of success
+ */
+int i2c_read(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
+{
+	int ret = 0;
+	uint32_t counter = 0;
+
+#ifdef DEBUG_I2C
+	mentor_i2c_probe(chip);
+#endif
+
+	do {
+		if (ret != -EAGAIN && ret) {
+			ERROR("i2c transaction failed, after %d retries\n",
+			      counter);
+			mentor_i2c_stop_bit_set();
+			return ret;
+		}
+
+		/* wait for 1 us for the interrupt clear to take effect */
+		if (counter > 0)
+			udelay(1);
+		counter++;
+
+		ret = mentor_i2c_start_bit_set();
+		if (ret) {
+			ret = mentor_i2c_unstuck(ret);
+			continue;
+		}
+
+		/* if EEPROM device */
+		if (alen != 0) {
+			ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
+			if (ret)
+				continue;
+
+			ret = mentor_i2c_target_offset_set(chip, addr, alen);
+			if (ret)
+				continue;
+			ret = mentor_i2c_start_bit_set();
+			if (ret)
+				continue;
+		}
+
+		ret =  mentor_i2c_address_set(chip, I2C_CMD_READ);
+		if (ret)
+			continue;
+
+		ret = mentor_i2c_data_receive(buffer, len);
+		if (ret)
+			continue;
+
+		ret =  mentor_i2c_stop_bit_set();
+	} while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
+
+	if (counter == I2C_MAX_RETRY_CNT) {
+		ERROR("I2C transactions failed, got EAGAIN %d times\n",
+		      I2C_MAX_RETRY_CNT);
+		ret = -EPERM;
+	}
+	mmio_write_32((uintptr_t)&base->control,
+		      mmio_read_32((uintptr_t)&base->control) |
+		      I2C_CONTROL_ACK);
+
+	udelay(1);
+	return ret;
+}
+
+/*
+ * i2c_write: -  Write multiple bytes to an i2c device
+ *
+ * The higher level routines take into account that this function is only
+ * called with len < page length of the device (see configuration file)
+ *
+ * @chip:	address of the chip which is to be written
+ * @addr:	i2c data address within the chip
+ * @alen:	length of the i2c data address (1..2 bytes)
+ * @buffer:	where to find the data to be written
+ * @len:	how much byte do we want to read
+ * @return:	0 in case of success
+ */
+int i2c_write(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len)
+{
+	int ret = 0;
+	uint32_t counter = 0;
+
+	do {
+		if (ret != -EAGAIN && ret) {
+			ERROR("i2c transaction failed\n");
+			mentor_i2c_stop_bit_set();
+			return ret;
+		}
+		/* wait for 1 us for the interrupt clear to take effect */
+		if (counter > 0)
+			udelay(1);
+		counter++;
+
+		ret = mentor_i2c_start_bit_set();
+		if (ret) {
+			ret = mentor_i2c_unstuck(ret);
+			continue;
+		}
+
+		ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE);
+		if (ret)
+			continue;
+
+		/* if EEPROM device */
+		if (alen != 0) {
+			ret = mentor_i2c_target_offset_set(chip, addr, alen);
+			if (ret)
+				continue;
+		}
+
+		ret = mentor_i2c_data_transmit(buffer, len);
+		if (ret)
+			continue;
+
+		ret = mentor_i2c_stop_bit_set();
+	} while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT));
+
+	if (counter == I2C_MAX_RETRY_CNT) {
+		ERROR("I2C transactions failed, got EAGAIN %d times\n",
+		      I2C_MAX_RETRY_CNT);
+		ret = -EPERM;
+	}
+
+	udelay(1);
+	return ret;
+}
diff --git a/include/drivers/marvell/a8k_i2c.h b/include/drivers/mentor/mi2cv.h
similarity index 84%
rename from include/drivers/marvell/a8k_i2c.h
rename to include/drivers/mentor/mi2cv.h
index 8a9abe8..6b03ed7 100644
--- a/include/drivers/marvell/a8k_i2c.h
+++ b/include/drivers/mentor/mi2cv.h
@@ -1,14 +1,15 @@
 /*
  * Copyright (C) 2018 Marvell International Ltd.
+ * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
  *
  * SPDX-License-Identifier:     BSD-3-Clause
  * https://spdx.org/licenses
  */
 
-/* This driver provides I2C support for Marvell A8K and compatible SoCs */
+/* This driver provides support for Mentor Graphics MI2CV IP core */
 
-#ifndef _A8K_I2C_H_
-#define _A8K_I2C_H_
+#ifndef _MI2CV_H_
+#define _MI2CV_H_
 
 #include <stdint.h>
 
diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h
index e5f5373..ce436d2 100644
--- a/include/plat/arm/board/common/v2m_def.h
+++ b/include/plat/arm/board/common/v2m_def.h
@@ -32,6 +32,9 @@
 #define V2M_FUNC_SHUTDOWN		0x08
 #define V2M_FUNC_REBOOT			0x09
 
+/* NVFLAGS in the V2M motherboard which is preserved after a watchdog reset */
+ #define V2M_SYS_NVFLAGS_ADDR		(V2M_SYSREGS_BASE + V2M_SYS_NVFLAGS)
+
 /*
  * V2M sysled bit definitions. The values written to this
  * register are defined in arch.h & runtime_svc.h. Only
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 0770c0e..53b4a45 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -245,6 +245,8 @@
 void plat_arm_interconnect_enter_coherency(void);
 void plat_arm_interconnect_exit_coherency(void);
 void plat_arm_program_trusted_mailbox(uintptr_t address);
+int plat_arm_bl1_fwu_needed(void);
+void plat_arm_error_handler(int err);
 
 #if ARM_PLAT_MT
 unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr);
diff --git a/lib/extensions/ras/std_err_record.c b/lib/extensions/ras/std_err_record.c
index 209cb73..9fdfd6b 100644
--- a/lib/extensions/ras/std_err_record.c
+++ b/lib/extensions/ras/std_err_record.c
@@ -56,7 +56,7 @@
 		((unsigned int) read_erridr_el1()) & ERRIDR_MASK;
 
 	assert(idx_start < max_idx);
-	assert(check_u32_overflow(idx_start, num_idx));
+	assert(check_u32_overflow(idx_start, num_idx) == 0);
 	assert((idx_start + num_idx - 1U) < max_idx);
 
 	for (i = 0; i < num_idx; i++) {
diff --git a/maintainers.rst b/maintainers.rst
index 969d5e5..3f64b83 100644
--- a/maintainers.rst
+++ b/maintainers.rst
@@ -24,6 +24,7 @@
 :G: `smaeul`_
 :F: docs/plat/allwinner.rst
 :F: plat/allwinner/
+:F: drivers/allwinner/
 
 Armv7-A architecture port
 -------------------------
diff --git a/plat/allwinner/common/sunxi_bl31_setup.c b/plat/allwinner/common/sunxi_bl31_setup.c
index 8ecf490..7e11cec 100644
--- a/plat/allwinner/common/sunxi_bl31_setup.c
+++ b/plat/allwinner/common/sunxi_bl31_setup.c
@@ -93,6 +93,8 @@
 
 	sunxi_security_setup();
 
+	sunxi_pmic_setup();
+
 	INFO("BL31: Platform setup done\n");
 }
 
diff --git a/plat/allwinner/common/sunxi_pm.c b/plat/allwinner/common/sunxi_pm.c
index 2a1f223..e4bb582 100644
--- a/plat/allwinner/common/sunxi_pm.c
+++ b/plat/allwinner/common/sunxi_pm.c
@@ -54,9 +54,7 @@
 	/* Turn off all secondary CPUs */
 	sunxi_disable_secondary_cpus(plat_my_core_pos());
 
-	ERROR("PSCI: Full shutdown not implemented, halting\n");
-	wfi();
-	panic();
+	sunxi_power_down();
 }
 
 static void __dead2 sunxi_system_reset(void)
diff --git a/plat/allwinner/common/sunxi_private.h b/plat/allwinner/common/sunxi_private.h
index e45f494..20fa23e 100644
--- a/plat/allwinner/common/sunxi_private.h
+++ b/plat/allwinner/common/sunxi_private.h
@@ -13,6 +13,10 @@
 void sunxi_disable_secondary_cpus(unsigned int primary_cpu);
 
 uint16_t sunxi_read_soc_id(void);
+
+void sunxi_pmic_setup(void);
 void sunxi_security_setup(void);
 
+void __dead2 sunxi_power_down(void);
+
 #endif /* __SUNXI_PRIVATE_H__ */
diff --git a/plat/allwinner/sun50i_a64/platform.mk b/plat/allwinner/sun50i_a64/platform.mk
index 236464f..e2868af 100644
--- a/plat/allwinner/sun50i_a64/platform.mk
+++ b/plat/allwinner/sun50i_a64/platform.mk
@@ -30,6 +30,7 @@
 				${AW_PLAT}/common/sunxi_bl31_setup.c	\
 				${AW_PLAT}/common/sunxi_cpu_ops.c	\
 				${AW_PLAT}/common/sunxi_pm.c		\
+				${AW_PLAT}/sun50i_a64/sunxi_power.c	\
 				${AW_PLAT}/common/sunxi_security.c	\
 				${AW_PLAT}/common/sunxi_topology.c
 
diff --git a/plat/allwinner/sun50i_a64/sunxi_power.c b/plat/allwinner/sun50i_a64/sunxi_power.c
new file mode 100644
index 0000000..c1907d6
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/sunxi_power.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <debug.h>
+
+int sunxi_pmic_setup(void)
+{
+	/* STUB */
+	NOTICE("BL31: STUB PMIC setup code called\n");
+
+	return 0;
+}
+
+void __dead2 sunxi_power_down(void)
+{
+	ERROR("PSCI: Full shutdown not implemented, halting\n");
+	wfi();
+	panic();
+}
diff --git a/plat/allwinner/sun50i_h6/platform.mk b/plat/allwinner/sun50i_h6/platform.mk
index c1b26fa..c3901d0 100644
--- a/plat/allwinner/sun50i_h6/platform.mk
+++ b/plat/allwinner/sun50i_h6/platform.mk
@@ -7,6 +7,7 @@
 include lib/xlat_tables_v2/xlat_tables.mk
 
 AW_PLAT			:=	plat/allwinner
+AW_DRIVERS		:=	drivers/allwinner
 
 PLAT_INCLUDES		:=	-Iinclude/plat/arm/common		\
 				-Iinclude/plat/arm/common/aarch64	\
@@ -15,6 +16,7 @@
 
 PLAT_BL_COMMON_SOURCES	:=	drivers/console/${ARCH}/console.S	\
 				drivers/ti/uart/${ARCH}/16550_console.S	\
+				${AW_DRIVERS}/sunxi_i2c.c		\
 				${XLAT_TABLES_LIB_SRCS}			\
 				${AW_PLAT}/common/plat_helpers.S	\
 				${AW_PLAT}/common/sunxi_common.c
@@ -30,6 +32,7 @@
 				${AW_PLAT}/common/sunxi_bl31_setup.c	\
 				${AW_PLAT}/common/sunxi_cpu_ops.c	\
 				${AW_PLAT}/common/sunxi_pm.c		\
+				${AW_PLAT}/sun50i_h6/sunxi_power.c	\
 				${AW_PLAT}/common/sunxi_security.c	\
 				${AW_PLAT}/common/sunxi_topology.c
 
diff --git a/plat/allwinner/sun50i_h6/sunxi_power.c b/plat/allwinner/sun50i_h6/sunxi_power.c
new file mode 100644
index 0000000..f109cce
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/sunxi_power.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018, Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <debug.h>
+#include <delay_timer.h>
+#include <errno.h>
+#include <mmio.h>
+#include <mentor/mi2cv.h>
+#include <string.h>
+#include <sunxi_mmap.h>
+
+#define AXP805_ADDR	0x36
+#define AXP805_ID	0x03
+
+enum pmic_type {
+	NO_PMIC,
+	AXP805,
+};
+
+enum pmic_type pmic;
+
+static int sunxi_init_r_i2c(void)
+{
+	uint32_t reg;
+
+	/* get currently configured function for pins PL0 and PL1 */
+	reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x00);
+	if ((reg & 0xff) == 0x33) {
+		NOTICE("PMIC: already configured for TWI\n");
+	}
+
+	/* switch pins PL0 and PL1 to I2C */
+	mmio_write_32(SUNXI_R_PIO_BASE + 0x00, (reg & ~0xff) | 0x33);
+
+	/* level 2 drive strength */
+	reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x14);
+	mmio_write_32(SUNXI_R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa);
+
+	/* set both ports to pull-up */
+	reg = mmio_read_32(SUNXI_R_PIO_BASE + 0x1c);
+	mmio_write_32(SUNXI_R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5);
+
+	/* assert & de-assert reset of R_I2C */
+	reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
+	mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, 0);
+	reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
+	mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00010000);
+
+	/* un-gate R_I2C clock */
+	reg = mmio_read_32(SUNXI_R_PRCM_BASE + 0x19c);
+	mmio_write_32(SUNXI_R_PRCM_BASE + 0x19c, reg | 0x00000001);
+
+	/* call mi2cv driver */
+	i2c_init((void *)SUNXI_R_I2C_BASE);
+
+	return 0;
+}
+
+int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
+{
+	int ret;
+
+	ret = i2c_write(chip, 0, 0, &reg, 1);
+	if (ret)
+		return ret;
+
+	return i2c_read(chip, 0, 0, val, 1);
+}
+
+int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
+{
+	return i2c_write(chip, reg, 1, &val, 1);
+}
+
+static int axp805_probe(void)
+{
+	int ret;
+	uint8_t val;
+
+	ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
+	if (ret) {
+		ERROR("PMIC: Cannot put AXP805 to master mode.\n");
+		return -EPERM;
+	}
+
+	ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
+
+	if (!ret && ((val & 0xcf) == 0x40))
+		NOTICE("PMIC: AXP805 detected\n");
+	else if (ret) {
+		ERROR("PMIC: Cannot communicate with AXP805.\n");
+		return -EPERM;
+	} else {
+		ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int sunxi_pmic_setup(void)
+{
+	int ret;
+
+	sunxi_init_r_i2c();
+
+	NOTICE("PMIC: Probing AXP805\n");
+	pmic = AXP805;
+
+	ret = axp805_probe();
+	if (ret)
+		pmic = NO_PMIC;
+	else
+		pmic = AXP805;
+
+	return 0;
+}
+
+void __dead2 sunxi_power_down(void)
+{
+	uint8_t val;
+
+	switch (pmic) {
+	case AXP805:
+		val = 0x26; /* Default value for REG 32H */
+		axp_i2c_read(AXP805_ADDR, 0x32, &val);
+		val |= 0x80;
+		axp_i2c_write(AXP805_ADDR, 0x32, val);
+		break;
+	default:
+		break;
+	}
+
+	udelay(1000);
+	ERROR("PSCI: Cannot communicate with PMIC, halting\n");
+	wfi();
+	panic();
+}
diff --git a/plat/arm/board/juno/juno_bl1_setup.c b/plat/arm/board/juno/juno_bl1_setup.c
index 836a672..3dd2a22 100644
--- a/plat/arm/board/juno/juno_bl1_setup.c
+++ b/plat/arm/board/juno/juno_bl1_setup.c
@@ -5,15 +5,72 @@
  */
 
 #include <bl_common.h>
+#include <debug.h>
 #include <errno.h>
 #include <plat_arm.h>
 #include <platform.h>
+#include <sds.h>
 #include <sp805.h>
 #include <tbbr_img_def.h>
 #include <v2m_def.h>
 
 void juno_reset_to_aarch32_state(void);
 
+static int is_watchdog_reset(void)
+{
+#if !CSS_USE_SCMI_SDS_DRIVER
+	#define RESET_REASON_WDOG_RESET		(0x2)
+	const uint32_t *reset_flags_ptr = (const uint32_t *)SSC_GPRETN;
+
+	if ((*reset_flags_ptr & RESET_REASON_WDOG_RESET) != 0)
+		return 1;
+
+	return 0;
+#else
+	int ret;
+	uint32_t scp_reset_synd_flags;
+
+	ret = sds_init();
+	if (ret != SDS_OK) {
+		ERROR("SCP SDS initialization failed\n");
+		panic();
+	}
+
+	ret = sds_struct_read(SDS_RESET_SYNDROME_STRUCT_ID,
+					SDS_RESET_SYNDROME_OFFSET,
+					&scp_reset_synd_flags,
+					SDS_RESET_SYNDROME_SIZE,
+					SDS_ACCESS_MODE_NON_CACHED);
+	if (ret != SDS_OK) {
+		ERROR("Getting reset reason from SDS failed\n");
+		panic();
+	}
+
+	/* Check if the WATCHDOG_RESET_BIT is set in the reset syndrome */
+	if (scp_reset_synd_flags & SDS_RESET_SYNDROME_AP_WD_RESET_BIT)
+		return 1;
+
+	return 0;
+#endif
+}
+
+/*******************************************************************************
+ * The following function checks if Firmware update is needed,
+ * by checking if TOC in FIP image is valid or watchdog reset happened.
+ ******************************************************************************/
+int plat_arm_bl1_fwu_needed(void)
+{
+	const uint32_t *nv_flags_ptr = (const uint32_t *)V2M_SYS_NVFLAGS_ADDR;
+
+	/* Check if TOC is invalid or watchdog reset happened. */
+	if ((arm_io_is_toc_valid() != 1) ||
+		(((*nv_flags_ptr == -EAUTH) || (*nv_flags_ptr == -ENOENT))
+		&& is_watchdog_reset()))
+		return 1;
+
+	return 0;
+}
+
 /*******************************************************************************
  * On JUNO update the arg2 with address of SCP_BL2U image info.
  ******************************************************************************/
diff --git a/plat/arm/board/juno/juno_err.c b/plat/arm/board/juno/juno_err.c
new file mode 100644
index 0000000..dd8e278
--- /dev/null
+++ b/plat/arm/board/juno/juno_err.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <errno.h>
+#include <platform.h>
+#include <v2m_def.h>
+
+/*
+ * Juno error handler
+ */
+void __dead2 plat_arm_error_handler(int err)
+{
+	uint32_t *flags_ptr = (uint32_t *)V2M_SYS_NVFLAGS_ADDR;
+
+	/* Propagate the err code in the NV-flags register */
+	*flags_ptr = err;
+
+	/* Loop until the watchdog resets the system */
+	for (;;)
+		wfi();
+}
diff --git a/plat/arm/board/juno/platform.mk b/plat/arm/board/juno/platform.mk
index 16390fa..481844f 100644
--- a/plat/arm/board/juno/platform.mk
+++ b/plat/arm/board/juno/platform.mk
@@ -22,7 +22,12 @@
 JUNO_SECURITY_SOURCES	+=	plat/arm/board/juno/juno_stack_protector.c
 endif
 
-PLAT_INCLUDES		:=	-Iplat/arm/board/juno/include
+# Select SCMI/SDS drivers instead of SCPI/BOM driver for communicating with the
+# SCP during power management operations and for SCP RAM Firmware transfer.
+CSS_USE_SCMI_SDS_DRIVER		:=	1
+
+PLAT_INCLUDES		:=	-Iplat/arm/board/juno/include		\
+				-Iplat/arm/css/drivers/sds
 
 PLAT_BL_COMMON_SOURCES	:=	plat/arm/board/juno/${ARCH}/juno_helpers.S
 
@@ -55,11 +60,13 @@
 BL1_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S		\
 				lib/cpus/aarch64/cortex_a57.S		\
 				lib/cpus/aarch64/cortex_a72.S		\
+				plat/arm/board/juno/juno_err.c		\
 				plat/arm/board/juno/juno_bl1_setup.c	\
 				${JUNO_INTERCONNECT_SOURCES}		\
 				${JUNO_SECURITY_SOURCES}
 
 BL2_SOURCES		+=	lib/utils/mem_region.c			\
+				plat/arm/board/juno/juno_err.c		\
 				plat/arm/board/juno/juno_bl2_setup.c	\
 				plat/arm/common/arm_nor_psci_mem_protect.c \
 				${JUNO_SECURITY_SOURCES}
@@ -76,8 +83,13 @@
 				${JUNO_GIC_SOURCES}			\
 				${JUNO_INTERCONNECT_SOURCES}		\
 				${JUNO_SECURITY_SOURCES}
+
+ifeq (${CSS_USE_SCMI_SDS_DRIVER},1)
+BL1_SOURCES		+=	plat/arm/css/drivers/sds/sds.c
 endif
 
+endif
+
 # Errata workarounds for Cortex-A53:
 ERRATA_A53_826319		:=	1
 ERRATA_A53_835769		:=	1
@@ -112,10 +124,6 @@
 # Do not enable SVE
 ENABLE_SVE_FOR_NS		:=	0
 
-# Select SCMI/SDS drivers instead of SCPI/BOM driver for communicating with the
-# SCP during power management operations and for SCP RAM Firmware transfer.
-CSS_USE_SCMI_SDS_DRIVER		:=	1
-
 include plat/arm/board/common/board_css.mk
 include plat/arm/common/arm_common.mk
 include plat/arm/soc/common/soc_css.mk
diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c
index a4d2b44..d9104ee 100644
--- a/plat/arm/common/arm_bl1_setup.c
+++ b/plat/arm/common/arm_bl1_setup.c
@@ -23,6 +23,8 @@
 #pragma weak bl1_platform_setup
 #pragma weak bl1_plat_sec_mem_layout
 #pragma weak bl1_plat_prepare_exit
+#pragma weak bl1_plat_get_next_image_id
+#pragma weak plat_arm_bl1_fwu_needed
 
 #define MAP_BL1_TOTAL		MAP_REGION_FLAT(			\
 					bl1_tzram_layout.total_base,	\
@@ -186,13 +188,22 @@
 #endif
 }
 
+/*
+ * On Arm platforms, the FWU process is triggered when the FIP image has
+ * been tampered with.
+ */
+int plat_arm_bl1_fwu_needed(void)
+{
+	return (arm_io_is_toc_valid() != 1);
+}
+
 /*******************************************************************************
  * The following function checks if Firmware update is needed,
  * by checking if TOC in FIP image is valid or not.
  ******************************************************************************/
 unsigned int bl1_plat_get_next_image_id(void)
 {
-	if (!arm_io_is_toc_valid())
+	if (plat_arm_bl1_fwu_needed() != 0)
 		return NS_BL1U_IMAGE_ID;
 
 	return BL2_IMAGE_ID;
diff --git a/plat/arm/common/arm_err.c b/plat/arm/common/arm_err.c
index 66568e7..e13e51f 100644
--- a/plat/arm/common/arm_err.c
+++ b/plat/arm/common/arm_err.c
@@ -13,10 +13,12 @@
 #include <platform_def.h>
 #include <stdint.h>
 
+#pragma weak plat_arm_error_handler
+
 /*
  * ARM common implementation for error handler
  */
-void plat_error_handler(int err)
+void __dead2 plat_arm_error_handler(int err)
 {
 	int ret;
 
@@ -44,3 +46,8 @@
 	for (;;)
 		wfi();
 }
+
+void __dead2 plat_error_handler(int err)
+{
+	plat_arm_error_handler(err);
+}
diff --git a/plat/arm/css/common/css_common.mk b/plat/arm/css/common/css_common.mk
index 29dd01d..984c1da 100644
--- a/plat/arm/css/common/css_common.mk
+++ b/plat/arm/css/common/css_common.mk
@@ -85,3 +85,12 @@
 # Process CSS_USE_SCMI_SDS_DRIVER flag
 $(eval $(call assert_boolean,CSS_USE_SCMI_SDS_DRIVER))
 $(eval $(call add_define,CSS_USE_SCMI_SDS_DRIVER))
+
+# Process CSS_NON_SECURE_UART flag
+# This undocumented build option is only to enable debug access to the UART
+# from non secure code, which is useful on some platforms.
+# Default (obviously) is off.
+CSS_NON_SECURE_UART		:= 0
+$(eval $(call assert_boolean,CSS_NON_SECURE_UART))
+$(eval $(call add_define,CSS_NON_SECURE_UART))
+
diff --git a/plat/arm/soc/common/soc_css_security.c b/plat/arm/soc/common/soc_css_security.c
index 19bd76f..f229679 100644
--- a/plat/arm/soc/common/soc_css_security.c
+++ b/plat/arm/soc/common/soc_css_security.c
@@ -23,7 +23,7 @@
 
 	/*
 	 * Allow non-secure access to some SOC regions, excluding UART1, which
-	 * remains secure.
+	 * remains secure (unless CSS_NON_SECURE_UART is set).
 	 * Note: This is the NIC-400 device on the SOC
 	 */
 	mmio_write_32(SOC_CSS_NIC400_BASE +
@@ -36,9 +36,15 @@
 		NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_PL354_SMC), ~0);
 	mmio_write_32(SOC_CSS_NIC400_BASE +
 		NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_APB4_BRIDGE), ~0);
+#if  CSS_NON_SECURE_UART
+	/* Configure UART for non-secure access */
+	mmio_write_32(SOC_CSS_NIC400_BASE +
+		NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_BOOTSEC_BRIDGE), ~0);
+#else
 	mmio_write_32(SOC_CSS_NIC400_BASE +
 		NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_BOOTSEC_BRIDGE),
 		~SOC_CSS_NIC400_BOOTSEC_BRIDGE_UART1);
+#endif /* CSS_NON_SECURE_UART */
 
 }
 
diff --git a/plat/hisilicon/hikey960/hikey960_io_storage.c b/plat/hisilicon/hikey960/hikey960_io_storage.c
index be7c941..cff3b0d 100644
--- a/plat/hisilicon/hikey960/hikey960_io_storage.c
+++ b/plat/hisilicon/hikey960/hikey960_io_storage.c
@@ -76,6 +76,44 @@
 	.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
 };
 
+#if TRUSTED_BOARD_BOOT
+static const io_uuid_spec_t trusted_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_KEY_CERT,
+};
+
+static const io_uuid_spec_t scp_fw_key_cert_uuid_spec = {
+	.uuid = UUID_SCP_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
+};
+
+static const io_uuid_spec_t scp_fw_cert_uuid_spec = {
+	.uuid = UUID_SCP_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t soc_fw_cert_uuid_spec = {
+	.uuid = UUID_SOC_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t tos_fw_cert_uuid_spec = {
+	.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
+};
+
+static const io_uuid_spec_t nt_fw_cert_uuid_spec = {
+	.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
+};
+#endif /* TRUSTED_BOARD_BOOT */
+
 static const struct plat_io_policy policies[] = {
 	[FIP_IMAGE_ID] = {
 		&ufs_dev_handle,
@@ -111,7 +149,54 @@
 		&fip_dev_handle,
 		(uintptr_t)&bl33_uuid_spec,
 		check_fip
-	}
+	},
+#if TRUSTED_BOARD_BOOT
+	[TRUSTED_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&trusted_key_cert_uuid_spec,
+		check_fip
+	},
+	[SCP_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[SOC_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[TRUSTED_OS_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[NON_TRUSTED_FW_KEY_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_key_cert_uuid_spec,
+		check_fip
+	},
+	[SCP_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&scp_fw_cert_uuid_spec,
+		check_fip
+	},
+	[SOC_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&soc_fw_cert_uuid_spec,
+		check_fip
+	},
+	[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&tos_fw_cert_uuid_spec,
+		check_fip
+	},
+	[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&nt_fw_cert_uuid_spec,
+		check_fip
+	},
+#endif /* TRUSTED_BOARD_BOOT */
 };
 
 static int check_ufs(const uintptr_t spec)
diff --git a/plat/hisilicon/hikey960/hikey960_rotpk.S b/plat/hisilicon/hikey960/hikey960_rotpk.S
new file mode 100644
index 0000000..f230ed6
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_rotpk.S
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+	.global hikey960_rotpk_hash
+	.global hikey960_rotpk_hash_end
+	.section .rodata.hikey960_rotpk_hash, "a"
+hikey960_rotpk_hash:
+	/* DER header */
+	.byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48
+	.byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+	/* SHA256 */
+	.incbin ROTPK_HASH
+hikey960_rotpk_hash_end:
diff --git a/plat/hisilicon/hikey960/hikey960_tbbr.c b/plat/hisilicon/hikey960/hikey960_tbbr.c
new file mode 100644
index 0000000..e9f28b3
--- /dev/null
+++ b/plat/hisilicon/hikey960/hikey960_tbbr.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform.h>
+
+extern char hikey960_rotpk_hash[], hikey960_rotpk_hash_end[];
+
+int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
+			unsigned int *flags)
+{
+	*key_ptr = hikey960_rotpk_hash;
+	*key_len = hikey960_rotpk_hash_end - hikey960_rotpk_hash;
+	*flags = ROTPK_IS_HASH;
+
+	return 0;
+}
+
+int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
+{
+	*nv_ctr = 0;
+
+	return 0;
+}
+
+int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
+{
+	return 1;
+}
diff --git a/plat/hisilicon/hikey960/include/platform_def.h b/plat/hisilicon/hikey960/include/platform_def.h
index 5a6021a..40304eb 100644
--- a/plat/hisilicon/hikey960/include/platform_def.h
+++ b/plat/hisilicon/hikey960/include/platform_def.h
@@ -19,7 +19,7 @@
  */
 
 /* Size of cacheable stacks */
-#define PLATFORM_STACK_SIZE		0x800
+#define PLATFORM_STACK_SIZE		0x1000
 
 #define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
 
@@ -49,8 +49,8 @@
  * BL1 specific defines.
  */
 #define BL1_RO_BASE			(0x1AC00000)
-#define BL1_RO_LIMIT			(BL1_RO_BASE + 0x10000)
-#define BL1_RW_BASE			(BL1_RO_LIMIT)		/* 1AC1_0000 */
+#define BL1_RO_LIMIT			(BL1_RO_BASE + 0x20000)
+#define BL1_RW_BASE			(BL1_RO_LIMIT)		/* 1AC2_0000 */
 #define BL1_RW_SIZE			(0x00188000)
 #define BL1_RW_LIMIT			(0x1B000000)
 
@@ -104,7 +104,7 @@
 #define NS_BL1U_SIZE			(0x00100000)
 #define NS_BL1U_LIMIT			(NS_BL1U_BASE + NS_BL1U_SIZE)
 
-#define HIKEY960_NS_IMAGE_OFFSET	(0x1AC18000)	/* offset in l-loader */
+#define HIKEY960_NS_IMAGE_OFFSET	(0x1AC28000)	/* offset in l-loader */
 #define HIKEY960_NS_TMP_OFFSET		(0x1AE00000)
 
 #define SCP_BL2_BASE			(0x89C80000)
diff --git a/plat/hisilicon/hikey960/platform.mk b/plat/hisilicon/hikey960/platform.mk
index 5fa7218..6f3a403 100644
--- a/plat/hisilicon/hikey960/platform.mk
+++ b/plat/hisilicon/hikey960/platform.mk
@@ -108,6 +108,46 @@
 				plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c \
 				${HIKEY960_GIC_SOURCES}
 
+ifneq (${TRUSTED_BOARD_BOOT},0)
+
+include drivers/auth/mbedtls/mbedtls_crypto.mk
+include drivers/auth/mbedtls/mbedtls_x509.mk
+
+USE_TBBR_DEFS		:=	1
+
+AUTH_SOURCES		:=	drivers/auth/auth_mod.c			\
+				drivers/auth/crypto_mod.c		\
+				drivers/auth/img_parser_mod.c		\
+				drivers/auth/tbbr/tbbr_cot.c
+
+BL1_SOURCES		+=	${AUTH_SOURCES}				\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/hisilicon/hikey960/hikey960_tbbr.c	\
+				plat/hisilicon/hikey960/hikey960_rotpk.S
+
+BL2_SOURCES		+=	${AUTH_SOURCES}				\
+				plat/common/tbbr/plat_tbbr.c		\
+				plat/hisilicon/hikey960/hikey960_tbbr.c	\
+				plat/hisilicon/hikey960/hikey960_rotpk.S
+
+ROT_KEY		=	$(BUILD_PLAT)/rot_key.pem
+ROTPK_HASH		=	$(BUILD_PLAT)/rotpk_sha256.bin
+
+$(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"'))
+$(BUILD_PLAT)/bl1/hikey960_rotpk.o: $(ROTPK_HASH)
+$(BUILD_PLAT)/bl2/hikey960_rotpk.o: $(ROTPK_HASH)
+
+certificates: $(ROT_KEY)
+$(ROT_KEY): | $(BUILD_PLAT)
+	@echo "  OPENSSL $@"
+	$(Q)openssl genrsa 2048 > $@ 2>/dev/null
+
+$(ROTPK_HASH): $(ROT_KEY)
+	@echo "  OPENSSL $@"
+	$(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\
+	openssl dgst -sha256 -binary > $@ 2>/dev/null
+endif
+
 # Enable workarounds for selected Cortex-A53 errata.
 ERRATA_A53_836870		:=	1
 ERRATA_A53_843419		:=	1
diff --git a/plat/marvell/a8k/a80x0/board/dram_port.c b/plat/marvell/a8k/a80x0/board/dram_port.c
index c720c11..a99bf7c 100644
--- a/plat/marvell/a8k/a80x0/board/dram_port.c
+++ b/plat/marvell/a8k/a80x0/board/dram_port.c
@@ -6,8 +6,8 @@
  */
 
 #include <arch_helpers.h>
-#include <a8k_i2c.h>
 #include <debug.h>
+#include <mentor/mi2cv.h>
 #include <mmio.h>
 #include <mv_ddr_if.h>
 #include <mvebu_def.h>
diff --git a/plat/marvell/a8k/a80x0_mcbin/board/dram_port.c b/plat/marvell/a8k/a80x0_mcbin/board/dram_port.c
index b455b83..fa222ee 100644
--- a/plat/marvell/a8k/a80x0_mcbin/board/dram_port.c
+++ b/plat/marvell/a8k/a80x0_mcbin/board/dram_port.c
@@ -6,8 +6,8 @@
  */
 
 #include <arch_helpers.h>
-#include <a8k_i2c.h>
 #include <debug.h>
+#include <mentor/mi2cv.h>
 #include <mmio.h>
 #include <mv_ddr_if.h>
 #include <mvebu_def.h>