This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit febf61119826cdd0d93ffcc5f72c17f793877f39
Author: raiden00pl <[email protected]>
AuthorDate: Fri Aug 21 09:02:12 2026 +0200

    arch/arm/stm32h7: add XSPI driver
    
    Add a driver for the STM32H7R/S XSPI controller. The driver implements
    the NuttX QSPI interface and supports the memory-mapped mode used to
    execute code from the external flash.
    
    Signed-off-by: raiden00pl <[email protected]>
    Assisted-by: OpenAI Codex:gpt-5
---
 arch/arm/src/common/stm32/Kconfig.have           |    3 +
 arch/arm/src/stm32h7/CMakeLists.txt              |    4 +
 arch/arm/src/stm32h7/Kconfig                     |    7 +
 arch/arm/src/stm32h7/Make.defs                   |    4 +
 arch/arm/src/stm32h7/hardware/stm32h7rsxx_xspi.h |  406 +++++++
 arch/arm/src/stm32h7/stm32_xspi.c                | 1230 ++++++++++++++++++++++
 arch/arm/src/stm32h7/stm32_xspi.h                |  163 +++
 7 files changed, 1817 insertions(+)

diff --git a/arch/arm/src/common/stm32/Kconfig.have 
b/arch/arm/src/common/stm32/Kconfig.have
index 9ede5dc2247..2eb65ed31e4 100644
--- a/arch/arm/src/common/stm32/Kconfig.have
+++ b/arch/arm/src/common/stm32/Kconfig.have
@@ -639,6 +639,9 @@ config STM32_HAVE_OCTOSPI2
 config STM32_HAVE_QSPI
        bool
 
+config STM32_HAVE_XSPI
+       bool
+
 # CRC capabilities
 
 config STM32_HAVE_CRC
diff --git a/arch/arm/src/stm32h7/CMakeLists.txt 
b/arch/arm/src/stm32h7/CMakeLists.txt
index 79651690179..ecc0880d253 100644
--- a/arch/arm/src/stm32h7/CMakeLists.txt
+++ b/arch/arm/src/stm32h7/CMakeLists.txt
@@ -116,6 +116,10 @@ if(CONFIG_STM32_QSPI)
   list(APPEND SRCS stm32_qspi.c)
 endif()
 
+if(CONFIG_STM32_XSPI)
+  list(APPEND SRCS stm32_xspi.c)
+endif()
+
 if(CONFIG_STM32_RTC)
   list(APPEND SRCS stm32_rtc.c)
   if(CONFIG_RTC_ALARM)
diff --git a/arch/arm/src/stm32h7/Kconfig b/arch/arm/src/stm32h7/Kconfig
index 70112131708..d114eceb2b5 100644
--- a/arch/arm/src/stm32h7/Kconfig
+++ b/arch/arm/src/stm32h7/Kconfig
@@ -804,6 +804,13 @@ config STM32_BYPASS_CLOCKCONFIG
                Bypass clock configuration. For dual core chips only one core
                should configure clocks
 
+config STM32_XSPI
+       bool "XSPI support"
+       depends on STM32_HAVE_XSPI
+       default n
+       ---help---
+               Enable support for the STM32H7R/S XSPI controller.
+
 config STM32_SRAM4EXCLUDE
        bool "Exclude SRAM4 from the heap"
        default y if RPTUN
diff --git a/arch/arm/src/stm32h7/Make.defs b/arch/arm/src/stm32h7/Make.defs
index bb3817171c7..abcb35307f0 100644
--- a/arch/arm/src/stm32h7/Make.defs
+++ b/arch/arm/src/stm32h7/Make.defs
@@ -119,6 +119,10 @@ ifeq ($(CONFIG_STM32_QSPI),y)
 CHIP_CSRCS += stm32_qspi.c
 endif
 
+ifeq ($(CONFIG_STM32_XSPI),y)
+CHIP_CSRCS += stm32_xspi.c
+endif
+
 ifeq ($(CONFIG_STM32_RTC),y)
 CHIP_CSRCS += stm32_rtc.c
 ifeq ($(CONFIG_RTC_ALARM),y)
diff --git a/arch/arm/src/stm32h7/hardware/stm32h7rsxx_xspi.h 
b/arch/arm/src/stm32h7/hardware/stm32h7rsxx_xspi.h
new file mode 100644
index 00000000000..fd136678a5f
--- /dev/null
+++ b/arch/arm/src/stm32h7/hardware/stm32h7rsxx_xspi.h
@@ -0,0 +1,406 @@
+/****************************************************************************
+ * arch/arm/src/stm32h7/hardware/stm32h7rsxx_xspi.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32H7RSXX_XSPI_H
+#define __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32H7RSXX_XSPI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include "stm32_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register Offsets *********************************************************/
+
+#define STM32_XSPI_CR_OFFSET         0x0000 /* Control register */
+#define STM32_XSPI_DCR1_OFFSET       0x0008 /* Device configuration 1 */
+#define STM32_XSPI_DCR2_OFFSET       0x000c /* Device configuration 2 */
+#define STM32_XSPI_DCR3_OFFSET       0x0010 /* Device configuration 3 */
+#define STM32_XSPI_DCR4_OFFSET       0x0014 /* Device configuration 4 */
+#define STM32_XSPI_SR_OFFSET         0x0020 /* Status register */
+#define STM32_XSPI_FCR_OFFSET        0x0024 /* Flag clear register */
+#define STM32_XSPI_DLR_OFFSET        0x0040 /* Data length register */
+#define STM32_XSPI_AR_OFFSET         0x0048 /* Address register */
+#define STM32_XSPI_DR_OFFSET         0x0050 /* Data register */
+#define STM32_XSPI_PSMKR_OFFSET      0x0080 /* Polling status mask */
+#define STM32_XSPI_PSMAR_OFFSET      0x0088 /* Polling status match */
+#define STM32_XSPI_PIR_OFFSET        0x0090 /* Polling interval */
+#define STM32_XSPI_CCR_OFFSET        0x0100 /* Communication configuration */
+#define STM32_XSPI_TCR_OFFSET        0x0108 /* Timing configuration */
+#define STM32_XSPI_IR_OFFSET         0x0110 /* Instruction register */
+#define STM32_XSPI_ABR_OFFSET        0x0120 /* Alternate bytes register */
+#define STM32_XSPI_LPTR_OFFSET       0x0130 /* Low-power timeout */
+#define STM32_XSPI_WPCCR_OFFSET      0x0140 /* Wrap communication config */
+#define STM32_XSPI_WPTCR_OFFSET      0x0148 /* Wrap timing config */
+#define STM32_XSPI_WPIR_OFFSET       0x0150 /* Wrap instruction */
+#define STM32_XSPI_WPABR_OFFSET      0x0160 /* Wrap alternate bytes */
+#define STM32_XSPI_WCCR_OFFSET       0x0180 /* Write communication config */
+#define STM32_XSPI_WTCR_OFFSET       0x0188 /* Write timing config */
+#define STM32_XSPI_WIR_OFFSET        0x0190 /* Write instruction */
+#define STM32_XSPI_WABR_OFFSET       0x01a0 /* Write alternate bytes */
+#define STM32_XSPI_HLCR_OFFSET       0x0200 /* HyperBus latency config */
+#define STM32_XSPI_CALFCR_OFFSET     0x0210 /* Full-cycle calibration */
+#define STM32_XSPI_CALMR_OFFSET      0x0218 /* Master calibration */
+#define STM32_XSPI_CALSOR_OFFSET     0x0220 /* Output calibration */
+#define STM32_XSPI_CALSIR_OFFSET     0x0228 /* Input calibration */
+
+#define STM32_XSPIM_CR_OFFSET        0x0000 /* XSPIM control */
+
+/* Register Addresses *******************************************************/
+
+#define STM32_XSPI1_CR               (STM32_XSPI1_R_BASE + 
STM32_XSPI_CR_OFFSET)
+#define STM32_XSPI1_DCR1             (STM32_XSPI1_R_BASE + 
STM32_XSPI_DCR1_OFFSET)
+#define STM32_XSPI1_DCR2             (STM32_XSPI1_R_BASE + 
STM32_XSPI_DCR2_OFFSET)
+#define STM32_XSPI1_DCR3             (STM32_XSPI1_R_BASE + 
STM32_XSPI_DCR3_OFFSET)
+#define STM32_XSPI1_DCR4             (STM32_XSPI1_R_BASE + 
STM32_XSPI_DCR4_OFFSET)
+#define STM32_XSPI1_SR               (STM32_XSPI1_R_BASE + 
STM32_XSPI_SR_OFFSET)
+#define STM32_XSPI1_FCR              (STM32_XSPI1_R_BASE + 
STM32_XSPI_FCR_OFFSET)
+#define STM32_XSPI1_DLR              (STM32_XSPI1_R_BASE + 
STM32_XSPI_DLR_OFFSET)
+#define STM32_XSPI1_AR               (STM32_XSPI1_R_BASE + 
STM32_XSPI_AR_OFFSET)
+#define STM32_XSPI1_DR               (STM32_XSPI1_R_BASE + 
STM32_XSPI_DR_OFFSET)
+#define STM32_XSPI1_PSMKR            (STM32_XSPI1_R_BASE + 
STM32_XSPI_PSMKR_OFFSET)
+#define STM32_XSPI1_PSMAR            (STM32_XSPI1_R_BASE + 
STM32_XSPI_PSMAR_OFFSET)
+#define STM32_XSPI1_PIR              (STM32_XSPI1_R_BASE + 
STM32_XSPI_PIR_OFFSET)
+#define STM32_XSPI1_CCR              (STM32_XSPI1_R_BASE + 
STM32_XSPI_CCR_OFFSET)
+#define STM32_XSPI1_TCR              (STM32_XSPI1_R_BASE + 
STM32_XSPI_TCR_OFFSET)
+#define STM32_XSPI1_IR               (STM32_XSPI1_R_BASE + 
STM32_XSPI_IR_OFFSET)
+#define STM32_XSPI1_ABR              (STM32_XSPI1_R_BASE + 
STM32_XSPI_ABR_OFFSET)
+#define STM32_XSPI1_LPTR             (STM32_XSPI1_R_BASE + 
STM32_XSPI_LPTR_OFFSET)
+#define STM32_XSPI1_WPCCR            (STM32_XSPI1_R_BASE + 
STM32_XSPI_WPCCR_OFFSET)
+#define STM32_XSPI1_WPTCR            (STM32_XSPI1_R_BASE + 
STM32_XSPI_WPTCR_OFFSET)
+#define STM32_XSPI1_WPIR             (STM32_XSPI1_R_BASE + 
STM32_XSPI_WPIR_OFFSET)
+#define STM32_XSPI1_WPABR            (STM32_XSPI1_R_BASE + 
STM32_XSPI_WPABR_OFFSET)
+#define STM32_XSPI1_WCCR             (STM32_XSPI1_R_BASE + 
STM32_XSPI_WCCR_OFFSET)
+#define STM32_XSPI1_WTCR             (STM32_XSPI1_R_BASE + 
STM32_XSPI_WTCR_OFFSET)
+#define STM32_XSPI1_WIR              (STM32_XSPI1_R_BASE + 
STM32_XSPI_WIR_OFFSET)
+#define STM32_XSPI1_WABR             (STM32_XSPI1_R_BASE + 
STM32_XSPI_WABR_OFFSET)
+#define STM32_XSPI1_HLCR             (STM32_XSPI1_R_BASE + 
STM32_XSPI_HLCR_OFFSET)
+#define STM32_XSPI1_CALFCR           (STM32_XSPI1_R_BASE + 
STM32_XSPI_CALFCR_OFFSET)
+#define STM32_XSPI1_CALMR            (STM32_XSPI1_R_BASE + 
STM32_XSPI_CALMR_OFFSET)
+#define STM32_XSPI1_CALSOR           (STM32_XSPI1_R_BASE + 
STM32_XSPI_CALSOR_OFFSET)
+#define STM32_XSPI1_CALSIR           (STM32_XSPI1_R_BASE + 
STM32_XSPI_CALSIR_OFFSET)
+
+#define STM32_XSPI2_CR               (STM32_XSPI2_R_BASE + 
STM32_XSPI_CR_OFFSET)
+#define STM32_XSPI2_DCR1             (STM32_XSPI2_R_BASE + 
STM32_XSPI_DCR1_OFFSET)
+#define STM32_XSPI2_DCR2             (STM32_XSPI2_R_BASE + 
STM32_XSPI_DCR2_OFFSET)
+#define STM32_XSPI2_DCR3             (STM32_XSPI2_R_BASE + 
STM32_XSPI_DCR3_OFFSET)
+#define STM32_XSPI2_DCR4             (STM32_XSPI2_R_BASE + 
STM32_XSPI_DCR4_OFFSET)
+#define STM32_XSPI2_SR               (STM32_XSPI2_R_BASE + 
STM32_XSPI_SR_OFFSET)
+#define STM32_XSPI2_FCR              (STM32_XSPI2_R_BASE + 
STM32_XSPI_FCR_OFFSET)
+#define STM32_XSPI2_DLR              (STM32_XSPI2_R_BASE + 
STM32_XSPI_DLR_OFFSET)
+#define STM32_XSPI2_AR               (STM32_XSPI2_R_BASE + 
STM32_XSPI_AR_OFFSET)
+#define STM32_XSPI2_DR               (STM32_XSPI2_R_BASE + 
STM32_XSPI_DR_OFFSET)
+#define STM32_XSPI2_PSMKR            (STM32_XSPI2_R_BASE + 
STM32_XSPI_PSMKR_OFFSET)
+#define STM32_XSPI2_PSMAR            (STM32_XSPI2_R_BASE + 
STM32_XSPI_PSMAR_OFFSET)
+#define STM32_XSPI2_PIR              (STM32_XSPI2_R_BASE + 
STM32_XSPI_PIR_OFFSET)
+#define STM32_XSPI2_CCR              (STM32_XSPI2_R_BASE + 
STM32_XSPI_CCR_OFFSET)
+#define STM32_XSPI2_TCR              (STM32_XSPI2_R_BASE + 
STM32_XSPI_TCR_OFFSET)
+#define STM32_XSPI2_IR               (STM32_XSPI2_R_BASE + 
STM32_XSPI_IR_OFFSET)
+#define STM32_XSPI2_ABR              (STM32_XSPI2_R_BASE + 
STM32_XSPI_ABR_OFFSET)
+#define STM32_XSPI2_LPTR             (STM32_XSPI2_R_BASE + 
STM32_XSPI_LPTR_OFFSET)
+#define STM32_XSPI2_WPCCR            (STM32_XSPI2_R_BASE + 
STM32_XSPI_WPCCR_OFFSET)
+#define STM32_XSPI2_WPTCR            (STM32_XSPI2_R_BASE + 
STM32_XSPI_WPTCR_OFFSET)
+#define STM32_XSPI2_WPIR             (STM32_XSPI2_R_BASE + 
STM32_XSPI_WPIR_OFFSET)
+#define STM32_XSPI2_WPABR            (STM32_XSPI2_R_BASE + 
STM32_XSPI_WPABR_OFFSET)
+#define STM32_XSPI2_WCCR             (STM32_XSPI2_R_BASE + 
STM32_XSPI_WCCR_OFFSET)
+#define STM32_XSPI2_WTCR             (STM32_XSPI2_R_BASE + 
STM32_XSPI_WTCR_OFFSET)
+#define STM32_XSPI2_WIR              (STM32_XSPI2_R_BASE + 
STM32_XSPI_WIR_OFFSET)
+#define STM32_XSPI2_WABR             (STM32_XSPI2_R_BASE + 
STM32_XSPI_WABR_OFFSET)
+#define STM32_XSPI2_HLCR             (STM32_XSPI2_R_BASE + 
STM32_XSPI_HLCR_OFFSET)
+#define STM32_XSPI2_CALFCR           (STM32_XSPI2_R_BASE + 
STM32_XSPI_CALFCR_OFFSET)
+#define STM32_XSPI2_CALMR            (STM32_XSPI2_R_BASE + 
STM32_XSPI_CALMR_OFFSET)
+#define STM32_XSPI2_CALSOR           (STM32_XSPI2_R_BASE + 
STM32_XSPI_CALSOR_OFFSET)
+#define STM32_XSPI2_CALSIR           (STM32_XSPI2_R_BASE + 
STM32_XSPI_CALSIR_OFFSET)
+
+#define STM32_XSPIM_CR               (STM32_XSPIM_BASE + STM32_XSPIM_CR_OFFSET)
+
+/* Register Bitfield Definitions ********************************************/
+
+/* Control register *********************************************************/
+
+#define XSPI_CR_EN                   (1 << 0)  /* XSPI enable */
+#define XSPI_CR_ABORT                (1 << 1)  /* Abort request */
+#define XSPI_CR_DMAEN                (1 << 2)  /* DMA enable */
+#define XSPI_CR_TCEN                 (1 << 3)  /* Timeout enable */
+#define XSPI_CR_DMM                  (1 << 6)  /* Dual-memory mode */
+#define XSPI_CR_FTHRES_SHIFT         (8)       /* FIFO threshold level */
+#define XSPI_CR_FTHRES_MASK          (31 << XSPI_CR_FTHRES_SHIFT)
+#  define XSPI_CR_FTHRES(n)          (((n) - 1) << XSPI_CR_FTHRES_SHIFT)
+#define XSPI_CR_TEIE                 (1 << 16) /* Transfer-error interrupt */
+#define XSPI_CR_TCIE                 (1 << 17) /* Transfer-complete interrupt 
*/
+#define XSPI_CR_FTIE                 (1 << 18) /* FIFO-threshold interrupt */
+#define XSPI_CR_SMIE                 (1 << 19) /* Status-match interrupt */
+#define XSPI_CR_TOIE                 (1 << 20) /* Timeout interrupt */
+#define XSPI_CR_APMS                 (1 << 22) /* Automatic-polling stop */
+#define XSPI_CR_PMM                  (1 << 23) /* Polling match mode */
+#define XSPI_CR_CSSEL                (1 << 24) /* Chip-select selection */
+#define XSPI_CR_FMODE_SHIFT          (28)      /* Functional mode */
+#define XSPI_CR_FMODE_MASK           (3 << XSPI_CR_FMODE_SHIFT)
+#  define XSPI_CR_FMODE_WRITE        (0 << XSPI_CR_FMODE_SHIFT)
+#  define XSPI_CR_FMODE_READ         (1 << XSPI_CR_FMODE_SHIFT)
+#  define XSPI_CR_FMODE_POLLING      (2 << XSPI_CR_FMODE_SHIFT)
+#  define XSPI_CR_FMODE_MEMORY       (3 << XSPI_CR_FMODE_SHIFT)
+#define XSPI_CR_MSEL_SHIFT           (30)      /* Memory select */
+#define XSPI_CR_MSEL_MASK            (3 << XSPI_CR_MSEL_SHIFT)
+
+/* Device configuration registers *******************************************/
+
+#define XSPI_DCR1_CKMODE             (1 << 0) /* Clock mode 3 */
+#define XSPI_DCR1_FRCK               (1 << 1) /* Free-running clock */
+#define XSPI_DCR1_CSHT_SHIFT         (8)      /* Chip-select high time */
+#define XSPI_DCR1_CSHT_MASK          (0x3f << XSPI_DCR1_CSHT_SHIFT)
+#  define XSPI_DCR1_CSHT(n)          (((n) - 1) << XSPI_DCR1_CSHT_SHIFT)
+#define XSPI_DCR1_DEVSIZE_SHIFT      (16)     /* Device size */
+#define XSPI_DCR1_DEVSIZE_MASK       (31 << XSPI_DCR1_DEVSIZE_SHIFT)
+#  define XSPI_DCR1_DEVSIZE(n)       ((n) << XSPI_DCR1_DEVSIZE_SHIFT)
+#define XSPI_DCR1_MTYP_SHIFT         (24)     /* Memory type */
+#define XSPI_DCR1_MTYP_MASK          (7 << XSPI_DCR1_MTYP_SHIFT)
+#  define XSPI_DCR1_MTYP(n)          ((n) << XSPI_DCR1_MTYP_SHIFT)
+
+#define XSPI_DCR2_PRESCALER_SHIFT    (0)  /* Clock prescaler */
+#define XSPI_DCR2_PRESCALER_MASK     (0xff << XSPI_DCR2_PRESCALER_SHIFT)
+#  define XSPI_DCR2_PRESCALER(n)     ((n) << XSPI_DCR2_PRESCALER_SHIFT)
+#define XSPI_DCR2_WRAPSIZE_SHIFT     (16) /* Wrap size */
+#define XSPI_DCR2_WRAPSIZE_MASK      (7 << XSPI_DCR2_WRAPSIZE_SHIFT)
+#  define XSPI_DCR2_WRAPSIZE(n)      ((n) << XSPI_DCR2_WRAPSIZE_SHIFT)
+
+#define XSPI_DCR3_MAXTRAN_SHIFT      (0)  /* Maximum transfer */
+#define XSPI_DCR3_MAXTRAN_MASK       (0xff << XSPI_DCR3_MAXTRAN_SHIFT)
+#  define XSPI_DCR3_MAXTRAN(n)       ((n) << XSPI_DCR3_MAXTRAN_SHIFT)
+#define XSPI_DCR3_CSBOUND_SHIFT      (16) /* CS boundary */
+#define XSPI_DCR3_CSBOUND_MASK       (31 << XSPI_DCR3_CSBOUND_SHIFT)
+#  define XSPI_DCR3_CSBOUND(n)       ((n) << XSPI_DCR3_CSBOUND_SHIFT)
+
+#define XSPI_DCR4_REFRESH_SHIFT      (0) /* Refresh rate */
+#define XSPI_DCR4_REFRESH_MASK       (0xffffffff << XSPI_DCR4_REFRESH_SHIFT)
+#  define XSPI_DCR4_REFRESH(n)       ((n) << XSPI_DCR4_REFRESH_SHIFT)
+
+/* Status and flag clear registers ******************************************/
+
+#define XSPI_SR_TEF                  (1 << 0) /* Transfer error */
+#define XSPI_SR_TCF                  (1 << 1) /* Transfer complete */
+#define XSPI_SR_FTF                  (1 << 2) /* FIFO threshold */
+#define XSPI_SR_SMF                  (1 << 3) /* Status match */
+#define XSPI_SR_TOF                  (1 << 4) /* Timeout */
+#define XSPI_SR_BUSY                 (1 << 5) /* Busy */
+#define XSPI_SR_FLEVEL_SHIFT         (8)      /* FIFO level */
+#define XSPI_SR_FLEVEL_MASK          (0x3f << XSPI_SR_FLEVEL_SHIFT)
+
+#define XSPI_FCR_CTEF                (1 << 0) /* Clear transfer error */
+#define XSPI_FCR_CTCF                (1 << 1) /* Clear transfer complete */
+#define XSPI_FCR_CSMF                (1 << 3) /* Clear status match */
+#define XSPI_FCR_CTOF                (1 << 4) /* Clear timeout */
+#define XSPI_FCR_ALL                 (XSPI_FCR_CTEF | XSPI_FCR_CTCF | 
XSPI_FCR_CSMF | XSPI_FCR_CTOF)
+
+/* Data, address and polling registers **************************************/
+
+#define XSPI_DLR_DL_SHIFT            (0) /* Data length */
+#define XSPI_DLR_DL_MASK             (0xffffffff << XSPI_DLR_DL_SHIFT)
+#define XSPI_AR_ADDRESS_SHIFT        (0) /* Address */
+#define XSPI_AR_ADDRESS_MASK         (0xffffffff << XSPI_AR_ADDRESS_SHIFT)
+#define XSPI_DR_DATA_SHIFT           (0) /* Data */
+#define XSPI_DR_DATA_MASK            (0xffffffff << XSPI_DR_DATA_SHIFT)
+#define XSPI_PSMKR_MASK_SHIFT        (0) /* Status mask */
+#define XSPI_PSMKR_MASK_MASK         (0xffffffff << XSPI_PSMKR_MASK_SHIFT)
+#define XSPI_PSMAR_MATCH_SHIFT       (0) /* Status match */
+#define XSPI_PSMAR_MATCH_MASK        (0xffffffff << XSPI_PSMAR_MATCH_SHIFT)
+#define XSPI_PIR_INTERVAL_SHIFT      (0) /* Polling interval */
+#define XSPI_PIR_INTERVAL_MASK       (0xffff << XSPI_PIR_INTERVAL_SHIFT)
+#  define XSPI_PIR_INTERVAL(n)       ((n) << XSPI_PIR_INTERVAL_SHIFT)
+
+/* Communication and timing registers ***************************************/
+
+#define XSPI_CCR_IMODE_SHIFT         (0)       /* Instruction mode */
+#define XSPI_CCR_IMODE_MASK          (7 << XSPI_CCR_IMODE_SHIFT)
+#  define XSPI_CCR_IMODE(n)          ((n) << XSPI_CCR_IMODE_SHIFT)
+#define XSPI_CCR_IDTR                (1 << 3)  /* Instruction DTR */
+#define XSPI_CCR_ISIZE_SHIFT         (4)       /* Instruction size */
+#define XSPI_CCR_ISIZE_MASK          (3 << XSPI_CCR_ISIZE_SHIFT)
+#  define XSPI_CCR_ISIZE(n)          ((n) << XSPI_CCR_ISIZE_SHIFT)
+#define XSPI_CCR_ADMODE_SHIFT        (8)       /* Address mode */
+#define XSPI_CCR_ADMODE_MASK         (7 << XSPI_CCR_ADMODE_SHIFT)
+#  define XSPI_CCR_ADMODE(n)         ((n) << XSPI_CCR_ADMODE_SHIFT)
+#define XSPI_CCR_ADDTR               (1 << 11) /* Address DTR */
+#define XSPI_CCR_ADSIZE_SHIFT        (12)      /* Address size */
+#define XSPI_CCR_ADSIZE_MASK         (3 << XSPI_CCR_ADSIZE_SHIFT)
+#  define XSPI_CCR_ADSIZE(n)         ((n) << XSPI_CCR_ADSIZE_SHIFT)
+#define XSPI_CCR_ABMODE_SHIFT        (16)      /* Alternate bytes mode */
+#define XSPI_CCR_ABMODE_MASK         (7 << XSPI_CCR_ABMODE_SHIFT)
+#  define XSPI_CCR_ABMODE(n)         ((n) << XSPI_CCR_ABMODE_SHIFT)
+#define XSPI_CCR_ABDTR               (1 << 19) /* Alternate bytes DTR */
+#define XSPI_CCR_ABSIZE_SHIFT        (20)      /* Alternate bytes size */
+#define XSPI_CCR_ABSIZE_MASK         (3 << XSPI_CCR_ABSIZE_SHIFT)
+#  define XSPI_CCR_ABSIZE(n)         ((n) << XSPI_CCR_ABSIZE_SHIFT)
+#define XSPI_CCR_DMODE_SHIFT         (24)      /* Data mode */
+#define XSPI_CCR_DMODE_MASK          (7 << XSPI_CCR_DMODE_SHIFT)
+#  define XSPI_CCR_DMODE(n)          ((n) << XSPI_CCR_DMODE_SHIFT)
+#define XSPI_CCR_DDTR                (1 << 27) /* Data DTR */
+#define XSPI_CCR_DQSE                (1 << 29) /* DQS enable */
+
+#define XSPI_TCR_DCYC_SHIFT          (0)       /* Dummy cycles */
+#define XSPI_TCR_DCYC_MASK           (31 << XSPI_TCR_DCYC_SHIFT)
+#  define XSPI_TCR_DCYC(n)           ((n) << XSPI_TCR_DCYC_SHIFT)
+#define XSPI_TCR_DHQC                (1 << 28) /* Delay hold quarter cycle */
+#define XSPI_TCR_SSHIFT              (1 << 30) /* Sample shift */
+
+#define XSPI_IR_INSTRUCTION_SHIFT    (0) /* Instruction */
+#define XSPI_IR_INSTRUCTION_MASK     (0xffffffff << XSPI_IR_INSTRUCTION_SHIFT)
+#define XSPI_ABR_ALTERNATE_SHIFT     (0) /* Alternate bytes */
+#define XSPI_ABR_ALTERNATE_MASK      (0xffffffff << XSPI_ABR_ALTERNATE_SHIFT)
+#define XSPI_LPTR_TIMEOUT_SHIFT      (0) /* Timeout period */
+#define XSPI_LPTR_TIMEOUT_MASK       (0xffff << XSPI_LPTR_TIMEOUT_SHIFT)
+#  define XSPI_LPTR_TIMEOUT(n)       ((n) << XSPI_LPTR_TIMEOUT_SHIFT)
+
+/* Wrap communication and timing registers **********************************/
+
+#define XSPI_WPCCR_IMODE_SHIFT       (0)       /* Instruction mode */
+#define XSPI_WPCCR_IMODE_MASK        (7 << XSPI_WPCCR_IMODE_SHIFT)
+#  define XSPI_WPCCR_IMODE(n)        ((n) << XSPI_WPCCR_IMODE_SHIFT)
+#define XSPI_WPCCR_IDTR              (1 << 3)  /* Instruction DTR */
+#define XSPI_WPCCR_ISIZE_SHIFT       (4)       /* Instruction size */
+#define XSPI_WPCCR_ISIZE_MASK        (3 << XSPI_WPCCR_ISIZE_SHIFT)
+#  define XSPI_WPCCR_ISIZE(n)        ((n) << XSPI_WPCCR_ISIZE_SHIFT)
+#define XSPI_WPCCR_ADMODE_SHIFT      (8)       /* Address mode */
+#define XSPI_WPCCR_ADMODE_MASK       (7 << XSPI_WPCCR_ADMODE_SHIFT)
+#  define XSPI_WPCCR_ADMODE(n)       ((n) << XSPI_WPCCR_ADMODE_SHIFT)
+#define XSPI_WPCCR_ADDTR             (1 << 11) /* Address DTR */
+#define XSPI_WPCCR_ADSIZE_SHIFT      (12)      /* Address size */
+#define XSPI_WPCCR_ADSIZE_MASK       (3 << XSPI_WPCCR_ADSIZE_SHIFT)
+#  define XSPI_WPCCR_ADSIZE(n)       ((n) << XSPI_WPCCR_ADSIZE_SHIFT)
+#define XSPI_WPCCR_ABMODE_SHIFT      (16)      /* Alternate bytes mode */
+#define XSPI_WPCCR_ABMODE_MASK       (7 << XSPI_WPCCR_ABMODE_SHIFT)
+#  define XSPI_WPCCR_ABMODE(n)       ((n) << XSPI_WPCCR_ABMODE_SHIFT)
+#define XSPI_WPCCR_ABDTR             (1 << 19) /* Alternate bytes DTR */
+#define XSPI_WPCCR_ABSIZE_SHIFT      (20)      /* Alternate bytes size */
+#define XSPI_WPCCR_ABSIZE_MASK       (3 << XSPI_WPCCR_ABSIZE_SHIFT)
+#  define XSPI_WPCCR_ABSIZE(n)       ((n) << XSPI_WPCCR_ABSIZE_SHIFT)
+#define XSPI_WPCCR_DMODE_SHIFT       (24)      /* Data mode */
+#define XSPI_WPCCR_DMODE_MASK        (7 << XSPI_WPCCR_DMODE_SHIFT)
+#  define XSPI_WPCCR_DMODE(n)        ((n) << XSPI_WPCCR_DMODE_SHIFT)
+#define XSPI_WPCCR_DDTR              (1 << 27) /* Data DTR */
+#define XSPI_WPCCR_DQSE              (1 << 29) /* DQS enable */
+
+#define XSPI_WPTCR_DCYC_SHIFT        (0)       /* Dummy cycles */
+#define XSPI_WPTCR_DCYC_MASK         (31 << XSPI_WPTCR_DCYC_SHIFT)
+#  define XSPI_WPTCR_DCYC(n)         ((n) << XSPI_WPTCR_DCYC_SHIFT)
+#define XSPI_WPTCR_DHQC              (1 << 28) /* Delay hold quarter cycle */
+#define XSPI_WPTCR_SSHIFT            (1 << 30) /* Sample shift */
+
+#define XSPI_WPIR_INSTRUCTION_SHIFT  (0) /* Instruction */
+#define XSPI_WPIR_INSTRUCTION_MASK   (0xffffffff << 
XSPI_WPIR_INSTRUCTION_SHIFT)
+#define XSPI_WPABR_ALTERNATE_SHIFT   (0) /* Alternate bytes */
+#define XSPI_WPABR_ALTERNATE_MASK    (0xffffffff << XSPI_WPABR_ALTERNATE_SHIFT)
+
+/* Write communication and timing registers *********************************/
+
+#define XSPI_WCCR_IMODE_SHIFT        (0)       /* Instruction mode */
+#define XSPI_WCCR_IMODE_MASK         (7 << XSPI_WCCR_IMODE_SHIFT)
+#  define XSPI_WCCR_IMODE(n)         ((n) << XSPI_WCCR_IMODE_SHIFT)
+#define XSPI_WCCR_IDTR               (1 << 3)  /* Instruction DTR */
+#define XSPI_WCCR_ISIZE_SHIFT        (4)       /* Instruction size */
+#define XSPI_WCCR_ISIZE_MASK         (3 << XSPI_WCCR_ISIZE_SHIFT)
+#  define XSPI_WCCR_ISIZE(n)         ((n) << XSPI_WCCR_ISIZE_SHIFT)
+#define XSPI_WCCR_ADMODE_SHIFT       (8)       /* Address mode */
+#define XSPI_WCCR_ADMODE_MASK        (7 << XSPI_WCCR_ADMODE_SHIFT)
+#  define XSPI_WCCR_ADMODE(n)        ((n) << XSPI_WCCR_ADMODE_SHIFT)
+#define XSPI_WCCR_ADDTR              (1 << 11) /* Address DTR */
+#define XSPI_WCCR_ADSIZE_SHIFT       (12)      /* Address size */
+#define XSPI_WCCR_ADSIZE_MASK        (3 << XSPI_WCCR_ADSIZE_SHIFT)
+#  define XSPI_WCCR_ADSIZE(n)        ((n) << XSPI_WCCR_ADSIZE_SHIFT)
+#define XSPI_WCCR_ABMODE_SHIFT       (16)      /* Alternate bytes mode */
+#define XSPI_WCCR_ABMODE_MASK        (7 << XSPI_WCCR_ABMODE_SHIFT)
+#  define XSPI_WCCR_ABMODE(n)        ((n) << XSPI_WCCR_ABMODE_SHIFT)
+#define XSPI_WCCR_ABDTR              (1 << 19) /* Alternate bytes DTR */
+#define XSPI_WCCR_ABSIZE_SHIFT       (20)      /* Alternate bytes size */
+#define XSPI_WCCR_ABSIZE_MASK        (3 << XSPI_WCCR_ABSIZE_SHIFT)
+#  define XSPI_WCCR_ABSIZE(n)        ((n) << XSPI_WCCR_ABSIZE_SHIFT)
+#define XSPI_WCCR_DMODE_SHIFT        (24)      /* Data mode */
+#define XSPI_WCCR_DMODE_MASK         (7 << XSPI_WCCR_DMODE_SHIFT)
+#  define XSPI_WCCR_DMODE(n)         ((n) << XSPI_WCCR_DMODE_SHIFT)
+#define XSPI_WCCR_DDTR               (1 << 27) /* Data DTR */
+#define XSPI_WCCR_DQSE               (1 << 29) /* DQS enable */
+
+#define XSPI_WTCR_DCYC_SHIFT         (0) /* Dummy cycles */
+#define XSPI_WTCR_DCYC_MASK          (31 << XSPI_WTCR_DCYC_SHIFT)
+#  define XSPI_WTCR_DCYC(n)          ((n) << XSPI_WTCR_DCYC_SHIFT)
+
+#define XSPI_WIR_INSTRUCTION_SHIFT   (0) /* Instruction */
+#define XSPI_WIR_INSTRUCTION_MASK    (0xffffffff << XSPI_WIR_INSTRUCTION_SHIFT)
+#define XSPI_WABR_ALTERNATE_SHIFT    (0) /* Alternate bytes */
+#define XSPI_WABR_ALTERNATE_MASK     (0xffffffff << XSPI_WABR_ALTERNATE_SHIFT)
+
+/* HyperBus latency register ************************************************/
+
+#define XSPI_HLCR_LM                 (1 << 0) /* Latency mode */
+#define XSPI_HLCR_WZL                (1 << 1) /* Write zero latency */
+#define XSPI_HLCR_TACC_SHIFT         (8)      /* Access time */
+#define XSPI_HLCR_TACC_MASK          (0xff << XSPI_HLCR_TACC_SHIFT)
+#define XSPI_HLCR_TRWR_SHIFT         (16)     /* Read write recovery time */
+#define XSPI_HLCR_TRWR_MASK          (0xff << XSPI_HLCR_TRWR_SHIFT)
+
+/* Calibration registers ****************************************************/
+
+#define XSPI_CALFCR_FINE_SHIFT       (0)       /* Fine calibration */
+#define XSPI_CALFCR_FINE_MASK        (0x7f << XSPI_CALFCR_FINE_SHIFT)
+#  define XSPI_CALFCR_FINE(n)        ((n) << XSPI_CALFCR_FINE_SHIFT)
+#define XSPI_CALFCR_COARSE_SHIFT     (16)      /* Coarse calibration */
+#define XSPI_CALFCR_COARSE_MASK      (31 << XSPI_CALFCR_COARSE_SHIFT)
+#  define XSPI_CALFCR_COARSE(n)      ((n) << XSPI_CALFCR_COARSE_SHIFT)
+#define XSPI_CALFCR_CALMAX           (1 << 31) /* Calibration max value */
+
+#define XSPI_CALMR_FINE_SHIFT        (0)  /* Fine calibration */
+#define XSPI_CALMR_FINE_MASK         (0x7f << XSPI_CALMR_FINE_SHIFT)
+#  define XSPI_CALMR_FINE(n)         ((n) << XSPI_CALMR_FINE_SHIFT)
+#define XSPI_CALMR_COARSE_SHIFT      (16) /* Coarse calibration */
+#define XSPI_CALMR_COARSE_MASK       (31 << XSPI_CALMR_COARSE_SHIFT)
+#  define XSPI_CALMR_COARSE(n)       ((n) << XSPI_CALMR_COARSE_SHIFT)
+
+#define XSPI_CALSOR_FINE_SHIFT       (0)  /* Fine calibration */
+#define XSPI_CALSOR_FINE_MASK        (0x7f << XSPI_CALSOR_FINE_SHIFT)
+#  define XSPI_CALSOR_FINE(n)        ((n) << XSPI_CALSOR_FINE_SHIFT)
+#define XSPI_CALSOR_COARSE_SHIFT     (16) /* Coarse calibration */
+#define XSPI_CALSOR_COARSE_MASK      (31 << XSPI_CALSOR_COARSE_SHIFT)
+#  define XSPI_CALSOR_COARSE(n)      ((n) << XSPI_CALSOR_COARSE_SHIFT)
+
+#define XSPI_CALSIR_FINE_SHIFT       (0)  /* Fine calibration */
+#define XSPI_CALSIR_FINE_MASK        (0x7f << XSPI_CALSIR_FINE_SHIFT)
+#  define XSPI_CALSIR_FINE(n)        ((n) << XSPI_CALSIR_FINE_SHIFT)
+#define XSPI_CALSIR_COARSE_SHIFT     (16) /* Coarse calibration */
+#define XSPI_CALSIR_COARSE_MASK      (31 << XSPI_CALSIR_COARSE_SHIFT)
+#  define XSPI_CALSIR_COARSE(n)      ((n) << XSPI_CALSIR_COARSE_SHIFT)
+
+/* XSPI I/O manager control register ****************************************/
+
+#define XSPIM_CR_MUXEN               (1 << 0) /* Multiplexed mode */
+#define XSPIM_CR_MODE                (1 << 1) /* Multiplexing mode */
+#define XSPIM_CR_CSSEL_OVR_EN        (1 << 4) /* Chip-select override */
+#define XSPIM_CR_CSSEL_OVR_O1        (1 << 5) /* XSPI1 uses nCS2 */
+#define XSPIM_CR_CSSEL_OVR_O2        (1 << 6) /* XSPI2 uses nCS2 */
+#define XSPIM_CR_REQ2ACK_SHIFT       (16)
+#define XSPIM_CR_REQ2ACK_MASK        (0xff << XSPIM_CR_REQ2ACK_SHIFT)
+#  define XSPIM_CR_REQ2ACK(n)        (((n) - 1) << XSPIM_CR_REQ2ACK_SHIFT)
+
+#endif /* __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32H7RSXX_XSPI_H */
diff --git a/arch/arm/src/stm32h7/stm32_xspi.c 
b/arch/arm/src/stm32h7/stm32_xspi.c
new file mode 100644
index 00000000000..0edf27e92fb
--- /dev/null
+++ b/arch/arm/src/stm32h7/stm32_xspi.c
@@ -0,0 +1,1230 @@
+/****************************************************************************
+ * arch/arm/src/stm32h7/stm32_xspi.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <arch/board/board.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/mutex.h>
+#include <nuttx/spi/qspi.h>
+
+#include "arm_internal.h"
+#include "stm32_gpio.h"
+#include "stm32_xspi.h"
+#include "hardware/stm32h7rsxx_pwr.h"
+#include "hardware/stm32h7rsxx_rcc.h"
+#include "hardware/stm32h7rsxx_sbs.h"
+#include "hardware/stm32h7rsxx_xspi.h"
+
+#ifdef CONFIG_STM32_XSPI
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define XSPI_TIMEOUT 1000000
+
+/* MTYP=5 is a reserved encoding in the DCR1 register */
+
+#define XSPI_MEMTYPE_RESERVED 5
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct stm32_xspidev_s
+{
+  struct qspi_dev_s qspi;
+  uint32_t base;
+  mutex_t lock;
+  uint8_t intf;
+  bool initialized;
+  bool memmap;
+  bool sample_shift;
+};
+
+struct stm32_xspi_cmd_s
+{
+  uint32_t instruction;
+  uint32_t address;
+  void *buffer;
+  size_t buflen;
+  uint8_t instruction_lines;
+  uint8_t address_lines;
+  uint8_t data_lines;
+  uint8_t instruction_bits;
+  uint8_t address_bits;
+  uint8_t dummy_cycles;
+  bool dtr;
+  bool write;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int xspi_lock(struct qspi_dev_s *dev, bool lock);
+static uint32_t xspi_setfrequency(struct qspi_dev_s *dev,
+                                  uint32_t frequency);
+static void xspi_setmode(struct qspi_dev_s *dev, enum qspi_mode_e mode);
+static void xspi_setbits(struct qspi_dev_s *dev, int nbits);
+static int xspi_command(struct qspi_dev_s *dev,
+                        struct qspi_cmdinfo_s *cmdinfo);
+static int xspi_memory(struct qspi_dev_s *dev,
+                       struct qspi_meminfo_s *meminfo);
+static void *xspi_alloc(struct qspi_dev_s *dev, size_t buflen);
+static void xspi_free(struct qspi_dev_s *dev, void *buffer);
+static int xspi_mmap_cmd(struct stm32_xspidev_s *priv,
+                         const struct qspi_meminfo_s *meminfo,
+                         bool write);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct qspi_ops_s g_xspi_ops =
+{
+  .lock         = xspi_lock,
+  .setfrequency = xspi_setfrequency,
+  .setmode      = xspi_setmode,
+  .setbits      = xspi_setbits,
+  .command      = xspi_command,
+  .memory       = xspi_memory,
+  .alloc        = xspi_alloc,
+  .free         = xspi_free,
+};
+
+static struct stm32_xspidev_s g_xspi1dev =
+{
+  .qspi =
+  {
+    .ops = &g_xspi_ops,
+  },
+  .base = STM32_XSPI1_R_BASE,
+  .lock = NXMUTEX_INITIALIZER,
+  .intf = 1,
+};
+
+static struct stm32_xspidev_s g_xspi2dev =
+{
+  .qspi =
+  {
+    .ops = &g_xspi_ops,
+  },
+  .base = STM32_XSPI2_R_BASE,
+  .lock = NXMUTEX_INITIALIZER,
+  .intf = 2,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: xspi_getreg
+ *
+ * Description:
+ *   Read an XSPI register.
+ *
+ ****************************************************************************/
+
+static inline uint32_t xspi_getreg(struct stm32_xspidev_s *priv,
+                                   uint32_t offset)
+{
+  return getreg32(priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: xspi_putreg
+ *
+ * Description:
+ *   Write a value to an XSPI register.
+ *
+ ****************************************************************************/
+
+static inline void xspi_putreg(struct stm32_xspidev_s *priv,
+                               uint32_t offset, uint32_t value)
+{
+  putreg32(value, priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: xspi_device
+ *
+ * Description:
+ *   Map an XSPI interface number to its device state structure.
+ *
+ ****************************************************************************/
+
+static struct stm32_xspidev_s *xspi_device(int intf)
+{
+  if (intf == 1)
+    {
+      return &g_xspi1dev;
+    }
+
+  if (intf == 2)
+    {
+      return &g_xspi2dev;
+    }
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Name: xspi_wait
+ *
+ * Description:
+ *   Poll until the masked status register bits equal the given value.
+ *
+ ****************************************************************************/
+
+static int xspi_wait(struct stm32_xspidev_s *priv, uint32_t mask,
+                     uint32_t value)
+{
+  int timeout;
+
+  for (timeout = XSPI_TIMEOUT; timeout > 0; timeout--)
+    {
+      uint32_t status = xspi_getreg(priv, STM32_XSPI_SR_OFFSET);
+
+      if ((status & XSPI_SR_TEF) != 0)
+        {
+          xspi_putreg(priv, STM32_XSPI_FCR_OFFSET, XSPI_FCR_CTEF);
+          return -EIO;
+        }
+
+      if ((status & mask) == value)
+        {
+          return OK;
+        }
+    }
+
+  return -ETIMEDOUT;
+}
+
+/****************************************************************************
+ * Name: xspi_wait_any
+ *
+ * Description:
+ *   Poll until any of the masked status register bits is set.
+ *
+ ****************************************************************************/
+
+static int xspi_wait_any(struct stm32_xspidev_s *priv, uint32_t mask)
+{
+  int timeout;
+
+  for (timeout = XSPI_TIMEOUT; timeout > 0; timeout--)
+    {
+      uint32_t status = xspi_getreg(priv, STM32_XSPI_SR_OFFSET);
+
+      if ((status & XSPI_SR_TEF) != 0)
+        {
+          xspi_putreg(priv, STM32_XSPI_FCR_OFFSET, XSPI_FCR_CTEF);
+          return -EIO;
+        }
+
+      if ((status & mask) != 0)
+        {
+          return OK;
+        }
+    }
+
+  return -ETIMEDOUT;
+}
+
+/****************************************************************************
+ * Name: xspi_size
+ *
+ * Description:
+ *   Convert a bit width (8/16/24/32) to the CCR SIZE field encoding.
+ *
+ ****************************************************************************/
+
+static int xspi_size(uint8_t bits)
+{
+  if (bits == 8 || bits == 16 || bits == 24 || bits == 32)
+    {
+      return (bits >> 3) - 1;
+    }
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: xspi_lines
+ *
+ * Description:
+ *   Convert a line count (0/1/2/4/8) to the CCR MODE field encoding.
+ *
+ ****************************************************************************/
+
+static int xspi_lines(uint8_t lines)
+{
+  switch (lines)
+    {
+      case 0:
+        return 0;
+      case 1:
+        return 1;
+      case 2:
+        return 2;
+      case 4:
+        return 3;
+      case 8:
+        return 4;
+      default:
+        return -EINVAL;
+    }
+}
+
+/****************************************************************************
+ * Name: xspi_ccr
+ *
+ * Description:
+ *   Build the CCR register value for a transfer command.
+ *
+ ****************************************************************************/
+
+static int xspi_ccr(const struct stm32_xspi_cmd_s *cmd, uint32_t *ccr)
+{
+  uint32_t reg = 0;
+  int lines;
+  int size;
+
+  lines = xspi_lines(cmd->instruction_lines);
+  if (lines < 0)
+    {
+      return lines;
+    }
+
+  if (lines != 0)
+    {
+      size = xspi_size(cmd->instruction_bits);
+      if (size < 0)
+        {
+          return size;
+        }
+
+      reg |= XSPI_CCR_IMODE(lines) | XSPI_CCR_ISIZE(size);
+      if (cmd->dtr)
+        {
+          reg |= XSPI_CCR_IDTR;
+        }
+    }
+
+  lines = xspi_lines(cmd->address_lines);
+  if (lines < 0)
+    {
+      return lines;
+    }
+
+  if (lines != 0)
+    {
+      size = xspi_size(cmd->address_bits);
+      if (size < 0)
+        {
+          return size;
+        }
+
+      reg |= XSPI_CCR_ADMODE(lines) | XSPI_CCR_ADSIZE(size);
+      if (cmd->dtr)
+        {
+          reg |= XSPI_CCR_ADDTR;
+        }
+    }
+
+  lines = xspi_lines(cmd->data_lines);
+  if (lines < 0)
+    {
+      return lines;
+    }
+
+  reg |= XSPI_CCR_DMODE(lines);
+  if (cmd->dtr && lines != 0)
+    {
+      reg |= XSPI_CCR_DDTR;
+    }
+
+  if (cmd->dummy_cycles > 31)
+    {
+      return -EINVAL;
+    }
+
+  *ccr = reg;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: xspi_iom_config
+ *
+ * Description:
+ *   Configure the XSPI I/O manager port and chip select routing.
+ *
+ ****************************************************************************/
+
+static void xspi_iom_config(struct stm32_xspidev_s *priv,
+                            const struct stm32_xspi_config_s *config)
+{
+  enum stm32_xspi_iomport_e port1;
+  enum stm32_xspi_iomport_e port2;
+  enum stm32_xspi_cs_e cs1;
+  enum stm32_xspi_cs_e cs2;
+  uint32_t xspi1cr;
+  uint32_t xspi2cr;
+  uint32_t reg;
+
+  reg = getreg32(STM32_XSPIM_CR);
+  port1 = (reg & XSPIM_CR_MODE) != 0 ? STM32_XSPI_IOM_PORT2 :
+                                      STM32_XSPI_IOM_PORT1;
+  port2 = ((reg & XSPIM_CR_MUXEN) != 0) !=
+          ((reg & XSPIM_CR_MODE) != 0) ? STM32_XSPI_IOM_PORT1 :
+                                        STM32_XSPI_IOM_PORT2;
+
+  if ((reg & XSPIM_CR_CSSEL_OVR_EN) == 0)
+    {
+      cs1 = STM32_XSPI_CS_DISABLED;
+      cs2 = STM32_XSPI_CS_DISABLED;
+    }
+  else
+    {
+      cs1 = (reg & XSPIM_CR_CSSEL_OVR_O1) != 0 ? STM32_XSPI_CS_NCS2 :
+                                                 STM32_XSPI_CS_NCS1;
+      cs2 = (reg & XSPIM_CR_CSSEL_OVR_O2) != 0 ? STM32_XSPI_CS_NCS2 :
+                                                 STM32_XSPI_CS_NCS1;
+    }
+
+  if (priv->intf == 1)
+    {
+      port1 = config->iomport;
+      cs1   = config->cs_override;
+    }
+  else
+    {
+      port2 = config->iomport;
+      cs2   = config->cs_override;
+    }
+
+  reg = XSPIM_CR_REQ2ACK(config->req2ack);
+  if (port1 == port2)
+    {
+      reg |= XSPIM_CR_MUXEN;
+    }
+
+  if (port1 == STM32_XSPI_IOM_PORT2)
+    {
+      reg |= XSPIM_CR_MODE;
+    }
+
+  if (cs1 != STM32_XSPI_CS_DISABLED || cs2 != STM32_XSPI_CS_DISABLED)
+    {
+      reg |= XSPIM_CR_CSSEL_OVR_EN;
+    }
+
+  if (cs1 == STM32_XSPI_CS_NCS2)
+    {
+      reg |= XSPIM_CR_CSSEL_OVR_O1;
+    }
+
+  if (cs2 == STM32_XSPI_CS_NCS2)
+    {
+      reg |= XSPIM_CR_CSSEL_OVR_O2;
+    }
+
+  xspi1cr = getreg32(STM32_XSPI1_CR);
+  xspi2cr = getreg32(STM32_XSPI2_CR);
+  modifyreg32(STM32_XSPI1_CR, XSPI_CR_EN, 0);
+  modifyreg32(STM32_XSPI2_CR, XSPI_CR_EN, 0);
+  putreg32(reg, STM32_XSPIM_CR);
+  putreg32(xspi1cr, STM32_XSPI1_CR);
+  putreg32(xspi2cr, STM32_XSPI2_CR);
+}
+
+/****************************************************************************
+ * Name: xspi_compensation_enable
+ *
+ * Description:
+ *   Enable the XSPI I/O compensation cell and wait until it is ready.
+ *
+ ****************************************************************************/
+
+static int xspi_compensation_enable(struct stm32_xspidev_s *priv)
+{
+  uint32_t enable;
+  uint32_t ready;
+  int timeout;
+
+  modifyreg32(STM32_RCC_APB4ENR, 0, RCC_APB4ENR_SBSEN);
+  modifyreg32(STM32_RCC_CR, 0, RCC_CR_CSION);
+
+  for (timeout = XSPI_TIMEOUT; timeout > 0; timeout--)
+    {
+      if ((getreg32(STM32_RCC_CR) & RCC_CR_CSIRDY) != 0)
+        {
+          break;
+        }
+    }
+
+  if (timeout == 0)
+    {
+      return -ETIMEDOUT;
+    }
+
+  if (priv->intf == 1)
+    {
+      enable = SBS_CCCSR_XSPI1_COMP_EN | SBS_CCCSR_XSPI1_IOHSLV;
+      ready  = SBS_CCCSR_XSPI1_COMP_RDY;
+    }
+  else
+    {
+      enable = SBS_CCCSR_XSPI2_COMP_EN | SBS_CCCSR_XSPI2_IOHSLV;
+      ready  = SBS_CCCSR_XSPI2_COMP_RDY;
+    }
+
+  modifyreg32(STM32_SBS_CCCSR, 0, enable);
+  for (timeout = XSPI_TIMEOUT; timeout > 0; timeout--)
+    {
+      if ((getreg32(STM32_SBS_CCCSR) & ready) != 0)
+        {
+          return OK;
+        }
+    }
+
+  return -ETIMEDOUT;
+}
+
+/****************************************************************************
+ * Name: xspi_hw_initialize
+ *
+ * Description:
+ *   One-time hardware initialization: power, clocking and GPIO pins.
+ *
+ ****************************************************************************/
+
+static int xspi_hw_initialize(struct stm32_xspidev_s *priv)
+{
+  if (priv->intf == 1)
+    {
+      modifyreg32(STM32_PWR_CSR2, 0, PWR_CSR2_EN_XSPIM1);
+      modifyreg32(STM32_RCC_CCIPR1, RCC_CCIPR1_XSPI1SEL_MASK,
+                  RCC_CCIPR1_XSPI1SEL_HCLK);
+      modifyreg32(STM32_RCC_AHB5ENR, 0, RCC_AHB5ENR_XSPI1EN |
+                   RCC_AHB5ENR_XSPIMEN);
+
+#ifdef GPIO_XSPI1_CLK
+      stm32_configgpio(GPIO_XSPI1_CLK);
+#endif
+#ifdef GPIO_XSPI1_DQS
+      stm32_configgpio(GPIO_XSPI1_DQS);
+#endif
+#ifdef GPIO_XSPI1_NCS
+      stm32_configgpio(GPIO_XSPI1_NCS);
+#endif
+#ifdef GPIO_XSPI1_IO0
+      stm32_configgpio(GPIO_XSPI1_IO0);
+#endif
+#ifdef GPIO_XSPI1_IO1
+      stm32_configgpio(GPIO_XSPI1_IO1);
+#endif
+#ifdef GPIO_XSPI1_IO2
+      stm32_configgpio(GPIO_XSPI1_IO2);
+#endif
+#ifdef GPIO_XSPI1_IO3
+      stm32_configgpio(GPIO_XSPI1_IO3);
+#endif
+#ifdef GPIO_XSPI1_IO4
+      stm32_configgpio(GPIO_XSPI1_IO4);
+#endif
+#ifdef GPIO_XSPI1_IO5
+      stm32_configgpio(GPIO_XSPI1_IO5);
+#endif
+#ifdef GPIO_XSPI1_IO6
+      stm32_configgpio(GPIO_XSPI1_IO6);
+#endif
+#ifdef GPIO_XSPI1_IO7
+      stm32_configgpio(GPIO_XSPI1_IO7);
+#endif
+    }
+  else
+    {
+      modifyreg32(STM32_PWR_CSR2, 0, PWR_CSR2_EN_XSPIM2);
+      modifyreg32(STM32_RCC_CCIPR1, RCC_CCIPR1_XSPI2SEL_MASK,
+                  RCC_CCIPR1_XSPI2SEL_HCLK);
+      modifyreg32(STM32_RCC_AHB5ENR, 0, RCC_AHB5ENR_XSPI2EN |
+                   RCC_AHB5ENR_XSPIMEN);
+
+#ifdef GPIO_XSPI2_CLK
+      stm32_configgpio(GPIO_XSPI2_CLK);
+#endif
+#ifdef GPIO_XSPI2_DQS
+      stm32_configgpio(GPIO_XSPI2_DQS);
+#endif
+#ifdef GPIO_XSPI2_NCS
+      stm32_configgpio(GPIO_XSPI2_NCS);
+#endif
+#ifdef GPIO_XSPI2_IO0
+      stm32_configgpio(GPIO_XSPI2_IO0);
+#endif
+#ifdef GPIO_XSPI2_IO1
+      stm32_configgpio(GPIO_XSPI2_IO1);
+#endif
+#ifdef GPIO_XSPI2_IO2
+      stm32_configgpio(GPIO_XSPI2_IO2);
+#endif
+#ifdef GPIO_XSPI2_IO3
+      stm32_configgpio(GPIO_XSPI2_IO3);
+#endif
+#ifdef GPIO_XSPI2_IO4
+      stm32_configgpio(GPIO_XSPI2_IO4);
+#endif
+#ifdef GPIO_XSPI2_IO5
+      stm32_configgpio(GPIO_XSPI2_IO5);
+#endif
+#ifdef GPIO_XSPI2_IO6
+      stm32_configgpio(GPIO_XSPI2_IO6);
+#endif
+#ifdef GPIO_XSPI2_IO7
+      stm32_configgpio(GPIO_XSPI2_IO7);
+#endif
+    }
+
+  return xspi_compensation_enable(priv);
+}
+
+/****************************************************************************
+ * Name: xspi_lock
+ *
+ * Description:
+ *   Lock or unlock the XSPI bus for exclusive access.
+ *
+ ****************************************************************************/
+
+static int xspi_lock(struct qspi_dev_s *dev, bool lock)
+{
+  struct stm32_xspidev_s *priv = (struct stm32_xspidev_s *)dev;
+
+  return lock ? nxmutex_lock(&priv->lock) : nxmutex_unlock(&priv->lock);
+}
+
+/****************************************************************************
+ * Name: xspi_setfrequency
+ *
+ * Description:
+ *   Set the XSPI frequency and return the actual frequency selected.
+ *
+ ****************************************************************************/
+
+static uint32_t xspi_setfrequency(struct qspi_dev_s *dev,
+                                  uint32_t frequency)
+{
+  struct stm32_xspidev_s *priv = (struct stm32_xspidev_s *)dev;
+  uint32_t prescaler;
+
+  if (frequency == 0)
+    {
+      return 0;
+    }
+
+  prescaler = (STM32_HCLK_FREQUENCY + frequency - 1) / frequency;
+  if (prescaler < 1)
+    {
+      prescaler = 1;
+    }
+  else if (prescaler > 256)
+    {
+      prescaler = 256;
+    }
+
+  modifyreg32(priv->base + STM32_XSPI_DCR2_OFFSET,
+              XSPI_DCR2_PRESCALER_MASK,
+              XSPI_DCR2_PRESCALER(prescaler - 1));
+  return STM32_HCLK_FREQUENCY / prescaler;
+}
+
+/****************************************************************************
+ * Name: xspi_setmode
+ *
+ * Description:
+ *   Set the XSPI clock mode (mode 0 or mode 3).
+ *
+ ****************************************************************************/
+
+static void xspi_setmode(struct qspi_dev_s *dev, enum qspi_mode_e mode)
+{
+  struct stm32_xspidev_s *priv = (struct stm32_xspidev_s *)dev;
+
+  DEBUGASSERT(mode == QSPIDEV_MODE0 || mode == QSPIDEV_MODE3);
+  modifyreg32(priv->base + STM32_XSPI_DCR1_OFFSET, XSPI_DCR1_CKMODE,
+              mode == QSPIDEV_MODE3 ? XSPI_DCR1_CKMODE : 0);
+}
+
+/****************************************************************************
+ * Name: xspi_setbits
+ *
+ * Description:
+ *   Set the number of bits per word (only 8 bits are supported).
+ *
+ ****************************************************************************/
+
+static void xspi_setbits(struct qspi_dev_s *dev, int nbits)
+{
+  UNUSED(dev);
+  DEBUGASSERT(nbits == 8);
+}
+
+/****************************************************************************
+ * Name: xspi_configure
+ *
+ * Description:
+ *   Validate the configuration and program the XSPI device registers.
+ *
+ ****************************************************************************/
+
+static int xspi_configure(struct stm32_xspidev_s *priv,
+                          const struct stm32_xspi_config_s *config)
+{
+  uint32_t dcr1;
+  uint32_t cr;
+  int ret;
+
+  if (config == NULL || config->memtype == XSPI_MEMTYPE_RESERVED ||
+      config->memtype > STM32_XSPI_MEMTYPE_APMEM_16BIT ||
+      config->iomport > STM32_XSPI_IOM_PORT2 ||
+      config->cs_override > STM32_XSPI_CS_NCS2 || config->devsize > 31 ||
+      config->csht < 1 || config->csht > 64 || config->fthres < 1 ||
+      config->fthres > 32 || config->wrapsize > 7 ||
+      config->csbound > 31 || config->req2ack < 1 ||
+      config->req2ack > 256)
+    {
+      return -EINVAL;
+    }
+
+  ret = xspi_wait(priv, XSPI_SR_BUSY, 0);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  cr = xspi_getreg(priv, STM32_XSPI_CR_OFFSET);
+  xspi_putreg(priv, STM32_XSPI_CR_OFFSET, cr & ~XSPI_CR_EN);
+  xspi_iom_config(priv, config);
+
+  dcr1 = XSPI_DCR1_CSHT(config->csht) |
+         XSPI_DCR1_DEVSIZE(config->devsize) |
+         XSPI_DCR1_MTYP(config->memtype);
+  if (config->clock_mode3)
+    {
+      dcr1 |= XSPI_DCR1_CKMODE;
+    }
+
+  if (config->free_running)
+    {
+      dcr1 |= XSPI_DCR1_FRCK;
+    }
+
+  xspi_putreg(priv, STM32_XSPI_DCR1_OFFSET, dcr1);
+  xspi_putreg(priv, STM32_XSPI_DCR2_OFFSET,
+              XSPI_DCR2_PRESCALER(config->prescaler) |
+              XSPI_DCR2_WRAPSIZE(config->wrapsize));
+  xspi_putreg(priv, STM32_XSPI_DCR3_OFFSET,
+              XSPI_DCR3_MAXTRAN(config->maxtran) |
+              XSPI_DCR3_CSBOUND(config->csbound));
+  xspi_putreg(priv, STM32_XSPI_DCR4_OFFSET, config->refresh);
+
+  priv->sample_shift = config->sample_shift;
+  cr &= ~(XSPI_CR_FTHRES_MASK | XSPI_CR_FMODE_MASK);
+  cr |= XSPI_CR_FTHRES(config->fthres) | XSPI_CR_EN;
+  xspi_putreg(priv, STM32_XSPI_CR_OFFSET, cr);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: xspi_transfer
+ *
+ * Description:
+ *   Execute a single polled indirect-mode transfer.
+ *
+ ****************************************************************************/
+
+static int xspi_transfer(struct stm32_xspidev_s *priv,
+                         const struct stm32_xspi_cmd_s *cmd)
+{
+  uint8_t *buffer;
+  uint32_t ccr;
+  uint32_t tcr;
+  uint32_t fmode;
+  size_t remaining;
+  int ret;
+
+  if (cmd == NULL || (cmd->buflen > 0 && cmd->buffer == NULL) ||
+      (cmd->buflen > 0 && cmd->data_lines == 0) ||
+      (cmd->buflen == 0 && cmd->data_lines != 0))
+    {
+      return -EINVAL;
+    }
+
+  ret = xspi_ccr(cmd, &ccr);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = xspi_wait(priv, XSPI_SR_BUSY, 0);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  xspi_putreg(priv, STM32_XSPI_FCR_OFFSET, XSPI_FCR_ALL);
+  if (cmd->buflen > 0)
+    {
+      xspi_putreg(priv, STM32_XSPI_DLR_OFFSET, cmd->buflen - 1);
+    }
+
+  tcr = XSPI_TCR_DCYC(cmd->dummy_cycles);
+  if (priv->sample_shift && !cmd->dtr)
+    {
+      tcr |= XSPI_TCR_SSHIFT;
+    }
+
+  xspi_putreg(priv, STM32_XSPI_CCR_OFFSET, ccr);
+  xspi_putreg(priv, STM32_XSPI_TCR_OFFSET, tcr);
+  fmode = cmd->write ? XSPI_CR_FMODE_WRITE : XSPI_CR_FMODE_READ;
+  modifyreg32(priv->base + STM32_XSPI_CR_OFFSET, XSPI_CR_FMODE_MASK,
+              fmode);
+
+  xspi_putreg(priv, STM32_XSPI_IR_OFFSET, cmd->instruction);
+  if (cmd->address_lines != 0)
+    {
+      xspi_putreg(priv, STM32_XSPI_AR_OFFSET, cmd->address);
+    }
+
+  if (cmd->buflen == 0)
+    {
+      ret = xspi_wait(priv, XSPI_SR_BUSY, 0);
+      xspi_putreg(priv, STM32_XSPI_FCR_OFFSET, XSPI_FCR_CTCF);
+      return ret;
+    }
+
+  buffer = cmd->buffer;
+  remaining = cmd->buflen;
+  while (remaining > 0)
+    {
+      uint32_t flags = cmd->write ? XSPI_SR_FTF :
+                                    (XSPI_SR_FTF | XSPI_SR_TCF);
+
+      ret = xspi_wait_any(priv, flags);
+      if (ret < 0)
+        {
+          break;
+        }
+
+      if (cmd->write)
+        {
+          putreg8(*buffer, priv->base + STM32_XSPI_DR_OFFSET);
+        }
+      else
+        {
+          *buffer = getreg8(priv->base + STM32_XSPI_DR_OFFSET);
+        }
+
+      buffer++;
+      remaining--;
+    }
+
+  if (ret == OK)
+    {
+      ret = xspi_wait(priv, XSPI_SR_TCF, XSPI_SR_TCF);
+    }
+
+  xspi_putreg(priv, STM32_XSPI_FCR_OFFSET,
+              XSPI_FCR_CTEF | XSPI_FCR_CTCF);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: xspi_instruction_lines
+ *
+ * Description:
+ *   Get the instruction line count from command or memory transfer flags.
+ *
+ ****************************************************************************/
+
+static uint8_t xspi_instruction_lines(uint16_t flags, bool memory)
+{
+  if (memory ? QSPIMEM_ISIOCTAL(flags) : QSPICMD_ISIOCTAL(flags))
+    {
+      return 8;
+    }
+
+  if (memory ? QSPIMEM_ISIQUAD(flags) : QSPICMD_ISIQUAD(flags))
+    {
+      return 4;
+    }
+
+  if (memory ? QSPIMEM_ISIDUAL(flags) : QSPICMD_ISIDUAL(flags))
+    {
+      return 2;
+    }
+
+  return 1;
+}
+
+/****************************************************************************
+ * Name: xspi_command
+ *
+ * Description:
+ *   Perform one QSPI command transaction.
+ *
+ ****************************************************************************/
+
+static int xspi_command(struct qspi_dev_s *dev,
+                        struct qspi_cmdinfo_s *cmdinfo)
+{
+  struct stm32_xspidev_s *priv = (struct stm32_xspidev_s *)dev;
+  struct stm32_xspi_cmd_s cmd;
+
+  if (cmdinfo == NULL || cmdinfo->addrlen > 4 ||
+      (QSPICMD_ISDATA(cmdinfo->flags) && cmdinfo->buffer == NULL))
+    {
+      return -EINVAL;
+    }
+
+  cmd.instruction       = cmdinfo->cmd;
+  cmd.address           = cmdinfo->addr;
+  cmd.buffer            = cmdinfo->buffer;
+  cmd.buflen            = QSPICMD_ISDATA(cmdinfo->flags) ?
+                          cmdinfo->buflen : 0;
+  cmd.instruction_lines = xspi_instruction_lines(cmdinfo->flags, false);
+  cmd.address_lines     = QSPICMD_ISADDRESS(cmdinfo->flags) ?
+                          (QSPICMD_ISOCTALIO(cmdinfo->flags) ? 8 : 1) : 0;
+  cmd.data_lines        = QSPICMD_ISDATA(cmdinfo->flags) ?
+                          (QSPICMD_ISOCTALIO(cmdinfo->flags) ? 8 : 1) : 0;
+  cmd.instruction_bits  = QSPICMD_ISIOCTAL(cmdinfo->flags) ? 16 : 8;
+  cmd.address_bits      = cmdinfo->addrlen * 8;
+  cmd.dummy_cycles      = 0;
+  cmd.dtr               = QSPICMD_ISDTR(cmdinfo->flags);
+  cmd.write             = !QSPICMD_ISREAD(cmdinfo->flags);
+  return xspi_transfer(priv, &cmd);
+}
+
+/****************************************************************************
+ * Name: xspi_memory
+ *
+ * Description:
+ *   Perform one QSPI memory transfer.
+ *
+ ****************************************************************************/
+
+static int xspi_memory(struct qspi_dev_s *dev,
+                       struct qspi_meminfo_s *meminfo)
+{
+  struct stm32_xspidev_s *priv = (struct stm32_xspidev_s *)dev;
+  struct stm32_xspi_cmd_s cmd;
+
+  if (meminfo == NULL || meminfo->addrlen > 4 ||
+      meminfo->buflen == 0 || meminfo->buffer == NULL ||
+      meminfo->dummies > 31)
+    {
+      return -EINVAL;
+    }
+
+  cmd.instruction       = meminfo->cmd;
+  cmd.address           = meminfo->addr;
+  cmd.buffer            = meminfo->buffer;
+  cmd.buflen            = meminfo->buflen;
+  cmd.instruction_lines = xspi_instruction_lines(meminfo->flags, true);
+  cmd.address_lines     = meminfo->addrlen == 0 ? 0 :
+                          QSPIMEM_ISOCTALIO(meminfo->flags) ? 8 :
+                          QSPIMEM_ISQUADIO(meminfo->flags) ? 4 :
+                          QSPIMEM_ISDUALIO(meminfo->flags) ? 2 : 1;
+  cmd.data_lines        = QSPIMEM_ISOCTALIO(meminfo->flags) ? 8 :
+                          (QSPIMEM_ISQUADIO(meminfo->flags) ||
+                           QSPIMEM_ISQUADDATA(meminfo->flags)) ? 4 :
+                          QSPIMEM_ISDUALIO(meminfo->flags) ? 2 : 1;
+  cmd.instruction_bits  = QSPIMEM_ISIOCTAL(meminfo->flags) ? 16 : 8;
+  cmd.address_bits      = meminfo->addrlen * 8;
+  cmd.dummy_cycles      = meminfo->dummies;
+  cmd.dtr               = QSPIMEM_ISDTR(meminfo->flags);
+  cmd.write             = QSPIMEM_ISWRITE(meminfo->flags);
+  return xspi_transfer(priv, &cmd);
+}
+
+/****************************************************************************
+ * Name: xspi_alloc
+ *
+ * Description:
+ *   Allocate a buffer suitable for XSPI transfers.
+ *
+ ****************************************************************************/
+
+static void *xspi_alloc(struct qspi_dev_s *dev, size_t buflen)
+{
+  UNUSED(dev);
+  return kmm_malloc(buflen);
+}
+
+/****************************************************************************
+ * Name: xspi_free
+ *
+ * Description:
+ *   Free a buffer allocated by xspi_alloc.
+ *
+ ****************************************************************************/
+
+static void xspi_free(struct qspi_dev_s *dev, void *buffer)
+{
+  UNUSED(dev);
+  kmm_free(buffer);
+}
+
+/****************************************************************************
+ * Name: xspi_mmap_cmd
+ *
+ * Description:
+ *   Program the read or write command registers for memory-mapped mode.
+ *
+ ****************************************************************************/
+
+static int xspi_mmap_cmd(struct stm32_xspidev_s *priv,
+                         const struct qspi_meminfo_s *meminfo,
+                         bool write)
+{
+  struct stm32_xspi_cmd_s cmd;
+  uint32_t ccr_offset = write ? STM32_XSPI_WCCR_OFFSET :
+                                STM32_XSPI_CCR_OFFSET;
+  uint32_t tcr_offset = write ? STM32_XSPI_WTCR_OFFSET :
+                                STM32_XSPI_TCR_OFFSET;
+  uint32_t ir_offset  = write ? STM32_XSPI_WIR_OFFSET :
+                                STM32_XSPI_IR_OFFSET;
+  uint32_t ccr;
+  uint32_t tcr;
+  int ret;
+
+  if (meminfo == NULL || meminfo->addrlen == 0 || meminfo->addrlen > 4 ||
+      meminfo->dummies > 31)
+    {
+      return -EINVAL;
+    }
+
+  cmd.instruction       = meminfo->cmd;
+  cmd.address           = 0;
+  cmd.buffer            = NULL;
+  cmd.buflen            = 0;
+  cmd.instruction_lines = xspi_instruction_lines(meminfo->flags, true);
+  cmd.address_lines     = QSPIMEM_ISOCTALIO(meminfo->flags) ? 8 :
+                          QSPIMEM_ISQUADIO(meminfo->flags) ? 4 :
+                          QSPIMEM_ISDUALIO(meminfo->flags) ? 2 : 1;
+  cmd.data_lines        = QSPIMEM_ISOCTALIO(meminfo->flags) ? 8 :
+                          (QSPIMEM_ISQUADIO(meminfo->flags) ||
+                           QSPIMEM_ISQUADDATA(meminfo->flags)) ? 4 :
+                          QSPIMEM_ISDUALIO(meminfo->flags) ? 2 : 1;
+  cmd.instruction_bits  = QSPIMEM_ISIOCTAL(meminfo->flags) ? 16 : 8;
+  cmd.address_bits      = meminfo->addrlen * 8;
+  cmd.dummy_cycles      = meminfo->dummies;
+  cmd.dtr               = QSPIMEM_ISDTR(meminfo->flags);
+  cmd.write             = write;
+
+  ret = xspi_ccr(&cmd, &ccr);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  tcr = XSPI_TCR_DCYC(cmd.dummy_cycles);
+  if (priv->sample_shift && !cmd.dtr)
+    {
+      tcr |= XSPI_TCR_SSHIFT;
+    }
+
+  xspi_putreg(priv, ccr_offset, ccr);
+  xspi_putreg(priv, tcr_offset, tcr);
+  xspi_putreg(priv, ir_offset, cmd.instruction);
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_xspi_initialize
+ *
+ * Description:
+ *   Initialize an XSPI controller.
+ *
+ * Input Parameters:
+ *   intf   - XSPI controller number (1 or 2)
+ *   config - XSPI controller configuration
+ *
+ * Returned Value:
+ *   Valid QSPI device structure on success; NULL on failure.
+ *
+ ****************************************************************************/
+
+struct qspi_dev_s *
+stm32_xspi_initialize(int intf, const struct stm32_xspi_config_s *config)
+{
+  struct stm32_xspidev_s *priv = xspi_device(intf);
+  int ret;
+
+  if (priv == NULL || config == NULL)
+    {
+      return NULL;
+    }
+
+  if (!priv->initialized)
+    {
+      ret = xspi_hw_initialize(priv);
+      if (ret < 0)
+        {
+          return NULL;
+        }
+
+      priv->initialized = true;
+    }
+
+  if (xspi_configure(priv, config) < 0)
+    {
+      return NULL;
+    }
+
+  return &priv->qspi;
+}
+
+/****************************************************************************
+ * Name: stm32_xspi_enter_memorymapped
+ *
+ * Description:
+ *   Configure the XSPI controller for memory-mapped access.
+ *
+ * Input Parameters:
+ *   dev       - QSPI device
+ *   readinfo  - Memory transfer parameters used for reading
+ *   writeinfo - Memory transfer parameters used for writing; may be NULL
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int stm32_xspi_enter_memorymapped(
+  struct qspi_dev_s *dev,
+  const struct qspi_meminfo_s *readinfo,
+  const struct qspi_meminfo_s *writeinfo)
+{
+  struct stm32_xspidev_s *priv = (struct stm32_xspidev_s *)dev;
+  uint32_t cr;
+  int ret;
+
+  if (dev == NULL || dev->ops != &g_xspi_ops)
+    {
+      return -EINVAL;
+    }
+
+  ret = xspi_lock(dev, true);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (priv->memmap)
+    {
+      xspi_lock(dev, false);
+      return OK;
+    }
+
+  ret = xspi_wait(priv, XSPI_SR_BUSY, 0);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  cr = xspi_getreg(priv, STM32_XSPI_CR_OFFSET);
+  xspi_putreg(priv, STM32_XSPI_CR_OFFSET, cr & ~XSPI_CR_EN);
+
+  ret = xspi_mmap_cmd(priv, readinfo, false);
+  if (ret == OK && writeinfo != NULL)
+    {
+      ret = xspi_mmap_cmd(priv, writeinfo, true);
+    }
+
+  if (ret < 0)
+    {
+      xspi_putreg(priv, STM32_XSPI_CR_OFFSET, cr);
+      goto errout;
+    }
+
+  cr &= ~XSPI_CR_FMODE_MASK;
+  cr |= XSPI_CR_EN | XSPI_CR_FMODE_MEMORY;
+  xspi_putreg(priv, STM32_XSPI_CR_OFFSET, cr);
+  priv->memmap = true;
+  xspi_lock(dev, false);
+  return OK;
+
+errout:
+  xspi_lock(dev, false);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: stm32_xspi_exit_memorymapped
+ *
+ * Description:
+ *   Take the XSPI device out of memory-mapped mode.
+ *
+ * Input Parameters:
+ *   dev - QSPI device
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void stm32_xspi_exit_memorymapped(struct qspi_dev_s *dev)
+{
+  struct stm32_xspidev_s *priv = (struct stm32_xspidev_s *)dev;
+
+  if (dev == NULL || dev->ops != &g_xspi_ops)
+    {
+      return;
+    }
+
+  xspi_lock(dev, true);
+  modifyreg32(priv->base + STM32_XSPI_CR_OFFSET, 0, XSPI_CR_ABORT);
+  xspi_wait(priv, XSPI_SR_BUSY, 0);
+  modifyreg32(priv->base + STM32_XSPI_CR_OFFSET,
+              XSPI_CR_ABORT | XSPI_CR_FMODE_MASK,
+              XSPI_CR_FMODE_WRITE);
+  priv->memmap = false;
+  xspi_lock(dev, false);
+}
+
+#endif /* CONFIG_STM32_XSPI */
diff --git a/arch/arm/src/stm32h7/stm32_xspi.h 
b/arch/arm/src/stm32h7/stm32_xspi.h
new file mode 100644
index 00000000000..de30b098f24
--- /dev/null
+++ b/arch/arm/src/stm32h7/stm32_xspi.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+ * arch/arm/src/stm32h7/stm32_xspi.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_STM32H7_STM32_XSPI_H
+#define __ARCH_ARM_SRC_STM32H7_STM32_XSPI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <nuttx/spi/qspi.h>
+
+#ifdef CONFIG_STM32_XSPI
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+enum stm32_xspi_memtype_e
+{
+  STM32_XSPI_MEMTYPE_MICRON       = 0,
+  STM32_XSPI_MEMTYPE_MACRONIX     = 1,
+  STM32_XSPI_MEMTYPE_APMEM        = 2,
+  STM32_XSPI_MEMTYPE_MACRONIX_RAM = 3,
+  STM32_XSPI_MEMTYPE_HYPERBUS     = 4,
+  STM32_XSPI_MEMTYPE_APMEM_16BIT  = 6
+};
+
+enum stm32_xspi_iomport_e
+{
+  STM32_XSPI_IOM_PORT1 = 0,
+  STM32_XSPI_IOM_PORT2 = 1
+};
+
+enum stm32_xspi_cs_e
+{
+  STM32_XSPI_CS_DISABLED = 0,
+  STM32_XSPI_CS_NCS1,
+  STM32_XSPI_CS_NCS2
+};
+
+struct stm32_xspi_config_s
+{
+  enum stm32_xspi_memtype_e memtype;
+  enum stm32_xspi_iomport_e iomport;
+  enum stm32_xspi_cs_e cs_override;
+  uint8_t devsize;
+  uint8_t csht;
+  uint8_t prescaler;
+  uint8_t fthres;
+  uint8_t wrapsize;
+  uint8_t maxtran;
+  uint8_t csbound;
+  uint16_t req2ack;
+  uint32_t refresh;
+  bool clock_mode3;
+  bool free_running;
+  bool sample_shift;
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: stm32_xspi_initialize
+ *
+ * Description:
+ *   Initialize an XSPI controller.
+ *
+ * Input Parameters:
+ *   intf   - XSPI controller number (1 or 2)
+ *   config - XSPI controller configuration
+ *
+ * Returned Value:
+ *   Valid QSPI device structure on success; NULL on failure.
+ *
+ ****************************************************************************/
+
+struct qspi_dev_s *
+stm32_xspi_initialize(int intf, const struct stm32_xspi_config_s *config);
+
+/****************************************************************************
+ * Name: stm32_xspi_enter_memorymapped
+ *
+ * Description:
+ *   Configure the XSPI controller for memory-mapped access.
+ *
+ * Input Parameters:
+ *   dev       - QSPI device
+ *   readinfo  - Memory transfer parameters used for reading
+ *   writeinfo - Memory transfer parameters used for writing; may be NULL
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int stm32_xspi_enter_memorymapped(
+  struct qspi_dev_s *dev,
+  const struct qspi_meminfo_s *readinfo,
+  const struct qspi_meminfo_s *writeinfo);
+
+/****************************************************************************
+ * Name: stm32_xspi_exit_memorymapped
+ *
+ * Description:
+ *   Take the XSPI device out of memory-mapped mode.
+ *
+ * Input Parameters:
+ *   dev - QSPI device
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void stm32_xspi_exit_memorymapped(struct qspi_dev_s *dev);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_STM32_XSPI */
+#endif /* __ARCH_ARM_SRC_STM32H7_STM32_XSPI_H */

Reply via email to