/* SPDX-License-Identifier: BSD-2-Clause */ /* * Copyright (C) 2023 Aaron Nyholm * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * 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 OWNER 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 "test_flashdev.h" #include #include #include #define TEST_DATA_SIZE ( PAGE_SIZE * PAGE_COUNT ) #define PAGE_COUNT 16 #define PAGE_SIZE 128 #define SECTOR_COUNT 4 #define SECTOR_SIZE ( TEST_DATA_SIZE / SECTOR_COUNT ) #define WB_SIZE 1 #define MAX_NUM_REGIONS 48 #define BITALLOC_SIZE 32 #define NUM_BITALLOC \ ( ( MAX_NUM_REGIONS + BITALLOC_SIZE - 1 ) / BITALLOC_SIZE ) /** * This flash device driver is for testing flashdev * API calls. */ typedef struct test_flashdev { char *data; uint32_t jedec_id; uint32_t bit_allocator[ NUM_BITALLOC ]; rtems_flashdev_region regions[ MAX_NUM_REGIONS ]; } test_flashdev; int test_flashdev_page_by_off( rtems_flashdev *flash, off_t search_offset, off_t *page_offset, size_t *page_size ); int test_flashdev_page_by_index( rtems_flashdev *flash, off_t search_index, off_t *page_offset, size_t *page_size ); int test_flashdev_page_count( rtems_flashdev *flash, int *page_count ); int test_flashdev_wb_size( rtems_flashdev *flash, size_t *write_block_size ); int test_flashdev_sector_by_off( rtems_flashdev *flash, off_t search_offset, off_t *sector_offset, size_t *sector_size ); int test_flashdev_sector_count( rtems_flashdev *flash, int *sector_count ); uint32_t test_flashdev_jedec_id( rtems_flashdev *flash ); int test_flashdev_type( rtems_flashdev *flash, rtems_flashdev_flash_type *type ); int test_flashdev_read( rtems_flashdev *flash, uintptr_t offset, size_t count, void *buffer ); int test_flashdev_write( rtems_flashdev *flash, uintptr_t offset, size_t count, const void *buffer ); int test_flashdev_erase( rtems_flashdev *flash, uintptr_t offset, size_t count ); /* Find page info by offset handler */ int test_flashdev_page_by_off( rtems_flashdev *flash, off_t search_offset, off_t *page_offset, size_t *page_size ) { (void) flash; *page_offset = search_offset - ( search_offset % PAGE_SIZE ); *page_size = PAGE_SIZE; return 0; } /* Find page by index handler */ int test_flashdev_page_by_index( rtems_flashdev *flash, off_t search_index, off_t *page_offset, size_t *page_size ) { (void) flash; *page_offset = search_index * PAGE_SIZE; *page_size = PAGE_SIZE; return 0; } /* Page count handler */ int test_flashdev_page_count( rtems_flashdev *flash, int *page_count ) { (void) flash; *page_count = PAGE_COUNT; return 0; } /* Write block size handler */ int test_flashdev_wb_size( rtems_flashdev *flash, size_t *write_block_size ) { (void) flash; *write_block_size = WB_SIZE; return 0; } int test_flashdev_sector_by_off( rtems_flashdev *flash, off_t search_offset, off_t *sector_offset, size_t *sector_size ) { (void) flash; *sector_offset = search_offset - ( search_offset % SECTOR_SIZE ); *sector_size = SECTOR_SIZE; return 0; } int test_flashdev_sector_count( rtems_flashdev *flash, int *sector_count ) { (void) flash; *sector_count = SECTOR_COUNT; return 0; } /* JEDEC ID handler, this would normally require a READID * call to the physical flash device. */ uint32_t test_flashdev_jedec_id( rtems_flashdev *flash ) { (void) flash; test_flashdev *driver = flash->driver; return driver->jedec_id; } /* Function to identify what kind of flash is attached. */ int test_flashdev_type( rtems_flashdev *flash, rtems_flashdev_flash_type *type ) { (void) flash; *type = RTEMS_FLASHDEV_NOR; return 0; } /* Read flash call. Any offset or count protections are * required to be done in the driver function. */ int test_flashdev_read( rtems_flashdev *flash, uintptr_t offset, size_t count, void *buffer ) { test_flashdev *driver = flash->driver; if ( offset + count > TEST_DATA_SIZE ) { rtems_set_errno_and_return_minus_one( EINVAL ); } memcpy( buffer, &driver->data[ offset ], count ); return 0; } /* Write Flash call. Any offset or count protections are * required to be done in the driver function. */ int test_flashdev_write( rtems_flashdev *flash, uintptr_t offset, size_t count, const void *buffer ) { test_flashdev *driver = flash->driver; if ( offset + count > TEST_DATA_SIZE ) { rtems_set_errno_and_return_minus_one( EINVAL ); } memcpy( &driver->data[ offset ], buffer, count ); return 0; } /* Erase Flash call. Any offset or count protections are * required to be done in the driver function. */ int test_flashdev_erase( rtems_flashdev *flash, uintptr_t offset, size_t count ) { test_flashdev *driver = flash->driver; if ( offset + count > TEST_DATA_SIZE ) { rtems_set_errno_and_return_minus_one( EINVAL ); } if ( offset % PAGE_SIZE || count % PAGE_SIZE ) { rtems_set_errno_and_return_minus_one( EINVAL ); } memset( &driver->data[ offset ], 0, count ); return 0; } static void test_flashdev_priv_destroy( rtems_flashdev *flash ) { test_flashdev *flash_driver = flash->driver; free( flash_driver->data ); free( flash->driver ); free( flash->region_table ); } /* Initialize Flashdev and underlying driver. */ rtems_flashdev *test_flashdev_init( void ) { rtems_flashdev *flash = rtems_flashdev_alloc_and_init( sizeof( rtems_flashdev ) ); if ( flash == NULL ) { return NULL; } test_flashdev *flash_driver = calloc( 1, sizeof( test_flashdev ) ); if ( flash_driver == NULL ) { rtems_flashdev_destroy_and_free( flash ); return NULL; } flash_driver->data = calloc( 1, TEST_DATA_SIZE ); if ( flash_driver->data == NULL ) { free( flash_driver ); rtems_flashdev_destroy_and_free( flash ); return NULL; } flash_driver->jedec_id = 0x00ABCDEF; rtems_flashdev_region_table *ftable = calloc( 1, sizeof( rtems_flashdev_region_table ) ); ftable->max_regions = MAX_NUM_REGIONS; ftable->regions = flash_driver->regions; ftable->bit_allocator = flash_driver->bit_allocator; flash->driver = flash_driver; flash->priv_destroy = &test_flashdev_priv_destroy; flash->read = &test_flashdev_read; flash->write = &test_flashdev_write; flash->erase = &test_flashdev_erase; flash->jedec_id = &test_flashdev_jedec_id; flash->flash_type = &test_flashdev_type; flash->page_info_by_offset = &test_flashdev_page_by_off; flash->page_info_by_index = &test_flashdev_page_by_index; flash->page_count = &test_flashdev_page_count; flash->write_block_size = &test_flashdev_wb_size; flash->sector_info_by_offset = &test_flashdev_sector_by_off; flash->sector_count = &test_flashdev_sector_count; flash->region_table = ftable; return flash; }