[PATCH v1 2/4] aarch64/versal: Add flash wrapper for Xilinx GQSPI

aaron.nyholm at unfoldedeffective.com aaron.nyholm at unfoldedeffective.com
Thu Oct 19 05:43:33 UTC 2023


From: Aaron Nyholm <aaron.nyholm at southerninnovation.com>

---
 .../dev/spi/versal_xqspi_flash.c              | 296 ++++++++++++++++++
 bsps/aarch64/xilinx-versal/include/bsp/irq.h  |   1 +
 .../include/dev/spi/versal_xqspi_flash.h      |  49 +++
 bsps/include/dev/spi/xqspipsu-flash-helper.h  |  24 ++
 bsps/shared/dev/spi/xqspipsu-flash-helper.c   |  16 +
 spec/build/bsps/aarch64/xilinx-versal/grp.yml |   2 +
 .../aarch64/xilinx-versal/objxqspiflash.yml   |  24 ++
 7 files changed, 412 insertions(+)
 create mode 100644 bsps/aarch64/xilinx-versal/dev/spi/versal_xqspi_flash.c
 create mode 100644 bsps/aarch64/xilinx-versal/include/dev/spi/versal_xqspi_flash.h
 create mode 100644 spec/build/bsps/aarch64/xilinx-versal/objxqspiflash.yml

diff --git a/bsps/aarch64/xilinx-versal/dev/spi/versal_xqspi_flash.c b/bsps/aarch64/xilinx-versal/dev/spi/versal_xqspi_flash.c
new file mode 100644
index 0000000000..7771af9dcd
--- /dev/null
+++ b/bsps/aarch64/xilinx-versal/dev/spi/versal_xqspi_flash.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2023, 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 <bsp/irq.h>
+#include <dev/spi/versal_xqspi_flash.h>
+#include <dev/spi/xqspipsu.h>
+#include <dev/spi/xqspipsu-flash-helper.h>
+#include <dev/spi/xqspipsu_flash_config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+
+uint32_t xqspi_get_jedec_id(rtems_flashdev *flash);
+
+int xqspi_get_flash_type(
+  rtems_flashdev *flash,
+  rtems_flashdev_flash_type *type
+);
+
+int xqspi_page_info_by_off(
+  rtems_flashdev *flash,
+  off_t search_offset,
+  off_t *page_offset,
+  size_t *page_size
+);
+
+int xqspi_page_info_by_index(
+  rtems_flashdev *flash,
+  off_t search_index,
+  off_t *page_offset,
+  size_t *page_size
+);
+
+int xqspi_page_count(
+  rtems_flashdev *flash,
+  int *page_count
+);
+
+int xqspi_write_block_size(
+  rtems_flashdev *flash,
+  size_t *write_block_size
+);
+
+int xqspi_read_wrapper(rtems_flashdev *flash,
+  uintptr_t offset,
+  size_t count,
+  void *buffer
+);
+
+int xqspi_write_wrapper(
+  rtems_flashdev *flash,
+  uintptr_t offset,
+  size_t count,
+  const void *buffer
+);
+
+int xqspi_erase_wrapper(
+  rtems_flashdev *flash,
+  uintptr_t offset,
+  size_t count
+);
+
+uint32_t xqspi_get_jedec_id(rtems_flashdev *flash) {
+  return QspiPsu_NOR_Get_JEDEC_ID(flash->driver);
+}
+
+int xqspi_get_flash_type(
+  rtems_flashdev *flash,
+  rtems_flashdev_flash_type *type
+)
+{
+  *type = RTEMS_FLASHDEV_NOR;
+  return 0;
+}
+
+int xqspi_read_wrapper(
+    rtems_flashdev *flash,
+    uintptr_t offset,
+    size_t count,
+    void *buffer
+)
+{
+  XQspiPsu *flash_driver = (XQspiPsu*)flash->driver;
+  uint8_t *tmp_buffer;
+  int status;
+  int startAlign = 0;
+
+  /* Align offset to two byte boundary */
+  if (offset%2) {
+    startAlign = 1;
+    offset = offset - 1;
+    count = count + 1;
+  }
+
+  while (count > MAX_READ_SIZE) {
+    /* Read block and copy to buffer */
+    status = QspiPsu_NOR_Read(flash_driver, (uint32_t)offset, MAX_READ_SIZE, &tmp_buffer);
+
+    if (status == 0) {
+      memcpy(buffer, tmp_buffer + startAlign, MAX_READ_SIZE - startAlign);
+      /* Update count, offset and buffer pointer */
+      count = count - MAX_READ_SIZE;
+      buffer = buffer + MAX_READ_SIZE - startAlign;
+      offset = offset + MAX_READ_SIZE;
+      /* Clear startAlign once first block read */
+      if (startAlign) {
+        startAlign = 0;
+      }
+    } else {
+      return status;
+    }
+  }
+
+  status = QspiPsu_NOR_Read(flash_driver, (uint32_t)offset, (uint32_t)count, &tmp_buffer);
+
+  if (status == 0) {
+    memcpy(buffer, tmp_buffer + startAlign, count);
+  }
+  return status;
+}
+
+int xqspi_page_info_by_off(
+  rtems_flashdev *flash,
+  off_t search_offset,
+  off_t *page_offset,
+  size_t *page_size
+)
+{
+  *page_size = QspiPsu_NOR_Get_Sector_Size(flash->driver);
+  *page_offset = search_offset - (search_offset%((off_t)(*page_size)));
+  return 0;
+}
+
+int xqspi_page_info_by_index(
+  rtems_flashdev *flash,
+  off_t search_index,
+  off_t *page_offset,
+  size_t *page_size
+)
+{
+  *page_size = QspiPsu_NOR_Get_Page_Size(flash->driver);
+  *page_offset = *page_size * search_index;
+  return 0;
+}
+
+int xqspi_page_count(
+  rtems_flashdev *flash,
+  int *page_count
+)
+{
+  *page_count = QspiPsu_NOR_Get_Device_Size(flash->driver) /
+                  QspiPsu_NOR_Get_Page_Size(flash->driver);
+  return 0;
+}
+
+int xqspi_write_block_size(
+  rtems_flashdev *flash,
+  size_t *write_block_size
+)
+{
+  *write_block_size = QspiPsu_NOR_Get_Page_Size(flash->driver);
+  return 0;
+}
+
+int xqspi_write_wrapper(
+  rtems_flashdev *flash,
+  uintptr_t offset,
+  size_t count,
+  const void *buffer
+)
+{
+  XQspiPsu *flash_driver = (XQspiPsu*)flash->driver;
+  return QspiPsu_NOR_Write(flash_driver, (uint32_t)offset, (uint32_t)count, (void*)buffer);
+}
+
+int xqspi_erase_wrapper(
+  rtems_flashdev *flash,
+  uintptr_t offset,
+  size_t count
+)
+{
+  XQspiPsu *flash_driver = (XQspiPsu*)flash->driver;
+  return QspiPsu_NOR_Erase(flash_driver, (uint32_t)offset, (uint32_t)count);
+}
+
+rtems_flashdev* xqspi_flash_init(void)
+{
+  int status;
+  XQspiPsu *xQspiDev;
+  XQspiPsu_Config *xQspiDev_Config;
+
+  xQspiDev = calloc(1, sizeof(XQspiPsu));
+  if (xQspiDev == NULL) {
+    return NULL;
+  }
+  xQspiDev_Config = calloc(1, sizeof(XQspiPsu_Config));
+  if (xQspiDev_Config == NULL) {
+    free(xQspiDev);
+    return NULL;
+  }
+
+  xQspiDev_Config->DeviceId = 0;
+  xQspiDev_Config->BaseAddress = XQSPIPS_BASEADDR;
+  xQspiDev_Config->InputClockHz = VERSAL_QSPI_INPUT_CLOCK_HZ;
+  xQspiDev_Config->ConnectionMode = XQSPIPSU_CONNECTION_MODE_PARALLEL;
+  xQspiDev_Config->BusWidth = 2;
+  xQspiDev_Config->IsCacheCoherent = 0;
+
+  status = XQspiPsu_CfgInitialize(xQspiDev, xQspiDev_Config, XQSPIPS_BASEADDR);
+
+  if (status != 0) {
+    free(xQspiDev);
+    free(xQspiDev_Config);
+    return NULL;
+  }
+
+  versal_xqspi_region_table *xtable =
+    calloc(1, sizeof(versal_xqspi_region_table));
+
+  if (xtable == NULL) {
+    free(xQspiDev);
+    free(xQspiDev_Config);
+    return NULL;
+  }
+
+  rtems_flashdev_region_table *ftable =
+    calloc(1, sizeof(rtems_flashdev_region_table));
+
+  if (ftable == NULL) {
+    free(ftable);
+    free(xQspiDev);
+    free(xQspiDev_Config);
+    return NULL;
+  }
+
+  ftable->regions = (rtems_flashdev_region*)(&(xtable->versal_xqspi_regions));
+  ftable->max_regions = VERSAL_XQSPI_MAX_REGIONS;
+  ftable->bit_allocator = &(xtable->versal_xqspi_bit_allocator);
+
+  status = QspiPsu_NOR_Initialize(
+    xQspiDev,
+    VERSAL_IRQ_QSPI
+  );
+
+  if (status != 0) {
+    free(xQspiDev);
+    free(xQspiDev_Config);
+    return NULL;
+  }
+
+  rtems_flashdev *flash = rtems_flashdev_alloc_and_init(sizeof(rtems_flashdev));
+
+  if (flash == NULL) {
+    free(xQspiDev);
+    free(xQspiDev_Config);
+    return NULL;
+  }
+
+  flash->driver = xQspiDev;
+  flash->read = &xqspi_read_wrapper;
+  flash->write = &xqspi_write_wrapper;
+  flash->erase = &xqspi_erase_wrapper;
+  flash->jedec_id = &xqspi_get_jedec_id;
+  flash->flash_type = &xqspi_get_flash_type;
+  flash->page_info_by_offset = &xqspi_page_info_by_off;
+  flash->page_info_by_index = &xqspi_page_info_by_index;
+  flash->page_count = &xqspi_page_count;
+  flash->write_block_size = &xqspi_write_block_size;
+  flash->region_table = ftable;
+
+  return flash;
+
+}
diff --git a/bsps/aarch64/xilinx-versal/include/bsp/irq.h b/bsps/aarch64/xilinx-versal/include/bsp/irq.h
index b34bdfd345..6f4d387e8f 100644
--- a/bsps/aarch64/xilinx-versal/include/bsp/irq.h
+++ b/bsps/aarch64/xilinx-versal/include/bsp/irq.h
@@ -61,6 +61,7 @@ extern "C" {
 #define VERSAL_IRQ_ETHERNET_0_WAKEUP 89
 #define VERSAL_IRQ_ETHERNET_1 90
 #define VERSAL_IRQ_ETHERNET_1_WAKEUP 91
+#define VERSAL_IRQ_QSPI 157
 
 /** @} */
 
diff --git a/bsps/aarch64/xilinx-versal/include/dev/spi/versal_xqspi_flash.h b/bsps/aarch64/xilinx-versal/include/dev/spi/versal_xqspi_flash.h
new file mode 100644
index 0000000000..fe0ffd3e71
--- /dev/null
+++ b/bsps/aarch64/xilinx-versal/include/dev/spi/versal_xqspi_flash.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2023, 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.
+ */
+
+#ifndef LIBBSP_AARCH64_XILINX_VERSAL_XQSPI_FLASH_H
+#define LIBBSP_AARCH64_XILINX_VERSAL_XQSPI_FLASH_H
+
+#include <dev/flash/flashdev.h>
+
+#define VERSAL_XQSPI_MAX_REGIONS 32
+#define VERSAL_QSPI_INPUT_CLOCK_HZ 295833038
+#define MAX_READ_SIZE 0x8000
+
+/*
+ * Initalize a qspi_flash device using Xilinx's qspi flash
+ * driver. Device still needs to be registered using
+ * qspi_flash_register in qspi_flash.c.
+*/
+rtems_flashdev* xqspi_flash_init(void);
+
+typedef struct versal_xqspi_region_table {
+  rtems_flashdev_region versal_xqspi_regions[VERSAL_XQSPI_MAX_REGIONS];
+  uint32_t versal_xqspi_bit_allocator;
+} versal_xqspi_region_table;
+
+#endif /* LIBBSP_AARCH64_XILINX_VERSAL_XQSPI_FLASH_H */
diff --git a/bsps/include/dev/spi/xqspipsu-flash-helper.h b/bsps/include/dev/spi/xqspipsu-flash-helper.h
index 5e4233e64e..69660d28f7 100644
--- a/bsps/include/dev/spi/xqspipsu-flash-helper.h
+++ b/bsps/include/dev/spi/xqspipsu-flash-helper.h
@@ -155,3 +155,27 @@ u32 QspiPsu_NOR_Get_Device_Size(XQspiPsu *QspiPsuPtr);
  *
  ******************************************************************************/
 u32 QspiPsu_NOR_Get_Sector_Size(XQspiPsu *QspiPsuPtr);
+
+/*****************************************************************************/
+/**
+ *
+ * This function returns the page size of attached flash parts.
+ *
+ * @param	QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
+ *
+ * @return	The page size of attached flash in bytes.
+ *
+ ******************************************************************************/
+u32 QspiPsu_NOR_Get_Page_Size(XQspiPsu *QspiPsuPtr);
+
+/*****************************************************************************/
+/**
+ *
+ * This function returns the JEDEC ID of attached flash parts.
+ *
+ * @param	QspiPsuPtr is a pointer to the QSPIPSU driver component to use.
+ *
+ * @return	The JEDEC ID of attached flash in bytes.
+ *
+ ******************************************************************************/
+u32 QspiPsu_NOR_Get_JEDEC_ID(XQspiPsu *QspiPsuPtr);
diff --git a/bsps/shared/dev/spi/xqspipsu-flash-helper.c b/bsps/shared/dev/spi/xqspipsu-flash-helper.c
index c9d8273b87..1795c9756b 100644
--- a/bsps/shared/dev/spi/xqspipsu-flash-helper.c
+++ b/bsps/shared/dev/spi/xqspipsu-flash-helper.c
@@ -2277,3 +2277,19 @@ u32 QspiPsu_NOR_Get_Device_Size(XQspiPsu *QspiPsuPtr)
   }
   return Flash_Config_Table[FCTIndex].FlashDeviceSize;
 }
+
+u32 QspiPsu_NOR_Get_Page_Size(XQspiPsu *QspiPsuPtr)
+{
+  if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) {
+    return Flash_Config_Table[FCTIndex].PageSize * 2;
+  }
+  return Flash_Config_Table[FCTIndex].PageSize;
+}
+
+u32 QspiPsu_NOR_Get_JEDEC_ID(XQspiPsu *QspiPsuPtr)
+{
+  if(QspiPsuPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED) {
+    return Flash_Config_Table[FCTIndex].jedec_id * 2;
+  }
+  return Flash_Config_Table[FCTIndex].jedec_id;
+}
diff --git a/spec/build/bsps/aarch64/xilinx-versal/grp.yml b/spec/build/bsps/aarch64/xilinx-versal/grp.yml
index badfa07fcc..098a8481db 100644
--- a/spec/build/bsps/aarch64/xilinx-versal/grp.yml
+++ b/spec/build/bsps/aarch64/xilinx-versal/grp.yml
@@ -24,6 +24,8 @@ links:
   uid: abi
 - role: build-dependency
   uid: obj
+- role: build-dependency
+  uid: objxqspiflash
 - role: build-dependency
   uid: optconirq
 - role: build-dependency
diff --git a/spec/build/bsps/aarch64/xilinx-versal/objxqspiflash.yml b/spec/build/bsps/aarch64/xilinx-versal/objxqspiflash.yml
new file mode 100644
index 0000000000..6d84bfa8cd
--- /dev/null
+++ b/spec/build/bsps/aarch64/xilinx-versal/objxqspiflash.yml
@@ -0,0 +1,24 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+build-type: objects
+cflags: []
+copyrights:
+- Copyright (C) 2022 On-Line Applications Research (OAR)
+cppflags: []
+cxxflags: []
+enabled-by: true
+includes:
+- bsps/include/dev/spi/
+- bsps/include/xil/
+- bsps/include/xil/${XIL_SUPPORT_PATH}/
+install:
+- destination: ${BSP_INCLUDEDIR}/bsp
+  source:
+  - bsps/aarch64/xilinx-versal/include/dev/spi/versal_xqspi_flash.h
+links:
+- role: build-dependency
+  uid: ../../objxilinxsupport
+- role: build-dependency
+  uid: ../../objqspipsu
+source:
+    - bsps/aarch64/xilinx-versal/dev/spi/versal_xqspi_flash.c
+type: build
-- 
2.25.1



More information about the devel mailing list