Merge pull request #614 from soby-mathew/sm/rem_fvp_ve_memmap

FVP: Remove VE memory map support and change default GIC driver
diff --git a/docs/porting-guide.md b/docs/porting-guide.md
index 0d713c4..5004d30 100644
--- a/docs/porting-guide.md
+++ b/docs/porting-guide.md
@@ -76,8 +76,8 @@
 A platform port must enable the Memory Management Unit (MMU) as well as the
 instruction and data caches for each BL stage. Setting up the translation
 tables is the responsibility of the platform port because memory maps differ
-across platforms. A memory translation library (see `lib/aarch64/xlat_tables.c`)
-is provided to help in this setup. Note that although this library supports
+across platforms. A memory translation library (see `lib/xlat_tables/`) is
+provided to help in this setup. Note that although this library supports
 non-identity mappings, this is intended only for re-mapping peripheral physical
 addresses and allows platforms with high I/O addresses to reduce their virtual
 address space. All other addresses corresponding to code and data must currently
@@ -448,6 +448,14 @@
     Defines the maximum number of open IO handles. Attempting to open more IO
     entities than this value using `io_open()` will fail with -ENOMEM.
 
+*   **#define : MAX_IO_BLOCK_DEVICES**
+
+    Defines the maximum number of registered IO block devices. Attempting to
+    register more devices this value using `io_dev_open()` will fail
+    with -ENOMEM. MAX_IO_BLOCK_DEVICES should be less than MAX_IO_DEVICES.
+    With this macro, multiple block devices could be supported at the same
+    time.
+
 If the platform needs to allocate data within the per-cpu data framework in
 BL31, it should define the following macro. Currently this is only required if
 the platform decides not to use the coherent memory section by undefining the
diff --git a/drivers/emmc/emmc.c b/drivers/emmc/emmc.c
new file mode 100644
index 0000000..5fe28ef
--- /dev/null
+++ b/drivers/emmc/emmc.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Defines a simple and generic interface to access eMMC device.
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <emmc.h>
+#include <errno.h>
+#include <string.h>
+
+static const emmc_ops_t *ops;
+static unsigned int emmc_ocr_value;
+static emmc_csd_t emmc_csd;
+
+static int emmc_device_state(void)
+{
+	emmc_cmd_t cmd;
+	int ret;
+
+	do {
+		memset(&cmd, 0, sizeof(emmc_cmd_t));
+		cmd.cmd_idx = EMMC_CMD13;
+		cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
+		cmd.resp_type = EMMC_RESPONSE_R1;
+		ret = ops->send_cmd(&cmd);
+		assert(ret == 0);
+		assert((cmd.resp_data[0] & STATUS_SWITCH_ERROR) == 0);
+		/* Ignore improbable errors in release builds */
+		(void)ret;
+	} while ((cmd.resp_data[0] & STATUS_READY_FOR_DATA) == 0);
+	return EMMC_GET_STATE(cmd.resp_data[0]);
+}
+
+static void emmc_set_ext_csd(unsigned int ext_cmd, unsigned int value)
+{
+	emmc_cmd_t cmd;
+	int ret, state;
+
+	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	cmd.cmd_idx = EMMC_CMD6;
+	cmd.cmd_arg = EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) |
+		      EXTCSD_VALUE(value) | 1;
+	ret = ops->send_cmd(&cmd);
+	assert(ret == 0);
+
+	/* wait to exit PRG state */
+	do {
+		state = emmc_device_state();
+	} while (state == EMMC_STATE_PRG);
+	/* Ignore improbable errors in release builds */
+	(void)ret;
+}
+
+static void emmc_set_ios(int clk, int bus_width)
+{
+	int ret;
+
+	/* set IO speed & IO bus width */
+	if (emmc_csd.spec_vers == 4)
+		emmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH, bus_width);
+	ret = ops->set_ios(clk, bus_width);
+	assert(ret == 0);
+	/* Ignore improbable errors in release builds */
+	(void)ret;
+}
+
+static int emmc_enumerate(int clk, int bus_width)
+{
+	emmc_cmd_t cmd;
+	int ret, state;
+
+	ops->init();
+
+	/* CMD0: reset to IDLE */
+	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	cmd.cmd_idx = EMMC_CMD0;
+	ret = ops->send_cmd(&cmd);
+	assert(ret == 0);
+
+	while (1) {
+		/* CMD1: get OCR register */
+		memset(&cmd, 0, sizeof(emmc_cmd_t));
+		cmd.cmd_idx = EMMC_CMD1;
+		cmd.cmd_arg = OCR_SECTOR_MODE | OCR_VDD_MIN_2V7 |
+			      OCR_VDD_MIN_1V7;
+		cmd.resp_type = EMMC_RESPONSE_R3;
+		ret = ops->send_cmd(&cmd);
+		assert(ret == 0);
+		emmc_ocr_value = cmd.resp_data[0];
+		if (emmc_ocr_value & OCR_POWERUP)
+			break;
+	}
+
+	/* CMD2: Card Identification */
+	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	cmd.cmd_idx = EMMC_CMD2;
+	cmd.resp_type = EMMC_RESPONSE_R2;
+	ret = ops->send_cmd(&cmd);
+	assert(ret == 0);
+
+	/* CMD3: Set Relative Address */
+	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	cmd.cmd_idx = EMMC_CMD3;
+	cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
+	cmd.resp_type = EMMC_RESPONSE_R1;
+	ret = ops->send_cmd(&cmd);
+	assert(ret == 0);
+
+	/* CMD9: CSD Register */
+	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	cmd.cmd_idx = EMMC_CMD9;
+	cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
+	cmd.resp_type = EMMC_RESPONSE_R2;
+	ret = ops->send_cmd(&cmd);
+	assert(ret == 0);
+	memcpy(&emmc_csd, &cmd.resp_data, sizeof(cmd.resp_data));
+
+	/* CMD7: Select Card */
+	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	cmd.cmd_idx = EMMC_CMD7;
+	cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET;
+	cmd.resp_type = EMMC_RESPONSE_R1;
+	ret = ops->send_cmd(&cmd);
+	assert(ret == 0);
+	/* wait to TRAN state */
+	do {
+		state = emmc_device_state();
+	} while (state != EMMC_STATE_TRAN);
+
+	emmc_set_ios(clk, bus_width);
+	return ret;
+}
+
+size_t emmc_read_blocks(int lba, uintptr_t buf, size_t size)
+{
+	emmc_cmd_t cmd;
+	int ret;
+
+	assert((ops != 0) &&
+	       (ops->read != 0) &&
+	       ((buf & EMMC_BLOCK_MASK) == 0) &&
+	       ((size & EMMC_BLOCK_MASK) == 0));
+
+	inv_dcache_range(buf, size);
+	ret = ops->prepare(lba, buf, size);
+	assert(ret == 0);
+
+	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	if (size > EMMC_BLOCK_SIZE)
+		cmd.cmd_idx = EMMC_CMD18;
+	else
+		cmd.cmd_idx = EMMC_CMD17;
+	if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE)
+		cmd.cmd_arg = lba * EMMC_BLOCK_SIZE;
+	else
+		cmd.cmd_arg = lba;
+	cmd.resp_type = EMMC_RESPONSE_R1;
+	ret = ops->send_cmd(&cmd);
+	assert(ret == 0);
+
+	ret = ops->read(lba, buf, size);
+	assert(ret == 0);
+
+	/* wait buffer empty */
+	emmc_device_state();
+
+	if (size > EMMC_BLOCK_SIZE) {
+		memset(&cmd, 0, sizeof(emmc_cmd_t));
+		cmd.cmd_idx = EMMC_CMD12;
+		ret = ops->send_cmd(&cmd);
+		assert(ret == 0);
+	}
+	/* Ignore improbable errors in release builds */
+	(void)ret;
+	return size;
+}
+
+size_t emmc_write_blocks(int lba, const uintptr_t buf, size_t size)
+{
+	emmc_cmd_t cmd;
+	int ret;
+
+	assert((ops != 0) &&
+	       (ops->write != 0) &&
+	       ((buf & EMMC_BLOCK_MASK) == 0) &&
+	       ((size & EMMC_BLOCK_MASK) == 0));
+
+	clean_dcache_range(buf, size);
+	ret = ops->prepare(lba, buf, size);
+	assert(ret == 0);
+
+	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	if (size > EMMC_BLOCK_SIZE)
+		cmd.cmd_idx = EMMC_CMD25;
+	else
+		cmd.cmd_idx = EMMC_CMD24;
+	if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE)
+		cmd.cmd_arg = lba * EMMC_BLOCK_SIZE;
+	else
+		cmd.cmd_arg = lba;
+	cmd.resp_type = EMMC_RESPONSE_R1;
+	ret = ops->send_cmd(&cmd);
+	assert(ret == 0);
+
+	ret = ops->write(lba, buf, size);
+	assert(ret == 0);
+
+	/* wait buffer empty */
+	emmc_device_state();
+
+	if (size > EMMC_BLOCK_SIZE) {
+		memset(&cmd, 0, sizeof(emmc_cmd_t));
+		cmd.cmd_idx = EMMC_CMD12;
+		ret = ops->send_cmd(&cmd);
+		assert(ret == 0);
+	}
+	/* Ignore improbable errors in release builds */
+	(void)ret;
+	return size;
+}
+
+size_t emmc_erase_blocks(int lba, size_t size)
+{
+	emmc_cmd_t cmd;
+	int ret, state;
+
+	assert(ops != 0);
+	assert((size != 0) && ((size % EMMC_BLOCK_SIZE) == 0));
+
+	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	cmd.cmd_idx = EMMC_CMD35;
+	cmd.cmd_arg = lba;
+	cmd.resp_type = EMMC_RESPONSE_R1;
+	ret = ops->send_cmd(&cmd);
+	assert(ret == 0);
+
+	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	cmd.cmd_idx = EMMC_CMD36;
+	cmd.cmd_arg = lba + (size / EMMC_BLOCK_SIZE) - 1;
+	cmd.resp_type = EMMC_RESPONSE_R1;
+	ret = ops->send_cmd(&cmd);
+	assert(ret == 0);
+
+	memset(&cmd, 0, sizeof(emmc_cmd_t));
+	cmd.cmd_idx = EMMC_CMD38;
+	cmd.resp_type = EMMC_RESPONSE_R1B;
+	ret = ops->send_cmd(&cmd);
+	assert(ret == 0);
+
+	/* wait to TRAN state */
+	do {
+		state = emmc_device_state();
+	} while (state != EMMC_STATE_TRAN);
+	/* Ignore improbable errors in release builds */
+	(void)ret;
+	return size;
+}
+
+static inline void emmc_rpmb_enable(void)
+{
+	emmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
+			PART_CFG_BOOT_PARTITION1_ENABLE |
+			PART_CFG_PARTITION1_ACCESS);
+}
+
+static inline void emmc_rpmb_disable(void)
+{
+	emmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
+			PART_CFG_BOOT_PARTITION1_ENABLE);
+}
+
+size_t emmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size)
+{
+	size_t size_read;
+
+	emmc_rpmb_enable();
+	size_read = emmc_read_blocks(lba, buf, size);
+	emmc_rpmb_disable();
+	return size_read;
+}
+
+size_t emmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size)
+{
+	size_t size_written;
+
+	emmc_rpmb_enable();
+	size_written = emmc_write_blocks(lba, buf, size);
+	emmc_rpmb_disable();
+	return size_written;
+}
+
+size_t emmc_rpmb_erase_blocks(int lba, size_t size)
+{
+	size_t size_erased;
+
+	emmc_rpmb_enable();
+	size_erased = emmc_erase_blocks(lba, size);
+	emmc_rpmb_disable();
+	return size_erased;
+}
+
+void emmc_init(const emmc_ops_t *ops_ptr, int clk, int width)
+{
+	assert((ops_ptr != 0) &&
+	       (ops_ptr->init != 0) &&
+	       (ops_ptr->send_cmd != 0) &&
+	       (ops_ptr->set_ios != 0) &&
+	       (ops_ptr->prepare != 0) &&
+	       (ops_ptr->read != 0) &&
+	       (ops_ptr->write != 0) &&
+	       (clk != 0) &&
+	       ((width == EMMC_BUS_WIDTH_1) ||
+		(width == EMMC_BUS_WIDTH_4) ||
+		(width == EMMC_BUS_WIDTH_8)));
+	ops = ops_ptr;
+
+	emmc_enumerate(clk, width);
+}
diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c
new file mode 100644
index 0000000..198b723
--- /dev/null
+++ b/drivers/io/io_block.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <io_block.h>
+#include <io_driver.h>
+#include <io_storage.h>
+#include <platform_def.h>
+#include <string.h>
+
+typedef struct {
+	io_block_dev_spec_t	*dev_spec;
+	uintptr_t		base;
+	size_t			file_pos;
+	size_t			size;
+} block_dev_state_t;
+
+#define is_power_of_2(x)	((x != 0) && ((x & (x - 1)) == 0))
+
+io_type_t device_type_block(void);
+
+static int block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+		      io_entity_t *entity);
+static int block_seek(io_entity_t *entity, int mode, ssize_t offset);
+static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+		      size_t *length_read);
+static int block_write(io_entity_t *entity, const uintptr_t buffer,
+		       size_t length, size_t *length_written);
+static int block_close(io_entity_t *entity);
+static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
+static int block_dev_close(io_dev_info_t *dev_info);
+
+static const io_dev_connector_t block_dev_connector = {
+	.dev_open	= block_dev_open
+};
+
+static const io_dev_funcs_t block_dev_funcs = {
+	.type		= device_type_block,
+	.open		= block_open,
+	.seek		= block_seek,
+	.size		= NULL,
+	.read		= block_read,
+	.write		= block_write,
+	.close		= block_close,
+	.dev_init	= NULL,
+	.dev_close	= block_dev_close,
+};
+
+static block_dev_state_t state_pool[MAX_IO_BLOCK_DEVICES];
+static io_dev_info_t dev_info_pool[MAX_IO_BLOCK_DEVICES];
+
+/* Track number of allocated block state */
+static unsigned int block_dev_count;
+
+io_type_t device_type_block(void)
+{
+	return IO_TYPE_BLOCK;
+}
+
+/* Locate a block state in the pool, specified by address */
+static int find_first_block_state(const io_block_dev_spec_t *dev_spec,
+				  unsigned int *index_out)
+{
+	int result = -ENOENT;
+	for (int index = 0; index < MAX_IO_BLOCK_DEVICES; ++index) {
+		/* dev_spec is used as identifier since it's unique */
+		if (state_pool[index].dev_spec == dev_spec) {
+			result = 0;
+			*index_out = index;
+			break;
+		}
+	}
+	return result;
+}
+
+/* Allocate a device info from the pool and return a pointer to it */
+static int allocate_dev_info(io_dev_info_t **dev_info)
+{
+	int result = -ENOMEM;
+	assert(dev_info != NULL);
+
+	if (block_dev_count < MAX_IO_BLOCK_DEVICES) {
+		unsigned int index = 0;
+		result = find_first_block_state(NULL, &index);
+		assert(result == 0);
+		/* initialize dev_info */
+		dev_info_pool[index].funcs = &block_dev_funcs;
+		dev_info_pool[index].info = (uintptr_t)&state_pool[index];
+		*dev_info = &dev_info_pool[index];
+		++block_dev_count;
+	}
+
+	return result;
+}
+
+
+/* Release a device info to the pool */
+static int free_dev_info(io_dev_info_t *dev_info)
+{
+	int result;
+	unsigned int index = 0;
+	block_dev_state_t *state;
+	assert(dev_info != NULL);
+
+	state = (block_dev_state_t *)dev_info->info;
+	result = find_first_block_state(state->dev_spec, &index);
+	if (result ==  0) {
+		/* free if device info is valid */
+		memset(state, 0, sizeof(block_dev_state_t));
+		memset(dev_info, 0, sizeof(io_dev_info_t));
+		--block_dev_count;
+	}
+
+	return result;
+}
+
+static int block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+		      io_entity_t *entity)
+{
+	block_dev_state_t *cur;
+	io_block_spec_t *region;
+
+	assert((dev_info->info != (uintptr_t)NULL) &&
+	       (spec != (uintptr_t)NULL) &&
+	       (entity->info == (uintptr_t)NULL));
+
+	region = (io_block_spec_t *)spec;
+	cur = (block_dev_state_t *)dev_info->info;
+	assert(((region->offset % cur->dev_spec->block_size) == 0) &&
+	       ((region->length % cur->dev_spec->block_size) == 0));
+
+	cur->base = region->offset;
+	cur->size = region->length;
+	cur->file_pos = 0;
+
+	entity->info = (uintptr_t)cur;
+	return 0;
+}
+
+/* parameter offset is relative address at here */
+static int block_seek(io_entity_t *entity, int mode, ssize_t offset)
+{
+	block_dev_state_t *cur;
+
+	assert(entity->info != (uintptr_t)NULL);
+
+	cur = (block_dev_state_t *)entity->info;
+	assert((offset >= 0) && (offset < cur->size));
+
+	switch (mode) {
+	case IO_SEEK_SET:
+		cur->file_pos = offset;
+		break;
+	case IO_SEEK_CUR:
+		cur->file_pos += offset;
+		break;
+	default:
+		return -EINVAL;
+	}
+	assert(cur->file_pos < cur->size);
+	return 0;
+}
+
+static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length,
+		      size_t *length_read)
+{
+	block_dev_state_t *cur;
+	io_block_spec_t *buf;
+	io_block_ops_t *ops;
+	size_t aligned_length, skip, count, left, padding, block_size;
+	int lba;
+
+	assert(entity->info != (uintptr_t)NULL);
+	cur = (block_dev_state_t *)entity->info;
+	ops = &(cur->dev_spec->ops);
+	buf = &(cur->dev_spec->buffer);
+	block_size = cur->dev_spec->block_size;
+	assert((length <= cur->size) &&
+	       (length > 0) &&
+	       (ops->read != 0));
+
+	skip = cur->file_pos % block_size;
+	aligned_length = ((skip + length) + (block_size - 1)) &
+			 ~(block_size - 1);
+	padding = aligned_length - (skip + length);
+	left = aligned_length;
+	do {
+		lba = (cur->file_pos + cur->base) / block_size;
+		if (left >= buf->length) {
+			/* Since left is larger, it's impossible to padding. */
+			if (skip) {
+				/*
+				 * The beginning address (file_pos) isn't
+				 * aligned with block size, we need to use
+				 * block buffer to read block. Since block
+				 * device is always relied on DMA operation.
+				 */
+				count = ops->read(lba, buf->offset,
+						  buf->length);
+			} else {
+				count = ops->read(lba, buffer, buf->length);
+			}
+			assert(count == buf->length);
+			cur->file_pos += count - skip;
+			if (skip) {
+				/*
+				 * Since it's not aligned with block size,
+				 * block buffer is used to store data.
+				 */
+				memcpy((void *)buffer,
+				       (void *)(buf->offset + skip),
+				       count - skip);
+			}
+			left = left - (count - skip);
+		} else {
+			if (skip || padding) {
+				/*
+				 * The beginning address (file_pos) isn't
+				 * aligned with block size, we have to read
+				 * full block by block buffer instead.
+				 * The size isn't aligned with block size.
+				 * Use block buffer to avoid overflow.
+				 */
+				count = ops->read(lba, buf->offset, left);
+			} else
+				count = ops->read(lba, buffer, left);
+			assert(count == left);
+			left = left - (skip + padding);
+			cur->file_pos += left;
+			if (skip || padding) {
+				/*
+				 * Since it's not aligned with block size,
+				 * block buffer is used to store data.
+				 */
+				memcpy((void *)buffer,
+				       (void *)(buf->offset + skip),
+				       left);
+			}
+			/* It's already the last block operation */
+			left = 0;
+		}
+		skip = cur->file_pos % block_size;
+	} while (left > 0);
+	*length_read = length;
+
+	return 0;
+}
+
+static int block_write(io_entity_t *entity, const uintptr_t buffer,
+		       size_t length, size_t *length_written)
+{
+	block_dev_state_t *cur;
+	io_block_spec_t *buf;
+	io_block_ops_t *ops;
+	size_t aligned_length, skip, count, left, padding, block_size;
+	int lba;
+
+	assert(entity->info != (uintptr_t)NULL);
+	cur = (block_dev_state_t *)entity->info;
+	ops = &(cur->dev_spec->ops);
+	buf = &(cur->dev_spec->buffer);
+	block_size = cur->dev_spec->block_size;
+	assert((length <= cur->size) &&
+	       (length > 0) &&
+	       (ops->read != 0) &&
+	       (ops->write != 0));
+
+	skip = cur->file_pos % block_size;
+	aligned_length = ((skip + length) + (block_size - 1)) &
+			 ~(block_size - 1);
+	padding = aligned_length - (skip + length);
+	left = aligned_length;
+	do {
+		lba = (cur->file_pos + cur->base) / block_size;
+		if (left >= buf->length) {
+			/* Since left is larger, it's impossible to padding. */
+			if (skip) {
+				/*
+				 * The beginning address (file_pos) isn't
+				 * aligned with block size, we need to use
+				 * block buffer to write block. Since block
+				 * device is always relied on DMA operation.
+				 */
+				count = ops->read(lba, buf->offset,
+						  buf->length);
+				assert(count == buf->length);
+				memcpy((void *)(buf->offset + skip),
+				       (void *)buffer,
+				       count - skip);
+				count = ops->write(lba, buf->offset,
+						   buf->length);
+			} else
+				count = ops->write(lba, buffer, buf->length);
+			assert(count == buf->length);
+			cur->file_pos += count - skip;
+			left = left - (count - skip);
+		} else {
+			if (skip || padding) {
+				/*
+				 * The beginning address (file_pos) isn't
+				 * aligned with block size, we need to avoid
+				 * poluate data in the beginning. Reading and
+				 * skipping the beginning is the only way.
+				 * The size isn't aligned with block size.
+				 * Use block buffer to avoid overflow.
+				 */
+				count = ops->read(lba, buf->offset, left);
+				assert(count == left);
+				memcpy((void *)(buf->offset + skip),
+				       (void *)buffer,
+				       left - skip - padding);
+				count = ops->write(lba, buf->offset, left);
+			} else
+				count = ops->write(lba, buffer, left);
+			assert(count == left);
+			cur->file_pos += left - (skip + padding);
+			/* It's already the last block operation */
+			left = 0;
+		}
+		skip = cur->file_pos % block_size;
+	} while (left > 0);
+	*length_written = length;
+	return 0;
+}
+
+static int block_close(io_entity_t *entity)
+{
+	entity->info = (uintptr_t)NULL;
+	return 0;
+}
+
+static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
+{
+	block_dev_state_t *cur;
+	io_block_spec_t *buffer;
+	io_dev_info_t *info;
+	size_t block_size;
+	int result;
+
+	assert(dev_info != NULL);
+	result = allocate_dev_info(&info);
+	if (result)
+		return -ENOENT;
+
+	cur = (block_dev_state_t *)info->info;
+	/* dev_spec is type of io_block_dev_spec_t. */
+	cur->dev_spec = (io_block_dev_spec_t *)dev_spec;
+	buffer = &(cur->dev_spec->buffer);
+	block_size = cur->dev_spec->block_size;
+	assert((block_size > 0) &&
+	       (is_power_of_2(block_size) != 0) &&
+	       ((buffer->offset % block_size) == 0) &&
+	       ((buffer->length % block_size) == 0));
+
+	*dev_info = info;	/* cast away const */
+	(void)block_size;
+	(void)buffer;
+	return 0;
+}
+
+static int block_dev_close(io_dev_info_t *dev_info)
+{
+	return free_dev_info(dev_info);
+}
+
+/* Exported functions */
+
+/* Register the Block driver with the IO abstraction */
+int register_io_dev_block(const io_dev_connector_t **dev_con)
+{
+	int result;
+
+	assert(dev_con != NULL);
+
+	/*
+	 * Since dev_info isn't really used in io_register_device, always
+	 * use the same device info at here instead.
+	 */
+	result = io_register_device(&dev_info_pool[0]);
+	if (result == 0)
+		*dev_con = &block_dev_connector;
+	return result;
+}
diff --git a/include/drivers/emmc.h b/include/drivers/emmc.h
new file mode 100644
index 0000000..61d4495
--- /dev/null
+++ b/include/drivers/emmc.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EMMC_H__
+#define __EMMC_H__
+
+#include <stdint.h>
+
+#define EMMC_BLOCK_SIZE			512
+#define EMMC_BLOCK_MASK			(EMMC_BLOCK_SIZE - 1)
+#define EMMC_BOOT_CLK_RATE		(400 * 1000)
+
+#define EMMC_CMD0			0
+#define EMMC_CMD1			1
+#define EMMC_CMD2			2
+#define EMMC_CMD3			3
+#define EMMC_CMD6			6
+#define EMMC_CMD7			7
+#define EMMC_CMD8			8
+#define EMMC_CMD9			9
+#define EMMC_CMD12			12
+#define EMMC_CMD13			13
+#define EMMC_CMD17			17
+#define EMMC_CMD18			18
+#define EMMC_CMD24			24
+#define EMMC_CMD25			25
+#define EMMC_CMD35			35
+#define EMMC_CMD36			36
+#define EMMC_CMD38			38
+
+#define OCR_POWERUP			(1 << 31)
+#define OCR_BYTE_MODE			(0 << 29)
+#define OCR_SECTOR_MODE			(2 << 29)
+#define OCR_ACCESS_MODE_MASK		(3 << 29)
+#define OCR_VDD_MIN_2V7			(0x1ff << 15)
+#define OCR_VDD_MIN_2V0			(0x7f << 8)
+#define OCR_VDD_MIN_1V7			(1 << 7)
+
+#define EMMC_RESPONSE_R1		1
+#define EMMC_RESPONSE_R1B		1
+#define EMMC_RESPONSE_R2		4
+#define EMMC_RESPONSE_R3		1
+#define EMMC_RESPONSE_R4		1
+#define EMMC_RESPONSE_R5		1
+
+#define EMMC_FIX_RCA			6	/* > 1 */
+#define RCA_SHIFT_OFFSET		16
+
+#define CMD_EXTCSD_PARTITION_CONFIG	179
+#define CMD_EXTCSD_BUS_WIDTH		183
+#define CMD_EXTCSD_HS_TIMING		185
+
+#define PART_CFG_BOOT_PARTITION1_ENABLE	(1 << 3)
+#define PART_CFG_PARTITION1_ACCESS	(1 << 0)
+
+/* values in EXT CSD register */
+#define EMMC_BUS_WIDTH_1		0
+#define EMMC_BUS_WIDTH_4		1
+#define EMMC_BUS_WIDTH_8		2
+#define EMMC_BOOT_MODE_BACKWARD		(0 << 3)
+#define EMMC_BOOT_MODE_HS_TIMING	(1 << 3)
+#define EMMC_BOOT_MODE_DDR		(2 << 3)
+
+#define EXTCSD_SET_CMD			(0 << 24)
+#define EXTCSD_SET_BITS			(1 << 24)
+#define EXTCSD_CLR_BITS			(2 << 24)
+#define EXTCSD_WRITE_BYTES		(3 << 24)
+#define EXTCSD_CMD(x)			(((x) & 0xff) << 16)
+#define EXTCSD_VALUE(x)			(((x) & 0xff) << 8)
+
+#define STATUS_CURRENT_STATE(x)		(((x) & 0xf) << 9)
+#define STATUS_READY_FOR_DATA		(1 << 8)
+#define STATUS_SWITCH_ERROR		(1 << 7)
+#define EMMC_GET_STATE(x)		(((x) >> 9) & 0xf)
+#define EMMC_STATE_IDLE			0
+#define EMMC_STATE_READY		1
+#define EMMC_STATE_IDENT		2
+#define EMMC_STATE_STBY			3
+#define EMMC_STATE_TRAN			4
+#define EMMC_STATE_DATA			5
+#define EMMC_STATE_RCV			6
+#define EMMC_STATE_PRG			7
+#define EMMC_STATE_DIS			8
+#define EMMC_STATE_BTST			9
+#define EMMC_STATE_SLP			10
+
+typedef struct emmc_cmd {
+	unsigned int	cmd_idx;
+	unsigned int	cmd_arg;
+	unsigned int	resp_type;
+	unsigned int	resp_data[4];
+} emmc_cmd_t;
+
+typedef struct emmc_ops {
+	void (*init)(void);
+	int (*send_cmd)(emmc_cmd_t *cmd);
+	int (*set_ios)(int clk, int width);
+	int (*prepare)(int lba, uintptr_t buf, size_t size);
+	int (*read)(int lba, uintptr_t buf, size_t size);
+	int (*write)(int lba, const uintptr_t buf, size_t size);
+} emmc_ops_t;
+
+typedef struct emmc_csd {
+	unsigned char		not_used:		1;
+	unsigned char		crc:			7;
+	unsigned char		ecc:			2;
+	unsigned char		file_format:		2;
+	unsigned char		tmp_write_protect:	1;
+	unsigned char		perm_write_protect:	1;
+	unsigned char		copy:			1;
+	unsigned char		file_format_grp:	1;
+
+	unsigned short		reserved_1:		5;
+	unsigned short		write_bl_partial:	1;
+	unsigned short		write_bl_len:		4;
+	unsigned short		r2w_factor:		3;
+	unsigned short		default_ecc:		2;
+	unsigned short		wp_grp_enable:		1;
+
+	unsigned int		wp_grp_size:		5;
+	unsigned int		erase_grp_mult:		5;
+	unsigned int		erase_grp_size:		5;
+	unsigned int		c_size_mult:		3;
+	unsigned int		vdd_w_curr_max:		3;
+	unsigned int		vdd_w_curr_min:		3;
+	unsigned int		vdd_r_curr_max:		3;
+	unsigned int		vdd_r_curr_min:		3;
+	unsigned int		c_size_low:		2;
+
+	unsigned int		c_size_high:		10;
+	unsigned int		reserved_2:		2;
+	unsigned int		dsr_imp:		1;
+	unsigned int		read_blk_misalign:	1;
+	unsigned int		write_blk_misalign:	1;
+	unsigned int		read_bl_partial:	1;
+	unsigned int		read_bl_len:		4;
+	unsigned int		ccc:			12;
+
+	unsigned int		tran_speed:		8;
+	unsigned int		nsac:			8;
+	unsigned int		taac:			8;
+	unsigned int		reserved_3:		2;
+	unsigned int		spec_vers:		4;
+	unsigned int		csd_structure:		2;
+} emmc_csd_t;
+
+size_t emmc_read_blocks(int lba, uintptr_t buf, size_t size);
+size_t emmc_write_blocks(int lba, const uintptr_t buf, size_t size);
+size_t emmc_erase_blocks(int lba, size_t size);
+size_t emmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size);
+size_t emmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size);
+size_t emmc_rpmb_erase_blocks(int lba, size_t size);
+void emmc_init(const emmc_ops_t *ops, int clk, int bus_width);
+
+#endif	/* __EMMC_H__ */
diff --git a/include/drivers/io/io_block.h b/include/drivers/io/io_block.h
new file mode 100644
index 0000000..ebf43cd
--- /dev/null
+++ b/include/drivers/io/io_block.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __IO_BLOCK_H__
+#define __IO_BLOCK_H__
+
+#include <io_storage.h>
+
+/* block devices ops */
+typedef struct io_block_ops {
+	size_t	(*read)(int lba, uintptr_t buf, size_t size);
+	size_t	(*write)(int lba, const uintptr_t buf, size_t size);
+} io_block_ops_t;
+
+typedef struct io_block_dev_spec {
+	io_block_spec_t	buffer;
+	io_block_ops_t	ops;
+	size_t		block_size;
+} io_block_dev_spec_t;
+
+struct io_dev_connector;
+
+int register_io_dev_block(const struct io_dev_connector **dev_con);
+
+#endif /* __IO_BLOCK_H__ */
diff --git a/include/drivers/io/io_storage.h b/include/drivers/io/io_storage.h
index 970ab2c..243f688 100644
--- a/include/drivers/io/io_storage.h
+++ b/include/drivers/io/io_storage.h
@@ -44,6 +44,7 @@
 	IO_TYPE_SEMIHOSTING,
 	IO_TYPE_MEMMAP,
 	IO_TYPE_FIRMWARE_IMAGE_PACKAGE,
+	IO_TYPE_BLOCK,
 	IO_TYPE_MAX
 } io_type_t;
 
diff --git a/lib/xlat_tables/xlat_tables_common.c b/lib/xlat_tables/xlat_tables_common.c
index 54c528c..fd10084 100644
--- a/lib/xlat_tables/xlat_tables_common.c
+++ b/lib/xlat_tables/xlat_tables_common.c
@@ -284,8 +284,9 @@
 	unsigned level_size_shift = L1_XLAT_ADDRESS_SHIFT - (level - 1) *
 						XLAT_TABLE_ENTRIES_SHIFT;
 	unsigned level_size = 1 << level_size_shift;
-	unsigned long long level_index_mask = XLAT_TABLE_ENTRIES_MASK <<
-							level_size_shift;
+	unsigned long long level_index_mask =
+		((unsigned long long) XLAT_TABLE_ENTRIES_MASK)
+		<< level_size_shift;
 
 	assert(level > 0 && level <= 3);
 
diff --git a/tools/fip_create/fip_create.c b/tools/fip_create/fip_create.c
index 7bce348..48cb3f6 100644
--- a/tools/fip_create/fip_create.c
+++ b/tools/fip_create/fip_create.c
@@ -811,7 +811,7 @@
 	if (fip_filename == NULL) {
 		printf("ERROR: Missing FIP filename\n");
 		print_usage();
-		return 0;
+		return EINVAL;
 	}
 
 	/* Unpack images from FIP always takes precedence over packaging. In