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

Kinsey Moore kinsey.moore at oarcorp.com
Thu Oct 19 13:13:29 UTC 2023


Comments inline below.

On Thu, Oct 19, 2023 at 12:43 AM <aaron.nyholm at unfoldedeffective.com> wrote:

> 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
> +);
>

The above prototypes are unnecessary and the corresponding functions below
should be marked static so as not to require them.


> +
> +uint32_t xqspi_get_jedec_id(rtems_flashdev *flash) {
> +  return QspiPsu_NOR_Get_JEDEC_ID(flash->driver);
> +}
>

Side commentary: I don't really like that this NOR driver has as much
untracked internal state as it does, but that's how it came from Xilinx. An
alternative would be to read the 3 relevant bytes using QspiPsu_NOR_RDID.
Longer term I'd like to get that state pulled out into a NOR
management/wrapper struct that holds the raw XQspiPsu driver struct.


> +
> +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;
> +}
>

You're mixing page size and sector size in these two functions.

+
> +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)
>

I'd recommend that this be passed an initialized XQspiPsu pointer and this
flashdev adapter should be moved to bsps/shared so that it can be used by
any consumer of XQspiPsu. Is there anything preventing this?

+{
> +  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;
>

This seems to be missing a destroy call to clean up the various allocations.


> +
> +  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;
> +}
>

Copy and paste error?


> 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
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/devel/attachments/20231019/74f23c80/attachment-0001.htm>


More information about the devel mailing list