/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #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) ¤t_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 *)¤t_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; }