[PATCH] microblaze: Add JFFS2 AXI QSPI driver

Alex White alex.white at oarcorp.com
Tue Mar 8 18:39:08 UTC 2022


ping

On Wed, Mar 2, 2022 at 8:30 PM Alex White <alex.white at oarcorp.com> wrote:
>
> 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 at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel


More information about the devel mailing list