1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <string.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <platform_def.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu #include <common/debug.h> 13*91f16700Schasinglulu #include <drivers/io/io_driver.h> 14*91f16700Schasinglulu #include <drivers/io/io_memmap.h> 15*91f16700Schasinglulu #include <drivers/io/io_storage.h> 16*91f16700Schasinglulu #include <lib/utils.h> 17*91f16700Schasinglulu 18*91f16700Schasinglulu #include "qspi/cadence_qspi.h" 19*91f16700Schasinglulu 20*91f16700Schasinglulu /* As we need to be able to keep state for seek, only one file can be open 21*91f16700Schasinglulu * at a time. Make this a structure and point to the entity->info. When we 22*91f16700Schasinglulu * can malloc memory we can change this to support more open files. 23*91f16700Schasinglulu */ 24*91f16700Schasinglulu typedef struct { 25*91f16700Schasinglulu /* Use the 'in_use' flag as any value for base and file_pos could be 26*91f16700Schasinglulu * valid. 27*91f16700Schasinglulu */ 28*91f16700Schasinglulu int in_use; 29*91f16700Schasinglulu uintptr_t base; 30*91f16700Schasinglulu unsigned long long file_pos; 31*91f16700Schasinglulu unsigned long long size; 32*91f16700Schasinglulu } file_state_t; 33*91f16700Schasinglulu 34*91f16700Schasinglulu static file_state_t current_file = {0}; 35*91f16700Schasinglulu 36*91f16700Schasinglulu /* Identify the device type as memmap */ 37*91f16700Schasinglulu static io_type_t device_type_memmap(void) 38*91f16700Schasinglulu { 39*91f16700Schasinglulu return IO_TYPE_MEMMAP; 40*91f16700Schasinglulu } 41*91f16700Schasinglulu 42*91f16700Schasinglulu /* Memmap device functions */ 43*91f16700Schasinglulu static int memmap_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 44*91f16700Schasinglulu static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec, 45*91f16700Schasinglulu io_entity_t *entity); 46*91f16700Schasinglulu static int memmap_block_seek(io_entity_t *entity, int mode, 47*91f16700Schasinglulu signed long long offset); 48*91f16700Schasinglulu static int memmap_block_len(io_entity_t *entity, size_t *length); 49*91f16700Schasinglulu static int memmap_block_read(io_entity_t *entity, uintptr_t buffer, 50*91f16700Schasinglulu size_t length, size_t *length_read); 51*91f16700Schasinglulu static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer, 52*91f16700Schasinglulu size_t length, size_t *length_written); 53*91f16700Schasinglulu static int memmap_block_close(io_entity_t *entity); 54*91f16700Schasinglulu static int memmap_dev_close(io_dev_info_t *dev_info); 55*91f16700Schasinglulu 56*91f16700Schasinglulu 57*91f16700Schasinglulu static const io_dev_connector_t memmap_dev_connector = { 58*91f16700Schasinglulu .dev_open = memmap_dev_open 59*91f16700Schasinglulu }; 60*91f16700Schasinglulu 61*91f16700Schasinglulu 62*91f16700Schasinglulu static const io_dev_funcs_t memmap_dev_funcs = { 63*91f16700Schasinglulu .type = device_type_memmap, 64*91f16700Schasinglulu .open = memmap_block_open, 65*91f16700Schasinglulu .seek = memmap_block_seek, 66*91f16700Schasinglulu .size = memmap_block_len, 67*91f16700Schasinglulu .read = memmap_block_read, 68*91f16700Schasinglulu .write = memmap_block_write, 69*91f16700Schasinglulu .close = memmap_block_close, 70*91f16700Schasinglulu .dev_init = NULL, 71*91f16700Schasinglulu .dev_close = memmap_dev_close, 72*91f16700Schasinglulu }; 73*91f16700Schasinglulu 74*91f16700Schasinglulu 75*91f16700Schasinglulu /* No state associated with this device so structure can be const */ 76*91f16700Schasinglulu static const io_dev_info_t memmap_dev_info = { 77*91f16700Schasinglulu .funcs = &memmap_dev_funcs, 78*91f16700Schasinglulu .info = (uintptr_t)NULL 79*91f16700Schasinglulu }; 80*91f16700Schasinglulu 81*91f16700Schasinglulu 82*91f16700Schasinglulu /* Open a connection to the memmap device */ 83*91f16700Schasinglulu static int memmap_dev_open(const uintptr_t dev_spec __unused, 84*91f16700Schasinglulu io_dev_info_t **dev_info) 85*91f16700Schasinglulu { 86*91f16700Schasinglulu assert(dev_info != NULL); 87*91f16700Schasinglulu *dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */ 88*91f16700Schasinglulu 89*91f16700Schasinglulu return 0; 90*91f16700Schasinglulu } 91*91f16700Schasinglulu 92*91f16700Schasinglulu 93*91f16700Schasinglulu 94*91f16700Schasinglulu /* Close a connection to the memmap device */ 95*91f16700Schasinglulu static int memmap_dev_close(io_dev_info_t *dev_info) 96*91f16700Schasinglulu { 97*91f16700Schasinglulu /* NOP */ 98*91f16700Schasinglulu /* TODO: Consider tracking open files and cleaning them up here */ 99*91f16700Schasinglulu return 0; 100*91f16700Schasinglulu } 101*91f16700Schasinglulu 102*91f16700Schasinglulu 103*91f16700Schasinglulu /* Open a file on the memmap device */ 104*91f16700Schasinglulu static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec, 105*91f16700Schasinglulu io_entity_t *entity) 106*91f16700Schasinglulu { 107*91f16700Schasinglulu int result = -ENOMEM; 108*91f16700Schasinglulu const io_block_spec_t *block_spec = (io_block_spec_t *)spec; 109*91f16700Schasinglulu 110*91f16700Schasinglulu /* Since we need to track open state for seek() we only allow one open 111*91f16700Schasinglulu * spec at a time. When we have dynamic memory we can malloc and set 112*91f16700Schasinglulu * entity->info. 113*91f16700Schasinglulu */ 114*91f16700Schasinglulu if (current_file.in_use == 0) { 115*91f16700Schasinglulu assert(block_spec != NULL); 116*91f16700Schasinglulu assert(entity != NULL); 117*91f16700Schasinglulu 118*91f16700Schasinglulu current_file.in_use = 1; 119*91f16700Schasinglulu current_file.base = block_spec->offset; 120*91f16700Schasinglulu /* File cursor offset for seek and incremental reads etc. */ 121*91f16700Schasinglulu current_file.file_pos = 0; 122*91f16700Schasinglulu current_file.size = block_spec->length; 123*91f16700Schasinglulu entity->info = (uintptr_t)¤t_file; 124*91f16700Schasinglulu result = 0; 125*91f16700Schasinglulu } else { 126*91f16700Schasinglulu WARN("A Memmap device is already active. Close first.\n"); 127*91f16700Schasinglulu } 128*91f16700Schasinglulu 129*91f16700Schasinglulu return result; 130*91f16700Schasinglulu } 131*91f16700Schasinglulu 132*91f16700Schasinglulu 133*91f16700Schasinglulu /* Seek to a particular file offset on the memmap device */ 134*91f16700Schasinglulu static int memmap_block_seek(io_entity_t *entity, int mode, 135*91f16700Schasinglulu signed long long offset) 136*91f16700Schasinglulu { 137*91f16700Schasinglulu int result = -ENOENT; 138*91f16700Schasinglulu file_state_t *fp; 139*91f16700Schasinglulu 140*91f16700Schasinglulu /* We only support IO_SEEK_SET for the moment. */ 141*91f16700Schasinglulu if (mode == IO_SEEK_SET) { 142*91f16700Schasinglulu assert(entity != NULL); 143*91f16700Schasinglulu 144*91f16700Schasinglulu fp = (file_state_t *) entity->info; 145*91f16700Schasinglulu 146*91f16700Schasinglulu /* Assert that new file position is valid */ 147*91f16700Schasinglulu assert((offset >= 0) && 148*91f16700Schasinglulu ((unsigned long long)offset < fp->size)); 149*91f16700Schasinglulu 150*91f16700Schasinglulu /* Reset file position */ 151*91f16700Schasinglulu fp->file_pos = offset; 152*91f16700Schasinglulu result = 0; 153*91f16700Schasinglulu } 154*91f16700Schasinglulu 155*91f16700Schasinglulu return result; 156*91f16700Schasinglulu } 157*91f16700Schasinglulu 158*91f16700Schasinglulu 159*91f16700Schasinglulu /* Return the size of a file on the memmap device */ 160*91f16700Schasinglulu static int memmap_block_len(io_entity_t *entity, size_t *length) 161*91f16700Schasinglulu { 162*91f16700Schasinglulu assert(entity != NULL); 163*91f16700Schasinglulu assert(length != NULL); 164*91f16700Schasinglulu 165*91f16700Schasinglulu *length = ((file_state_t *)entity->info)->size; 166*91f16700Schasinglulu 167*91f16700Schasinglulu return 0; 168*91f16700Schasinglulu } 169*91f16700Schasinglulu 170*91f16700Schasinglulu 171*91f16700Schasinglulu /* Read data from a file on the memmap device */ 172*91f16700Schasinglulu static int memmap_block_read(io_entity_t *entity, uintptr_t buffer, 173*91f16700Schasinglulu size_t length, size_t *length_read) 174*91f16700Schasinglulu { 175*91f16700Schasinglulu file_state_t *fp; 176*91f16700Schasinglulu unsigned long long pos_after; 177*91f16700Schasinglulu 178*91f16700Schasinglulu assert(entity != NULL); 179*91f16700Schasinglulu assert(length_read != NULL); 180*91f16700Schasinglulu 181*91f16700Schasinglulu fp = (file_state_t *) entity->info; 182*91f16700Schasinglulu 183*91f16700Schasinglulu /* Assert that file position is valid for this read operation */ 184*91f16700Schasinglulu pos_after = fp->file_pos + length; 185*91f16700Schasinglulu assert((pos_after >= fp->file_pos) && (pos_after <= fp->size)); 186*91f16700Schasinglulu 187*91f16700Schasinglulu //memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length); 188*91f16700Schasinglulu cad_qspi_read((void *)buffer, fp->base + fp->file_pos, length); 189*91f16700Schasinglulu *length_read = length; 190*91f16700Schasinglulu 191*91f16700Schasinglulu /* Set file position after read */ 192*91f16700Schasinglulu fp->file_pos = pos_after; 193*91f16700Schasinglulu 194*91f16700Schasinglulu return 0; 195*91f16700Schasinglulu } 196*91f16700Schasinglulu 197*91f16700Schasinglulu 198*91f16700Schasinglulu /* Write data to a file on the memmap device */ 199*91f16700Schasinglulu static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer, 200*91f16700Schasinglulu size_t length, size_t *length_written) 201*91f16700Schasinglulu { 202*91f16700Schasinglulu file_state_t *fp; 203*91f16700Schasinglulu unsigned long long pos_after; 204*91f16700Schasinglulu 205*91f16700Schasinglulu assert(entity != NULL); 206*91f16700Schasinglulu assert(length_written != NULL); 207*91f16700Schasinglulu 208*91f16700Schasinglulu fp = (file_state_t *) entity->info; 209*91f16700Schasinglulu 210*91f16700Schasinglulu /* Assert that file position is valid for this write operation */ 211*91f16700Schasinglulu pos_after = fp->file_pos + length; 212*91f16700Schasinglulu assert((pos_after >= fp->file_pos) && (pos_after <= fp->size)); 213*91f16700Schasinglulu 214*91f16700Schasinglulu memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length); 215*91f16700Schasinglulu 216*91f16700Schasinglulu *length_written = length; 217*91f16700Schasinglulu 218*91f16700Schasinglulu /* Set file position after write */ 219*91f16700Schasinglulu fp->file_pos = pos_after; 220*91f16700Schasinglulu 221*91f16700Schasinglulu return 0; 222*91f16700Schasinglulu } 223*91f16700Schasinglulu 224*91f16700Schasinglulu 225*91f16700Schasinglulu /* Close a file on the memmap device */ 226*91f16700Schasinglulu static int memmap_block_close(io_entity_t *entity) 227*91f16700Schasinglulu { 228*91f16700Schasinglulu assert(entity != NULL); 229*91f16700Schasinglulu 230*91f16700Schasinglulu entity->info = 0; 231*91f16700Schasinglulu 232*91f16700Schasinglulu /* This would be a mem free() if we had malloc.*/ 233*91f16700Schasinglulu zeromem((void *)¤t_file, sizeof(current_file)); 234*91f16700Schasinglulu 235*91f16700Schasinglulu return 0; 236*91f16700Schasinglulu } 237*91f16700Schasinglulu 238*91f16700Schasinglulu 239*91f16700Schasinglulu /* Exported functions */ 240*91f16700Schasinglulu 241*91f16700Schasinglulu /* Register the memmap driver with the IO abstraction */ 242*91f16700Schasinglulu int register_io_dev_memmap(const io_dev_connector_t **dev_con) 243*91f16700Schasinglulu { 244*91f16700Schasinglulu int result; 245*91f16700Schasinglulu 246*91f16700Schasinglulu assert(dev_con != NULL); 247*91f16700Schasinglulu 248*91f16700Schasinglulu result = io_register_device(&memmap_dev_info); 249*91f16700Schasinglulu if (result == 0) 250*91f16700Schasinglulu *dev_con = &memmap_dev_connector; 251*91f16700Schasinglulu 252*91f16700Schasinglulu return result; 253*91f16700Schasinglulu } 254