rcar_gen3: drivers: io [emmc/mem]

Signed-off-by: ldts <jramirez@baylibre.com>
diff --git a/drivers/renesas/rcar/io/io_memdrv.c b/drivers/renesas/rcar/io/io_memdrv.c
new file mode 100644
index 0000000..e55fd64
--- /dev/null
+++ b/drivers/renesas/rcar/io/io_memdrv.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <io_driver.h>
+#include <io_storage.h>
+#include <string.h>
+
+#include "io_common.h"
+#include "io_private.h"
+#include "io_memdrv.h"
+#include "rcar_def.h"
+
+extern void rcar_dma_exec(uintptr_t dst, uint32_t src, uint32_t len);
+
+static int32_t memdrv_dev_open(const uintptr_t dev __attribute__ ((unused)),
+			       io_dev_info_t **dev_info);
+static int32_t memdrv_dev_close(io_dev_info_t *dev_info);
+
+/* As we need to be able to keep state for seek, only one file can be open
+ * at a time. Make this a structure and point to the entity->info. When we
+ * can malloc memory we can change this to support more open files.
+ */
+typedef struct {
+	uint32_t in_use;
+	uintptr_t base;
+	ssize_t file_pos;
+} file_state_t;
+
+static file_state_t current_file = { 0 };
+
+static io_type_t device_type_memdrv(void)
+{
+	return IO_TYPE_MEMMAP;
+}
+
+static int32_t memdrv_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
+				 io_entity_t *entity)
+{
+	const io_drv_spec_t *block_spec = (io_drv_spec_t *) spec;
+
+	/* Since we need to track open state for seek() we only allow one open
+	 * spec at a time. When we have dynamic memory we can malloc and set
+	 * entity->info.
+	 */
+	if (current_file.in_use)
+		return IO_RESOURCES_EXHAUSTED;
+
+	/* File cursor offset for seek and incremental reads etc. */
+	current_file.base = block_spec->offset;
+	current_file.file_pos = 0;
+	current_file.in_use = 1;
+
+	entity->info = (uintptr_t) &current_file;
+
+	return IO_SUCCESS;
+}
+
+static int32_t memdrv_block_seek(io_entity_t *entity, int32_t mode,
+				 ssize_t offset)
+{
+	if (mode != IO_SEEK_SET)
+		return IO_FAIL;
+
+	((file_state_t *) entity->info)->file_pos = offset;
+
+	return IO_SUCCESS;
+}
+
+static int32_t memdrv_block_read(io_entity_t *entity, uintptr_t buffer,
+				 size_t length, size_t *cnt)
+{
+	file_state_t *fp;
+
+	fp = (file_state_t *) entity->info;
+
+	NOTICE("BL2: dst=0x%lx src=0x%lx len=%ld(0x%lx)\n",
+	       buffer, fp->base + fp->file_pos, length, length);
+
+	if (FLASH_MEMORY_SIZE < fp->file_pos + length) {
+		ERROR("BL2: check load image (source address)\n");
+		return IO_FAIL;
+	}
+
+	rcar_dma_exec(buffer, fp->base + fp->file_pos, length);
+	fp->file_pos += length;
+	*cnt = length;
+
+	return IO_SUCCESS;
+}
+
+static int32_t memdrv_block_close(io_entity_t *entity)
+{
+	entity->info = 0U;
+
+	memset((void *)&current_file, 0, sizeof(current_file));
+
+	return IO_SUCCESS;
+}
+
+static const io_dev_funcs_t memdrv_dev_funcs = {
+	.type = &device_type_memdrv,
+	.open = &memdrv_block_open,
+	.seek = &memdrv_block_seek,
+	.size = NULL,
+	.read = &memdrv_block_read,
+	.write = NULL,
+	.close = &memdrv_block_close,
+	.dev_init = NULL,
+	.dev_close = &memdrv_dev_close,
+};
+
+static const io_dev_info_t memdrv_dev_info = {
+	.funcs = &memdrv_dev_funcs,
+	.info = 0,
+};
+
+static const io_dev_connector_t memdrv_dev_connector = {
+	.dev_open = &memdrv_dev_open
+};
+
+static int32_t memdrv_dev_open(const uintptr_t dev __attribute__ ((unused)),
+			       io_dev_info_t **dev_info)
+{
+	*dev_info = (io_dev_info_t *) &memdrv_dev_info;
+
+	return IO_SUCCESS;
+}
+
+static int32_t memdrv_dev_close(io_dev_info_t *dev_info)
+{
+	return IO_SUCCESS;
+}
+
+int32_t rcar_register_io_dev_memdrv(const io_dev_connector_t **dev_con)
+{
+	int32_t result;
+
+	result = io_register_device(&memdrv_dev_info);
+	if (result == IO_SUCCESS)
+		*dev_con = &memdrv_dev_connector;
+
+	return result;
+}