[rtems commit] microblaze: Add JFFS2 AXI QSPI driver

Joel Sherrill joel at rtems.org
Tue Mar 15 15:36:20 UTC 2022


Module:    rtems
Branch:    master
Commit:    14381c432a61252f7e130500400823f1bff397c9
Changeset: http://git.rtems.org/rtems/commit/?id=14381c432a61252f7e130500400823f1bff397c9

Author:    Alex White <alex.white at oarcorp.com>
Date:      Wed Feb 16 13:32:30 2022 -0600

microblaze: Add JFFS2 AXI QSPI driver

This driver has been tested with Micron NOR Flash via AXI Quad SPI.

---

 bsps/microblaze/microblaze_fpga/fs/jffs2_qspi.c    | 319 +++++++++++++++++++++
 .../microblaze_fpga/include/bsp/jffs2_qspi.h       |  56 ++++
 spec/build/bsps/microblaze/microblaze_fpga/grp.yml |   6 +
 spec/build/bsps/microblaze/microblaze_fpga/obj.yml |   2 +
 .../microblaze_fpga/optspibaseaddress.yml          |  18 ++
 .../bsps/microblaze/microblaze_fpga/optspiirq.yml  |  17 ++
 6 files changed, 418 insertions(+)

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 0000000..39328b6
--- /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 0000000..9c071c4
--- /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 11df180..bb9b82c 100644
--- a/spec/build/bsps/microblaze/microblaze_fpga/grp.yml
+++ b/spec/build/bsps/microblaze/microblaze_fpga/grp.yml
@@ -36,6 +36,10 @@ links:
 - role: build-dependency
   uid: optramlen
 - role: build-dependency
+  uid: optspibaseaddress
+- role: build-dependency
+  uid: optspiirq
+- role: build-dependency
   uid: opttimerbaseaddress
 - role: build-dependency
   uid: opttimerfrequency
@@ -44,6 +48,8 @@ links:
 - role: build-dependency
   uid: ../../obj
 - role: build-dependency
+  uid: ../../objdevspixil
+- role: build-dependency
   uid: ../../objirq
 - role: build-dependency
   uid: ../../objmem
diff --git a/spec/build/bsps/microblaze/microblaze_fpga/obj.yml b/spec/build/bsps/microblaze/microblaze_fpga/obj.yml
index 37096cd..993ba04 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 0000000..86907b7
--- /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 0000000..7186c6b
--- /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



More information about the vc mailing list