This driver has been tested with Micron NOR Flash via AXI Quad SPI. --- .../microblaze_fpga/fs/jffs2_qspi.c | 319 ++++++++++++++++++ .../microblaze_fpga/include/bsp/jffs2_qspi.h | 56 +++ .../bsps/microblaze/microblaze_fpga/grp.yml | 6 + .../bsps/microblaze/microblaze_fpga/obj.yml | 2 + .../microblaze_fpga/optspibaseaddress.yml | 18 + .../microblaze/microblaze_fpga/optspiirq.yml | 17 + 6 files changed, 418 insertions(+) create mode 100644 bsps/microblaze/microblaze_fpga/fs/jffs2_qspi.c create mode 100644 bsps/microblaze/microblaze_fpga/include/bsp/jffs2_qspi.h create mode 100644 spec/build/bsps/microblaze/microblaze_fpga/optspibaseaddress.yml create mode 100644 spec/build/bsps/microblaze/microblaze_fpga/optspiirq.yml
diff --git a/bsps/microblaze/microblaze_fpga/fs/jffs2_qspi.c b/bsps/microblaze/microblaze_fpga/fs/jffs2_qspi.c new file mode 100644 index 0000000000..39328b6b7c --- /dev/null +++ b/bsps/microblaze/microblaze_fpga/fs/jffs2_qspi.c @@ -0,0 +1,319 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSBSPsMicroblaze + * + * @brief MicroBlaze AXI QSPI JFFS2 flash driver implementation + */ + +/* + * Copyright (C) 2022 On-Line Applications Research Corporation (OAR) + * + * 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 <assert.h> +#include <errno.h> +#include <string.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <bspopts.h> +#include <dev/spi/xilinx-axi-spi.h> +#include <linux/spi/spidev.h> +#include <rtems/jffs2.h> +#include <rtems/libio.h> + +#include <bsp/jffs2_qspi.h> + +#define BLOCK_SIZE (64UL * 1024UL) +#define FLASH_SIZE (32UL * BLOCK_SIZE) +#define FLASH_PAGE_SIZE 256 +#define FLASH_NUM_CS 2 +#define FLASH_DEVICE_ID 0xbb19 /* Type: 0xbb, Capacity: 0x19 */ +#define BUS_PATH "/dev/spi-0" +#define FLASH_MOUNT_POINT "/mnt" + +#define READ_WRITE_EXTRA_BYTES 4 +#define WRITE_ENABLE_BYTES 1 +#define SECTOR_ERASE_BYTES 4 + +#define COMMAND_QUAD_WRITE 0x32 +#define COMMAND_SECTOR_ERASE 0xD8 +#define COMMAND_QUAD_READ 0x6B +#define COMMAND_STATUSREG_READ 0x05 +#define COMMAND_WRITE_ENABLE 0x06 +#define FLASH_SR_IS_READY_MASK 0x01 + +typedef struct { + rtems_jffs2_flash_control super; + int fd; +} flash_control; + +static uint8_t ReadBuffer[FLASH_PAGE_SIZE + READ_WRITE_EXTRA_BYTES + 4]; +static uint8_t WriteBuffer[FLASH_PAGE_SIZE + READ_WRITE_EXTRA_BYTES + 4]; + +static flash_control *get_flash_control( rtems_jffs2_flash_control *super ) +{ + return (flash_control *) super; +} + +static int flash_wait_for_ready( flash_control *self ) +{ + uint8_t rv = 0; + uint8_t status = 0; + + WriteBuffer[0] = COMMAND_STATUSREG_READ; + + struct spi_ioc_transfer mesg = { + .tx_buf = WriteBuffer, + .rx_buf = ReadBuffer, + .len = 2, + .bits_per_word = 8, + .cs = 0 + }; + + do { + rv = ioctl( self->fd, SPI_IOC_MESSAGE( 1 ), &mesg ); + if ( rv != 0 ) { + return -EIO; + } + + status = ReadBuffer[1]; + } while ( (status & FLASH_SR_IS_READY_MASK) != 0 ); + + return 0; +} + +static int flash_write_enable( flash_control *self ) +{ + uint8_t rv = 0; + + rv = flash_wait_for_ready( self ); + if ( rv != 0 ) { + return rv; + } + + WriteBuffer[0] = COMMAND_WRITE_ENABLE; + + struct spi_ioc_transfer mesg = { + .tx_buf = WriteBuffer, + .len = WRITE_ENABLE_BYTES, + .bits_per_word = 8, + .cs = 0 + }; + + rv = ioctl( self->fd, SPI_IOC_MESSAGE( 1 ), &mesg ); + if ( rv != 0 ) { + return -EIO; + } + + return 0; +} + +static int flash_read( + rtems_jffs2_flash_control *super, + uint32_t offset, + unsigned char *buffer, + size_t size_of_buffer +) +{ + int rv = 0; + uint32_t current_offset = offset; + uint32_t bytes_left = size_of_buffer; + + flash_control *self = get_flash_control( super ); + + rv = flash_wait_for_ready( self ); + if ( rv != 0 ) { + return rv; + } + + WriteBuffer[0] = COMMAND_QUAD_READ; + + /* Read in 256-byte chunks */ + do { + uint32_t chunk_size = bytes_left > FLASH_PAGE_SIZE ? FLASH_PAGE_SIZE : bytes_left; + + struct spi_ioc_transfer mesg = { + .tx_buf = WriteBuffer, + .rx_buf = ReadBuffer, + .len = chunk_size + 8, + .bits_per_word = 8, + .cs = 0 + }; + + WriteBuffer[1] = (uint8_t) (current_offset >> 16); + WriteBuffer[2] = (uint8_t) (current_offset >> 8); + WriteBuffer[3] = (uint8_t) current_offset; + + rv = ioctl( self->fd, SPI_IOC_MESSAGE( 1 ), &mesg ); + if ( rv != 0 ) { + return -EIO; + } + + memcpy( &buffer[current_offset - offset], &ReadBuffer[8], chunk_size ); + + current_offset += chunk_size; + bytes_left -= chunk_size; + } while ( bytes_left > 0 ); + + return 0; +} + +static int flash_write( + rtems_jffs2_flash_control *super, + uint32_t offset, + const unsigned char *buffer, + size_t size_of_buffer +) +{ + int rv = 0; + + flash_control *self = get_flash_control( super ); + + rv = flash_write_enable( self ); + if ( rv != 0 ) { + return rv; + } + + rv = flash_wait_for_ready( self ); + if ( rv != 0 ) { + return rv; + } + + WriteBuffer[0] = COMMAND_QUAD_WRITE; + WriteBuffer[1] = (uint8_t) (offset >> 16); + WriteBuffer[2] = (uint8_t) (offset >> 8); + WriteBuffer[3] = (uint8_t) offset; + + memcpy( &WriteBuffer[4], buffer, size_of_buffer ); + + struct spi_ioc_transfer mesg = { + .tx_buf = WriteBuffer, + .len = size_of_buffer + 4, + .bits_per_word = 8, + .cs = 0 + }; + + rv = ioctl( self->fd, SPI_IOC_MESSAGE( 1 ), &mesg ); + if ( rv != 0 ) { + return -EIO; + } + + return 0; +} + +static int flash_erase( + rtems_jffs2_flash_control *super, + uint32_t offset +) +{ + int rv = 0; + + flash_control *self = get_flash_control( super ); + + rv = flash_write_enable( self ); + if ( rv != 0 ) { + return rv; + } + + rv = flash_wait_for_ready( self ); + if ( rv != 0 ) { + return rv; + } + + WriteBuffer[0] = COMMAND_SECTOR_ERASE; + WriteBuffer[1] = (uint8_t) (offset >> 16); + WriteBuffer[2] = (uint8_t) (offset >> 8); + WriteBuffer[3] = (uint8_t) offset; + + struct spi_ioc_transfer mesg = { + .tx_buf = WriteBuffer, + .len = SECTOR_ERASE_BYTES, + .bits_per_word = 8, + .cs = 0 + }; + + rv = ioctl( self->fd, SPI_IOC_MESSAGE( 1 ), &mesg ); + if ( rv != 0 ) { + return -EIO; + } + + return 0; +} + +static flash_control flash_instance = { + .super = { + .block_size = BLOCK_SIZE, + .flash_size = FLASH_SIZE, + .read = flash_read, + .write = flash_write, + .erase = flash_erase, + .device_identifier = FLASH_DEVICE_ID + } +}; + +static rtems_jffs2_mount_data mount_data = { + .flash_control = &flash_instance.super, + .compressor_control = NULL +}; + +int microblaze_jffs2_initialize( const char* mount_dir ) +{ + int rv = 0; + int fd = -1; + + rv = spi_bus_register_xilinx_axi( + BUS_PATH, + BSP_MICROBLAZE_FPGA_SPI_BASE, + FLASH_PAGE_SIZE, + FLASH_NUM_CS, + BSP_MICROBLAZE_FPGA_SPI_IRQ_NUM + ); + if ( rv != 0 ) { + return rv; + } + + fd = open( BUS_PATH, O_RDWR ); + if ( fd < 0 ) { + return -1; + } + + flash_instance.fd = fd; + + rv = mount_and_make_target_path( + NULL, + mount_dir, + RTEMS_FILESYSTEM_TYPE_JFFS2, + RTEMS_FILESYSTEM_READ_WRITE, + &mount_data + ); + if ( rv != 0 ) { + return rv; + } + + return 0; +} diff --git a/bsps/microblaze/microblaze_fpga/include/bsp/jffs2_qspi.h b/bsps/microblaze/microblaze_fpga/include/bsp/jffs2_qspi.h new file mode 100644 index 0000000000..9c071c4977 --- /dev/null +++ b/bsps/microblaze/microblaze_fpga/include/bsp/jffs2_qspi.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSBSPsMicroblaze + * + * @brief MicroBlaze AXI QSPI JFFS2 flash driver definitions + */ + +/* + * Copyright (C) 2022 On-Line Applications Research Corporation (OAR) + * + * 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. + */ + +#ifndef LIBBSP_MICROBLAZE_FPGA_JFFS2_QSPI_H +#define LIBBSP_MICROBLAZE_FPGA_JFFS2_QSPI_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @brief Mount jffs2 filesystem. + * + * @param[in] mount_dir The directory to mount the filesystem at. + * + * @retval 0 Successful operation. Negative number otherwise. + */ +int microblaze_jffs2_initialize( const char* mount_dir ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_MICROBLAZE_FPGA_JFFS2_QSPI_H */ diff --git a/spec/build/bsps/microblaze/microblaze_fpga/grp.yml b/spec/build/bsps/microblaze/microblaze_fpga/grp.yml index 11df1802f1..bb9b82c250 100644 --- a/spec/build/bsps/microblaze/microblaze_fpga/grp.yml +++ b/spec/build/bsps/microblaze/microblaze_fpga/grp.yml @@ -35,6 +35,10 @@ links: uid: optintcbaseaddress - role: build-dependency uid: optramlen +- role: build-dependency + uid: optspibaseaddress +- role: build-dependency + uid: optspiirq - role: build-dependency uid: opttimerbaseaddress - role: build-dependency @@ -43,6 +47,8 @@ links: uid: optuartlitebaseaddress - role: build-dependency uid: ../../obj +- role: build-dependency + uid: ../../objdevspixil - role: build-dependency uid: ../../objirq - role: build-dependency diff --git a/spec/build/bsps/microblaze/microblaze_fpga/obj.yml b/spec/build/bsps/microblaze/microblaze_fpga/obj.yml index 37096cdc84..993ba04004 100644 --- a/spec/build/bsps/microblaze/microblaze_fpga/obj.yml +++ b/spec/build/bsps/microblaze/microblaze_fpga/obj.yml @@ -15,6 +15,7 @@ install: - destination: ${BSP_INCLUDEDIR}/bsp source: - bsps/microblaze/microblaze_fpga/include/bsp/irq.h + - bsps/microblaze/microblaze_fpga/include/bsp/jffs2_qspi.h - bsps/microblaze/include/common/xil_types.h - bsps/microblaze/include/dev/serial/uartlite.h - bsps/microblaze/include/dev/serial/uartlite_l.h @@ -24,6 +25,7 @@ source: - bsps/microblaze/microblaze_fpga/console/console-io.c - bsps/microblaze/microblaze_fpga/console/debug-io.c - bsps/microblaze/microblaze_fpga/fdt/bsp_fdt.c +- bsps/microblaze/microblaze_fpga/fs/jffs2_qspi.c - bsps/microblaze/microblaze_fpga/irq/irq.c - bsps/microblaze/microblaze_fpga/start/_debug_sw_break_handler.S - bsps/microblaze/microblaze_fpga/start/_exception_handler.S diff --git a/spec/build/bsps/microblaze/microblaze_fpga/optspibaseaddress.yml b/spec/build/bsps/microblaze/microblaze_fpga/optspibaseaddress.yml new file mode 100644 index 0000000000..86907b70ab --- /dev/null +++ b/spec/build/bsps/microblaze/microblaze_fpga/optspibaseaddress.yml @@ -0,0 +1,18 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- get-integer: null +- assert-uint32: null +- env-assign: null +- format-and-define: null +build-type: option +copyrights: +- Copyright (C) 2022 On-Line Applications Research Corporation (OAR) +default: 0x44a00000 +default-by-variant: [] +description: | + base address of the AXI Quad SPI +enabled-by: true +format: '{:#010x}' +links: [] +name: BSP_MICROBLAZE_FPGA_SPI_BASE +type: build diff --git a/spec/build/bsps/microblaze/microblaze_fpga/optspiirq.yml b/spec/build/bsps/microblaze/microblaze_fpga/optspiirq.yml new file mode 100644 index 0000000000..7186c6b8e1 --- /dev/null +++ b/spec/build/bsps/microblaze/microblaze_fpga/optspiirq.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +actions: +- get-integer: null +- assert-uint32: null +- define: null +build-type: option +copyrights: +- Copyright (C) 2022 On-Line Applications Research Corporation (OAR) +default: 3 +default-by-variant: [] +description: | + IRQ number of the AXI SPI +enabled-by: true +format: '{}' +links: [] +name: BSP_MICROBLAZE_FPGA_SPI_IRQ_NUM +type: build -- 2.32.0 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel