From 8d878523af8160474aa6cd598807d860afa586d2 Mon Sep 17 00:00:00 2001 From: Jouni Ukkonen Date: Wed, 29 May 2024 14:38:22 +0300 Subject: [PATCH 1/2] imx9: Add flexspi support, ported from imxrt Signed-off-by: Jouni Ukkonen --- arch/arm64/src/imx9/Kconfig | 5 + arch/arm64/src/imx9/Make.defs | 4 + arch/arm64/src/imx9/hardware/imx9_flexspi.h | 598 +++++++++ arch/arm64/src/imx9/imx9_flexspi.c | 1258 +++++++++++++++++++ arch/arm64/src/imx9/imx9_flexspi.h | 573 +++++++++ 5 files changed, 2438 insertions(+) create mode 100644 arch/arm64/src/imx9/hardware/imx9_flexspi.h create mode 100644 arch/arm64/src/imx9/imx9_flexspi.c create mode 100644 arch/arm64/src/imx9/imx9_flexspi.h diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index 3f012563c9bbc..67ee9c7454e2b 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -246,6 +246,11 @@ endmenu # LPUART Configuration endmenu # LPUART +config IMX9_FLEXSPI + bool "ENABLE FLEXSPI interface" + default n + + config IMX9_FLEXIO1_PWM depends on PWM bool "Enable FLEXIO1 based PWM generation" diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs index 38466ba3704aa..f97bb2a676ad6 100644 --- a/arch/arm64/src/imx9/Make.defs +++ b/arch/arm64/src/imx9/Make.defs @@ -67,3 +67,7 @@ endif ifeq ($(CONFIG_IMX9_USDHC),y) CHIP_CSRCS += imx9_usdhc.c endif + +ifeq ($(CONFIG_IMX9_FLEXSPI), y) + CHIP_CSRCS += imx9_flexspi.c +endif diff --git a/arch/arm64/src/imx9/hardware/imx9_flexspi.h b/arch/arm64/src/imx9/hardware/imx9_flexspi.h new file mode 100644 index 0000000000000..929cdfb911d28 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_flexspi.h @@ -0,0 +1,598 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_flexspi.h + * + * 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_ARM64_SRC_IMX9_HARDWARE_IMX9_FLEXSPI_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_FLEXSPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/imx9_memorymap.h" + +/* FLEXSPI - Register Layout Typedef */ + +struct flexspi_type_s +{ + volatile uint32_t MCR0; /* Module Control Register 0, offset: 0x0 */ + volatile uint32_t MCR1; /* Module Control Register 1, offset: 0x4 */ + volatile uint32_t MCR2; /* Module Control Register 2, offset: 0x8 */ + volatile uint32_t AHBCR; /* AHB Bus Control Register, offset: 0xc */ + volatile uint32_t INTEN; /* Interrupt Enable Register, offset: 0x10 */ + volatile uint32_t INTR; /* Interrupt Register, offset: 0x14 */ + volatile uint32_t LUTKEY; /* LUT Key Register, offset: 0x18 */ + volatile uint32_t LUTCR; /* LUT Control Register, offset: 0x1c */ + volatile uint32_t AHBRXBUFCR0[8]; /* AHB RX Buffer 0 Control Register 0..AHB RX Buffer 7 Control Register 0, array offset: 0x20, array step: 0x4 */ + volatile uint8_t RESERVED_0[32]; + volatile uint32_t FLSHCR0[4]; /* Flash A1 Control Register 0..Flash B2 Control Register 0, array offset: 0x60, array step: 0x4 */ + volatile uint32_t FLSHCR1[4]; /* Flash A1 Control Register 1..Flash B2 Control Register 1, array offset: 0x70, array step: 0x4 */ + volatile uint32_t FLSHCR2[4]; /* Flash A1 Control Register 2..Flash B2 Control Register 2, array offset: 0x80, array step: 0x4 */ + uint8_t RESERVED_1[4]; + volatile uint32_t FLSHCR4; /* Flash Control Register 4, offset: 0x94 */ + uint8_t RESERVED_2[8]; + volatile uint32_t IPCR0; /* IP Control Register 0, offset: 0xa0 */ + volatile uint32_t IPCR1; /* IP Control Register 1, offset: 0xa4 */ + uint8_t RESERVED_3[8]; + volatile uint32_t IPCMD; /* IP Command Register, offset: 0xb0 */ + uint8_t RESERVED_4[4]; + volatile uint32_t IPRXFCR; /* IP RX FIFO Control Register, offset: 0xb8 */ + volatile uint32_t IPTXFCR; /* IP TX FIFO Control Register, offset: 0xbc */ + volatile uint32_t DLLCR[2]; /* DLL Control Register 0, array offset: 0xc0, array step: 0x4 */ + uint8_t RESERVED_5[24]; + volatile uint32_t STS0; /* Status Register 0, offset: 0xe0 */ + volatile uint32_t STS1; /* Status Register 1, offset: 0xe4 */ + volatile uint32_t STS2; /* Status Register 2, offset: 0xe8 */ + volatile uint32_t AHBSPNDSTS; /* AHB Suspend Status Register, offset: 0xec */ + volatile uint32_t IPRXFSTS; /* IP RX FIFO Status Register, offset: 0xf0 */ + volatile uint32_t IPTXFSTS; /* IP TX FIFO Status Register, offset: 0xf4 */ + uint8_t RESERVED_6[8]; + volatile uint32_t RFDR[32]; /* IP RX FIFO Data Register 0..IP RX FIFO Data Register 31, array offset: 0x100, array step: 0x4 */ + volatile uint32_t TFDR[32]; /* IP TX FIFO Data Register 0..IP TX FIFO Data Register 31, array offset: 0x180, array step: 0x4 */ + volatile uint32_t LUT[128]; /* LUT 0..LUT 127, array offset: 0x200, array step: 0x4 */ +}; + +#define IMX9_FLEXSPI_AHBBUFREGIONSTART0_OFFSET 0x440 +#define IMX9_FLEXSPI_AHBBUFREGIONEND0_OFFSET 0x444 +#define IMX9_FLEXSPI_AHBBUFREGIONSTART1_OFFSET 0x448 +#define IMX9_FLEXSPI_AHBBUFREGIONEND1_OFFSET 0x44C +#define IMX9_FLEXSPI_AHBBUFREGIONSTART2_OFFSET 0x450 +#define IMX9_FLEXSPI_AHBBUFREGIONEND2_OFFSET 0x454 +#define IMX9_FLEXSPI_AHBBUFREGIONSTART3_OFFSET 0x458 +#define IMX9_FLEXSPI_AHBBUFREGIONEND3_OFFSET 0x45C + +#define IMX9_FLEXSPI1_AHBBUFREGIONSTART0 (IMX9_FLEXSPI_BASE + IMX9_FLEXSPI_AHBBUFREGIONSTART0_OFFSET) +#define IMX9_FLEXSPI1_AHBBUFREGIONEND0 (IMX9_FLEXSPI_BASE + IMX9_FLEXSPI_AHBBUFREGIONEND0_OFFSET) +#define IMX9_FLEXSPI1_AHBBUFREGIONSTART1 (IMX9_FLEXSPI_BASE + IMX9_FLEXSPI_AHBBUFREGIONSTART1_OFFSET) +#define IMX9_FLEXSPI1_AHBBUFREGIONEND1 (IMX9_FLEXSPI_BASE + IMX9_FLEXSPI_AHBBUFREGIONEND1_OFFSET) +#define IMX9_FLEXSPI1_AHBBUFREGIONSTART2 (IMX9_FLEXSPI_BASE + IMX9_FLEXSPI_AHBBUFREGIONSTART2_OFFSET) +#define IMX9_FLEXSPI1_AHBBUFREGIONEND2 (IMX9_FLEXSPI_BASE + IMX9_FLEXSPI_AHBBUFREGIONEND2_OFFSET) +#define IMX9_FLEXSPI1_AHBBUFREGIONSTART3 (IMX9_FLEXSPI_BASE + IMX9_FLEXSPI_AHBBUFREGIONSTART3_OFFSET) +#define IMX9_FLEXSPI1_AHBBUFREGIONEND3 (IMX9_FLEXSPI_BASE + IMX9_FLEXSPI_AHBBUFREGIONEND3_OFFSET) + +/* MCR0 - Module Control Register 0 */ + +#define FLEXSPI_MCR0_SWRESET_MASK (0x1u) +#define FLEXSPI_MCR0_SWRESET_SHIFT (0u) + +/* SWRESET - Software Reset */ + +#define FLEXSPI_MCR0_SWRESET(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_SWRESET_SHIFT)) & FLEXSPI_MCR0_SWRESET_MASK) +#define FLEXSPI_MCR0_MDIS_MASK (0x2u) +#define FLEXSPI_MCR0_MDIS_SHIFT (1u) + +/* MDIS - Module Disable */ + +#define FLEXSPI_MCR0_MDIS(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_MDIS_SHIFT)) & FLEXSPI_MCR0_MDIS_MASK) +#define FLEXSPI_MCR0_RXCLKSRC_MASK (0x30u) +#define FLEXSPI_MCR0_RXCLKSRC_SHIFT (4u) + +#define FLEXSPI_MCR0_RXCLKSRC(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_RXCLKSRC_SHIFT)) & FLEXSPI_MCR0_RXCLKSRC_MASK) +#define FLEXSPI_MCR0_ARDFEN_MASK (0x40u) +#define FLEXSPI_MCR0_ARDFEN_SHIFT (6u) + +#define FLEXSPI_MCR0_ARDFEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_ARDFEN_SHIFT)) & FLEXSPI_MCR0_ARDFEN_MASK) +#define FLEXSPI_MCR0_ATDFEN_MASK (0x80u) +#define FLEXSPI_MCR0_ATDFEN_SHIFT (7u) + +#define FLEXSPI_MCR0_ATDFEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_ATDFEN_SHIFT)) & FLEXSPI_MCR0_ATDFEN_MASK) +#define FLEXSPI_MCR0_HSEN_MASK (0x800u) +#define FLEXSPI_MCR0_HSEN_SHIFT (11u) + +#define FLEXSPI_MCR0_HSEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_HSEN_SHIFT)) & FLEXSPI_MCR0_HSEN_MASK) +#define FLEXSPI_MCR0_DOZEEN_MASK (0x1000u) +#define FLEXSPI_MCR0_DOZEEN_SHIFT (12u) + +#define FLEXSPI_MCR0_DOZEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_DOZEEN_SHIFT)) & FLEXSPI_MCR0_DOZEEN_MASK) +#define FLEXSPI_MCR0_COMBINATIONEN_MASK (0x2000u) +#define FLEXSPI_MCR0_COMBINATIONEN_SHIFT (13u) + +#define FLEXSPI_MCR0_COMBINATIONEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_COMBINATIONEN_SHIFT)) & FLEXSPI_MCR0_COMBINATIONEN_MASK) +#define FLEXSPI_MCR0_SCKFREERUNEN_MASK (0x4000u) +#define FLEXSPI_MCR0_SCKFREERUNEN_SHIFT (14u) + +#define FLEXSPI_MCR0_SCKFREERUNEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_SCKFREERUNEN_SHIFT)) & FLEXSPI_MCR0_SCKFREERUNEN_MASK) +#define FLEXSPI_MCR0_IPGRANTWAIT_MASK (0xff0000u) +#define FLEXSPI_MCR0_IPGRANTWAIT_SHIFT (16u) + +#define FLEXSPI_MCR0_IPGRANTWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_IPGRANTWAIT_SHIFT)) & FLEXSPI_MCR0_IPGRANTWAIT_MASK) +#define FLEXSPI_MCR0_AHBGRANTWAIT_MASK (0xff000000u) +#define FLEXSPI_MCR0_AHBGRANTWAIT_SHIFT (24u) + +#define FLEXSPI_MCR0_AHBGRANTWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR0_AHBGRANTWAIT_SHIFT)) & FLEXSPI_MCR0_AHBGRANTWAIT_MASK) + +#define FLEXSPI_MCR1_AHBBUSWAIT_MASK (0xffffu) +#define FLEXSPI_MCR1_AHBBUSWAIT_SHIFT (0u) +#define FLEXSPI_MCR1_AHBBUSWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR1_AHBBUSWAIT_SHIFT)) & FLEXSPI_MCR1_AHBBUSWAIT_MASK) +#define FLEXSPI_MCR1_SEQWAIT_MASK (0xffff0000u) +#define FLEXSPI_MCR1_SEQWAIT_SHIFT (16u) +#define FLEXSPI_MCR1_SEQWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR1_SEQWAIT_SHIFT)) & FLEXSPI_MCR1_SEQWAIT_MASK) + +#define FLEXSPI_MCR2_CLRAHBBUFOPT_MASK (0x800u) +#define FLEXSPI_MCR2_CLRAHBBUFOPT_SHIFT (11u) + +#define FLEXSPI_MCR2_CLRAHBBUFOPT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR2_CLRAHBBUFOPT_SHIFT)) & FLEXSPI_MCR2_CLRAHBBUFOPT_MASK) +#define FLEXSPI_MCR2_CLRLEARNPHASE_MASK (0x4000u) +#define FLEXSPI_MCR2_CLRLEARNPHASE_SHIFT (14u) + +#define FLEXSPI_MCR2_CLRLEARNPHASE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR2_CLRLEARNPHASE_SHIFT)) & FLEXSPI_MCR2_CLRLEARNPHASE_MASK) +#define FLEXSPI_MCR2_SAMEDEVICEEN_MASK (0x8000u) +#define FLEXSPI_MCR2_SAMEDEVICEEN_SHIFT (15u) + +#define FLEXSPI_MCR2_SAMEDEVICEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR2_SAMEDEVICEEN_SHIFT)) & FLEXSPI_MCR2_SAMEDEVICEEN_MASK) +#define FLEXSPI_MCR2_SCKBDIFFOPT_MASK (0x80000u) +#define FLEXSPI_MCR2_SCKBDIFFOPT_SHIFT (19u) + +#define FLEXSPI_MCR2_SCKBDIFFOPT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR2_SCKBDIFFOPT_SHIFT)) & FLEXSPI_MCR2_SCKBDIFFOPT_MASK) +#define FLEXSPI_MCR2_RESUMEWAIT_MASK (0xff000000u) +#define FLEXSPI_MCR2_RESUMEWAIT_SHIFT (24u) + +#define FLEXSPI_MCR2_RESUMEWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_MCR2_RESUMEWAIT_SHIFT)) & FLEXSPI_MCR2_RESUMEWAIT_MASK) + +#define FLEXSPI_AHBCR_APAREN_MASK (0x1u) +#define FLEXSPI_AHBCR_APAREN_SHIFT (0u) + +#define FLEXSPI_AHBCR_APAREN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBCR_APAREN_SHIFT)) & FLEXSPI_AHBCR_APAREN_MASK) +#define FLEXSPI_AHBCR_CACHABLEEN_MASK (0x8u) +#define FLEXSPI_AHBCR_CACHABLEEN_SHIFT (3u) + +#define FLEXSPI_AHBCR_CACHABLEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBCR_CACHABLEEN_SHIFT)) & FLEXSPI_AHBCR_CACHABLEEN_MASK) +#define FLEXSPI_AHBCR_BUFFERABLEEN_MASK (0x10u) +#define FLEXSPI_AHBCR_BUFFERABLEEN_SHIFT (4u) + +#define FLEXSPI_AHBCR_BUFFERABLEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBCR_BUFFERABLEEN_SHIFT)) & FLEXSPI_AHBCR_BUFFERABLEEN_MASK) +#define FLEXSPI_AHBCR_PREFETCHEN_MASK (0x20u) +#define FLEXSPI_AHBCR_PREFETCHEN_SHIFT (5u) + +#define FLEXSPI_AHBCR_PREFETCHEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBCR_PREFETCHEN_SHIFT)) & FLEXSPI_AHBCR_PREFETCHEN_MASK) +#define FLEXSPI_AHBCR_READADDROPT_MASK (0x40u) +#define FLEXSPI_AHBCR_READADDROPT_SHIFT (6u) + +#define FLEXSPI_AHBCR_READADDROPT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBCR_READADDROPT_SHIFT)) & FLEXSPI_AHBCR_READADDROPT_MASK) + +#define FLEXSPI_INTEN_IPCMDDONEEN_MASK (0x1u) +#define FLEXSPI_INTEN_IPCMDDONEEN_SHIFT (0u) + +#define FLEXSPI_INTEN_IPCMDDONEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_IPCMDDONEEN_SHIFT)) & FLEXSPI_INTEN_IPCMDDONEEN_MASK) +#define FLEXSPI_INTEN_IPCMDGEEN_MASK (0x2u) +#define FLEXSPI_INTEN_IPCMDGEEN_SHIFT (1u) + +#define FLEXSPI_INTEN_IPCMDGEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_IPCMDGEEN_SHIFT)) & FLEXSPI_INTEN_IPCMDGEEN_MASK) +#define FLEXSPI_INTEN_AHBCMDGEEN_MASK (0x4u) +#define FLEXSPI_INTEN_AHBCMDGEEN_SHIFT (2u) + +#define FLEXSPI_INTEN_AHBCMDGEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_AHBCMDGEEN_SHIFT)) & FLEXSPI_INTEN_AHBCMDGEEN_MASK) +#define FLEXSPI_INTEN_IPCMDERREN_MASK (0x8u) +#define FLEXSPI_INTEN_IPCMDERREN_SHIFT (3u) + +#define FLEXSPI_INTEN_IPCMDERREN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_IPCMDERREN_SHIFT)) & FLEXSPI_INTEN_IPCMDERREN_MASK) +#define FLEXSPI_INTEN_AHBCMDERREN_MASK (0x10u) +#define FLEXSPI_INTEN_AHBCMDERREN_SHIFT (4u) + +#define FLEXSPI_INTEN_AHBCMDERREN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_AHBCMDERREN_SHIFT)) & FLEXSPI_INTEN_AHBCMDERREN_MASK) +#define FLEXSPI_INTEN_IPRXWAEN_MASK (0x20u) +#define FLEXSPI_INTEN_IPRXWAEN_SHIFT (5u) + +#define FLEXSPI_INTEN_IPRXWAEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_IPRXWAEN_SHIFT)) & FLEXSPI_INTEN_IPRXWAEN_MASK) +#define FLEXSPI_INTEN_IPTXWEEN_MASK (0x40u) +#define FLEXSPI_INTEN_IPTXWEEN_SHIFT (6u) + +#define FLEXSPI_INTEN_IPTXWEEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_IPTXWEEN_SHIFT)) & FLEXSPI_INTEN_IPTXWEEN_MASK) +#define FLEXSPI_INTEN_SCKSTOPBYRDEN_MASK (0x100u) +#define FLEXSPI_INTEN_SCKSTOPBYRDEN_SHIFT (8u) + +#define FLEXSPI_INTEN_SCKSTOPBYRDEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_SCKSTOPBYRDEN_SHIFT)) & FLEXSPI_INTEN_SCKSTOPBYRDEN_MASK) +#define FLEXSPI_INTEN_SCKSTOPBYWREN_MASK (0x200u) +#define FLEXSPI_INTEN_SCKSTOPBYWREN_SHIFT (9u) +#define FLEXSPI_INTEN_SCKSTOPBYWREN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_SCKSTOPBYWREN_SHIFT)) & FLEXSPI_INTEN_SCKSTOPBYWREN_MASK) + +#define FLEXSPI_INTEN_AHBBUSERROREN_MASK (0x400u) +#define FLEXSPI_INTEN_AHBBUSERROREN_SHIFT (10u) +#define FLEXSPI_INTEN_AHBBUSERROREN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_AHBBUSERROREN_SHIFT)) & FLEXSPI_INTEN_AHBBUSERROREN_MASK) + +#define FLEXSPI_INTEN_SEQTIMEOUTEN_MASK (0x800u) +#define FLEXSPI_INTEN_SEQTIMEOUTEN_SHIFT (11u) +#define FLEXSPI_INTEN_SEQTIMEOUTEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_SEQTIMEOUTEN_SHIFT)) & FLEXSPI_INTEN_SEQTIMEOUTEN_MASK) + +#define FLEXSPI_INTEN_KEYDONE_MASK (0x1000u) +#define FLEXSPI_INTEN_KEYDONE_SHIFT (12u) +#define FLEXSPI_INTEN_KEYDONE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_KEYDONE_SHIFT)) & FLEXSPI_INTEN_KEYDONE_MASK) + +#define FLEXSPI_INTEN_KEYERROR_MASK (0x2000u) +#define FLEXSPI_INTEN_KEYERROR_SHIFT (13u) +#define FLEXSPI_INTEN_KEYERROR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTEN_KEYERROR_SHIFT)) & FLEXSPI_INTEN_KEYERROR_MASK) + +#define FLEXSPI_INTR_IPCMDDONE_MASK (0x1u) +#define FLEXSPI_INTR_IPCMDDONE_SHIFT (0u) + +#define FLEXSPI_INTR_IPCMDDONE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_IPCMDDONE_SHIFT)) & FLEXSPI_INTR_IPCMDDONE_MASK) +#define FLEXSPI_INTR_IPCMDGE_MASK (0x2u) +#define FLEXSPI_INTR_IPCMDGE_SHIFT (1u) + +#define FLEXSPI_INTR_IPCMDGE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_IPCMDGE_SHIFT)) & FLEXSPI_INTR_IPCMDGE_MASK) +#define FLEXSPI_INTR_AHBCMDGE_MASK (0x4u) +#define FLEXSPI_INTR_AHBCMDGE_SHIFT (2u) + +#define FLEXSPI_INTR_AHBCMDGE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_AHBCMDGE_SHIFT)) & FLEXSPI_INTR_AHBCMDGE_MASK) +#define FLEXSPI_INTR_IPCMDERR_MASK (0x8u) +#define FLEXSPI_INTR_IPCMDERR_SHIFT (3u) + +#define FLEXSPI_INTR_IPCMDERR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_IPCMDERR_SHIFT)) & FLEXSPI_INTR_IPCMDERR_MASK) +#define FLEXSPI_INTR_AHBCMDERR_MASK (0x10u) +#define FLEXSPI_INTR_AHBCMDERR_SHIFT (4u) + +#define FLEXSPI_INTR_AHBCMDERR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_AHBCMDERR_SHIFT)) & FLEXSPI_INTR_AHBCMDERR_MASK) +#define FLEXSPI_INTR_IPRXWA_MASK (0x20u) +#define FLEXSPI_INTR_IPRXWA_SHIFT (5u) + +#define FLEXSPI_INTR_IPRXWA(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_IPRXWA_SHIFT)) & FLEXSPI_INTR_IPRXWA_MASK) +#define FLEXSPI_INTR_IPTXWE_MASK (0x40u) +#define FLEXSPI_INTR_IPTXWE_SHIFT (6u) + +#define FLEXSPI_INTR_IPTXWE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_IPTXWE_SHIFT)) & FLEXSPI_INTR_IPTXWE_MASK) +#define FLEXSPI_INTR_SCKSTOPBYRD_MASK (0x100u) +#define FLEXSPI_INTR_SCKSTOPBYRD_SHIFT (8u) + +#define FLEXSPI_INTR_SCKSTOPBYRD(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_SCKSTOPBYRD_SHIFT)) & FLEXSPI_INTR_SCKSTOPBYRD_MASK) +#define FLEXSPI_INTR_SCKSTOPBYWR_MASK (0x200u) +#define FLEXSPI_INTR_SCKSTOPBYWR_SHIFT (9u) + +#define FLEXSPI_INTR_SCKSTOPBYWR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_SCKSTOPBYWR_SHIFT)) & FLEXSPI_INTR_SCKSTOPBYWR_MASK) +#define FLEXSPI_INTR_AHBBUSTIMEOUT_MASK (0x400u) +#define FLEXSPI_INTR_AHBBUSTIMEOUT_SHIFT (10u) + +#define FLEXSPI_INTR_AHBBUSTIMEOUT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_AHBBUSTIMEOUT_SHIFT)) & FLEXSPI_INTR_AHBBUSTIMEOUT_MASK) +#define FLEXSPI_INTR_SEQTIMEOUT_MASK (0x800u) +#define FLEXSPI_INTR_SEQTIMEOUT_SHIFT (11u) + +#define FLEXSPI_INTR_SEQTIMEOUT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_SEQTIMEOUT_SHIFT)) & FLEXSPI_INTR_SEQTIMEOUT_MASK) + +#define FLEXSPI_INTR_KEYDONE_MASK (0x1000u) +#define FLEXSPI_INTR_KEYDONE_SHIFT (12u) +#define FLEXSPI_INTR_KEYDONE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_KEYDONE_SHIFT)) & FLEXSPI_INTR_KEYDONE_MASK) + +#define FLEXSPI_INTR_KEYERROR_MASK (0x2000u) +#define FLEXSPI_INTR_KEYERROR_SHIFT (13u) +#define FLEXSPI_INTR_KEYERROR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_INTR_KEYERROR_SHIFT)) & FLEXSPI_INTR_KEYERROR_MASK) + +#define FLEXSPI_LUTKEY_KEY_MASK (0xffffffffu) +#define FLEXSPI_LUTKEY_KEY_SHIFT (0u) + +#define FLEXSPI_LUTKEY_KEY(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUTKEY_KEY_SHIFT)) & FLEXSPI_LUTKEY_KEY_MASK) + +#define FLEXSPI_LUTCR_LOCK_MASK (0x1u) +#define FLEXSPI_LUTCR_LOCK_SHIFT (0u) + +#define FLEXSPI_LUTCR_LOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUTCR_LOCK_SHIFT)) & FLEXSPI_LUTCR_LOCK_MASK) +#define FLEXSPI_LUTCR_UNLOCK_MASK (0x2u) +#define FLEXSPI_LUTCR_UNLOCK_SHIFT (1u) + +#define FLEXSPI_LUTCR_UNLOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUTCR_UNLOCK_SHIFT)) & FLEXSPI_LUTCR_UNLOCK_MASK) + +#define FLEXSPI_AHBRXBUFCR0_BUFSZ_MASK (0x1ffu) + +#define FLEXSPI_AHBRXBUFCR0_BUFSZ_SHIFT (0u) + +#define FLEXSPI_AHBRXBUFCR0_BUFSZ(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBRXBUFCR0_BUFSZ_SHIFT)) & FLEXSPI_AHBRXBUFCR0_BUFSZ_MASK) +#define FLEXSPI_AHBRXBUFCR0_MSTRID_MASK (0xf0000u) +#define FLEXSPI_AHBRXBUFCR0_MSTRID_SHIFT (16u) + +#define FLEXSPI_AHBRXBUFCR0_MSTRID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBRXBUFCR0_MSTRID_SHIFT)) & FLEXSPI_AHBRXBUFCR0_MSTRID_MASK) +#define FLEXSPI_AHBRXBUFCR0_PRIORITY_MASK (0x7000000u) +#define FLEXSPI_AHBRXBUFCR0_PRIORITY_SHIFT (24u) + +#define FLEXSPI_AHBRXBUFCR0_PRIORITY(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBRXBUFCR0_PRIORITY_SHIFT)) & FLEXSPI_AHBRXBUFCR0_PRIORITY_MASK) + +#define FLEXSPI_AHBRXBUFCR0_REGIONEN_MASK (0x40000000u) +#define FLEXSPI_AHBRXBUFCR0_REGIONEN_SHIFT (30u) + +#define FLEXSPI_AHBRXBUFCR0_REGIONEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBRXBUFCR0_REGIONEN_SHIFT)) & FLEXSPI_AHBRXBUFCR0_REGIONEN_MASK) + +#define FLEXSPI_AHBRXBUFCR0_PREFETCHEN_MASK (0x80000000u) +#define FLEXSPI_AHBRXBUFCR0_PREFETCHEN_SHIFT (31u) + +#define FLEXSPI_AHBRXBUFCR0_PREFETCHEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBRXBUFCR0_PREFETCHEN_SHIFT)) & FLEXSPI_AHBRXBUFCR0_PREFETCHEN_MASK) + +#define FLEXSPI_AHBRXBUFCR0_COUNT (4u) + +#define FLEXSPI_FLSHCR0_FLSHSZ_MASK (0x7fffffu) +#define FLEXSPI_FLSHCR0_FLSHSZ_SHIFT (0u) + +#define FLEXSPI_FLSHCR0_FLSHSZ(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR0_FLSHSZ_SHIFT)) & FLEXSPI_FLSHCR0_FLSHSZ_MASK) + +#define FLEXSPI_FLSHCR0_COUNT (4u) + +#define FLEXSPI_FLSHCR1_TCSS_MASK (0x1fu) +#define FLEXSPI_FLSHCR1_TCSS_SHIFT (0u) + +#define FLEXSPI_FLSHCR1_TCSS(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_TCSS_SHIFT)) & FLEXSPI_FLSHCR1_TCSS_MASK) +#define FLEXSPI_FLSHCR1_TCSH_MASK (0x3e0u) +#define FLEXSPI_FLSHCR1_TCSH_SHIFT (5u) + +#define FLEXSPI_FLSHCR1_TCSH(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_TCSH_SHIFT)) & FLEXSPI_FLSHCR1_TCSH_MASK) +#define FLEXSPI_FLSHCR1_WA_MASK (0x400u) +#define FLEXSPI_FLSHCR1_WA_SHIFT (10u) + +#define FLEXSPI_FLSHCR1_WA(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_WA_SHIFT)) & FLEXSPI_FLSHCR1_WA_MASK) +#define FLEXSPI_FLSHCR1_CAS_MASK (0x7800u) +#define FLEXSPI_FLSHCR1_CAS_SHIFT (11u) + +#define FLEXSPI_FLSHCR1_CAS(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_CAS_SHIFT)) & FLEXSPI_FLSHCR1_CAS_MASK) +#define FLEXSPI_FLSHCR1_CSINTERVALUNIT_MASK (0x8000u) +#define FLEXSPI_FLSHCR1_CSINTERVALUNIT_SHIFT (15u) + +#define FLEXSPI_FLSHCR1_CSINTERVALUNIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_CSINTERVALUNIT_SHIFT)) & FLEXSPI_FLSHCR1_CSINTERVALUNIT_MASK) +#define FLEXSPI_FLSHCR1_CSINTERVAL_MASK (0xffff0000u) +#define FLEXSPI_FLSHCR1_CSINTERVAL_SHIFT (16u) + +#define FLEXSPI_FLSHCR1_CSINTERVAL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR1_CSINTERVAL_SHIFT)) & FLEXSPI_FLSHCR1_CSINTERVAL_MASK) + +#define FLEXSPI_FLSHCR1_COUNT (4u) + +#define FLEXSPI_FLSHCR2_ARDSEQID_MASK (0xfu) +#define FLEXSPI_FLSHCR2_ARDSEQID_SHIFT (0u) + +#define FLEXSPI_FLSHCR2_ARDSEQID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_ARDSEQID_SHIFT)) & FLEXSPI_FLSHCR2_ARDSEQID_MASK) +#define FLEXSPI_FLSHCR2_ARDSEQNUM_MASK (0xe0u) +#define FLEXSPI_FLSHCR2_ARDSEQNUM_SHIFT (5u) + +#define FLEXSPI_FLSHCR2_ARDSEQNUM(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_ARDSEQNUM_SHIFT)) & FLEXSPI_FLSHCR2_ARDSEQNUM_MASK) +#define FLEXSPI_FLSHCR2_AWRSEQID_MASK (0xf00u) +#define FLEXSPI_FLSHCR2_AWRSEQID_SHIFT (8u) + +#define FLEXSPI_FLSHCR2_AWRSEQID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_AWRSEQID_SHIFT)) & FLEXSPI_FLSHCR2_AWRSEQID_MASK) +#define FLEXSPI_FLSHCR2_AWRSEQNUM_MASK (0xe000u) +#define FLEXSPI_FLSHCR2_AWRSEQNUM_SHIFT (13u) + +#define FLEXSPI_FLSHCR2_AWRSEQNUM(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_AWRSEQNUM_SHIFT)) & FLEXSPI_FLSHCR2_AWRSEQNUM_MASK) +#define FLEXSPI_FLSHCR2_AWRWAIT_MASK (0xfff0000u) +#define FLEXSPI_FLSHCR2_AWRWAIT_SHIFT (16u) +#define FLEXSPI_FLSHCR2_AWRWAIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_AWRWAIT_SHIFT)) & FLEXSPI_FLSHCR2_AWRWAIT_MASK) +#define FLEXSPI_FLSHCR2_AWRWAITUNIT_MASK (0x70000000u) +#define FLEXSPI_FLSHCR2_AWRWAITUNIT_SHIFT (28u) + +#define FLEXSPI_FLSHCR2_AWRWAITUNIT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_AWRWAITUNIT_SHIFT)) & FLEXSPI_FLSHCR2_AWRWAITUNIT_MASK) +#define FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK (0x80000000u) +#define FLEXSPI_FLSHCR2_CLRINSTRPTR_SHIFT (31u) + +#define FLEXSPI_FLSHCR2_CLRINSTRPTR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR2_CLRINSTRPTR_SHIFT)) & FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK) + +#define FLEXSPI_FLSHCR2_COUNT (4u) + +#define FLEXSPI_FLSHCR4_WMOPT1_MASK (0x1u) +#define FLEXSPI_FLSHCR4_WMOPT1_SHIFT (0u) + +#define FLEXSPI_FLSHCR4_WMOPT1(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR4_WMOPT1_SHIFT)) & FLEXSPI_FLSHCR4_WMOPT1_MASK) +#define FLEXSPI_FLSHCR4_WMENA_MASK (0x4u) +#define FLEXSPI_FLSHCR4_WMENA_SHIFT (2u) + +#define FLEXSPI_FLSHCR4_WMENA(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR4_WMENA_SHIFT)) & FLEXSPI_FLSHCR4_WMENA_MASK) +#define FLEXSPI_FLSHCR4_WMENB_MASK (0x8u) +#define FLEXSPI_FLSHCR4_WMENB_SHIFT (3u) + +#define FLEXSPI_FLSHCR4_WMENB(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_FLSHCR4_WMENB_SHIFT)) & FLEXSPI_FLSHCR4_WMENB_MASK) + +#define FLEXSPI_IPCR0_SFAR_MASK (0xffffffffu) +#define FLEXSPI_IPCR0_SFAR_SHIFT (0u) + +#define FLEXSPI_IPCR0_SFAR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCR0_SFAR_SHIFT)) & FLEXSPI_IPCR0_SFAR_MASK) + +#define FLEXSPI_IPCR1_IDATSZ_MASK (0xffffu) +#define FLEXSPI_IPCR1_IDATSZ_SHIFT (0u) + +#define FLEXSPI_IPCR1_IDATSZ(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCR1_IDATSZ_SHIFT)) & FLEXSPI_IPCR1_IDATSZ_MASK) +#define FLEXSPI_IPCR1_ISEQID_MASK (0xf0000u) +#define FLEXSPI_IPCR1_ISEQID_SHIFT (16u) + +#define FLEXSPI_IPCR1_ISEQID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCR1_ISEQID_SHIFT)) & FLEXSPI_IPCR1_ISEQID_MASK) +#define FLEXSPI_IPCR1_ISEQNUM_MASK (0x7000000u) +#define FLEXSPI_IPCR1_ISEQNUM_SHIFT (24u) + +#define FLEXSPI_IPCR1_ISEQNUM(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCR1_ISEQNUM_SHIFT)) & FLEXSPI_IPCR1_ISEQNUM_MASK) +#define FLEXSPI_IPCR1_IPAREN_MASK (0x80000000u) +#define FLEXSPI_IPCR1_IPAREN_SHIFT (31u) + +#define FLEXSPI_IPCR1_IPAREN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCR1_IPAREN_SHIFT)) & FLEXSPI_IPCR1_IPAREN_MASK) + +#define FLEXSPI_IPCMD_TRG_MASK (0x1u) +#define FLEXSPI_IPCMD_TRG_SHIFT (0u) + +#define FLEXSPI_IPCMD_TRG(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPCMD_TRG_SHIFT)) & FLEXSPI_IPCMD_TRG_MASK) + +#define FLEXSPI_IPRXFCR_CLRIPRXF_MASK (0x1u) +#define FLEXSPI_IPRXFCR_CLRIPRXF_SHIFT (0u) + +#define FLEXSPI_IPRXFCR_CLRIPRXF(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPRXFCR_CLRIPRXF_SHIFT)) & FLEXSPI_IPRXFCR_CLRIPRXF_MASK) +#define FLEXSPI_IPRXFCR_RXDMAEN_MASK (0x2u) +#define FLEXSPI_IPRXFCR_RXDMAEN_SHIFT (1u) + +#define FLEXSPI_IPRXFCR_RXDMAEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPRXFCR_RXDMAEN_SHIFT)) & FLEXSPI_IPRXFCR_RXDMAEN_MASK) +#define FLEXSPI_IPRXFCR_RXWMRK_MASK (0x3cu) +#define FLEXSPI_IPRXFCR_RXWMRK_SHIFT (2u) + +#define FLEXSPI_IPRXFCR_RXWMRK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPRXFCR_RXWMRK_SHIFT)) & FLEXSPI_IPRXFCR_RXWMRK_MASK) + +#define FLEXSPI_IPTXFCR_CLRIPTXF_MASK (0x1u) +#define FLEXSPI_IPTXFCR_CLRIPTXF_SHIFT (0u) + +#define FLEXSPI_IPTXFCR_CLRIPTXF(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPTXFCR_CLRIPTXF_SHIFT)) & FLEXSPI_IPTXFCR_CLRIPTXF_MASK) +#define FLEXSPI_IPTXFCR_TXDMAEN_MASK (0x2u) +#define FLEXSPI_IPTXFCR_TXDMAEN_SHIFT (1u) + +#define FLEXSPI_IPTXFCR_TXDMAEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPTXFCR_TXDMAEN_SHIFT)) & FLEXSPI_IPTXFCR_TXDMAEN_MASK) +#define FLEXSPI_IPTXFCR_TXWMRK_MASK (0x3cu) +#define FLEXSPI_IPTXFCR_TXWMRK_SHIFT (2u) + +#define FLEXSPI_IPTXFCR_TXWMRK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPTXFCR_TXWMRK_SHIFT)) & FLEXSPI_IPTXFCR_TXWMRK_MASK) + +#define FLEXSPI_DLLCR_DLLEN_MASK (0x1u) +#define FLEXSPI_DLLCR_DLLEN_SHIFT (0u) + +#define FLEXSPI_DLLCR_DLLEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_DLLCR_DLLEN_SHIFT)) & FLEXSPI_DLLCR_DLLEN_MASK) +#define FLEXSPI_DLLCR_DLLRESET_MASK (0x2u) +#define FLEXSPI_DLLCR_DLLRESET_SHIFT (1u) + +#define FLEXSPI_DLLCR_DLLRESET(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_DLLCR_DLLRESET_SHIFT)) & FLEXSPI_DLLCR_DLLRESET_MASK) +#define FLEXSPI_DLLCR_SLVDLYTARGET_MASK (0x78u) +#define FLEXSPI_DLLCR_SLVDLYTARGET_SHIFT (3u) + +#define FLEXSPI_DLLCR_SLVDLYTARGET(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_DLLCR_SLVDLYTARGET_SHIFT)) & FLEXSPI_DLLCR_SLVDLYTARGET_MASK) +#define FLEXSPI_DLLCR_OVRDEN_MASK (0x100u) +#define FLEXSPI_DLLCR_OVRDEN_SHIFT (8u) + +#define FLEXSPI_DLLCR_OVRDEN(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_DLLCR_OVRDEN_SHIFT)) & FLEXSPI_DLLCR_OVRDEN_MASK) +#define FLEXSPI_DLLCR_OVRDVAL_MASK (0x7e00u) +#define FLEXSPI_DLLCR_OVRDVAL_SHIFT (9u) + +#define FLEXSPI_DLLCR_OVRDVAL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_DLLCR_OVRDVAL_SHIFT)) & FLEXSPI_DLLCR_OVRDVAL_MASK) + +#define FLEXSPI_DLLCR_COUNT (2u) + +#define FLEXSPI_STS0_SEQIDLE_MASK (0x1u) +#define FLEXSPI_STS0_SEQIDLE_SHIFT (0u) + +#define FLEXSPI_STS0_SEQIDLE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS0_SEQIDLE_SHIFT)) & FLEXSPI_STS0_SEQIDLE_MASK) +#define FLEXSPI_STS0_ARBIDLE_MASK (0x2u) +#define FLEXSPI_STS0_ARBIDLE_SHIFT (1u) + +#define FLEXSPI_STS0_ARBIDLE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS0_ARBIDLE_SHIFT)) & FLEXSPI_STS0_ARBIDLE_MASK) +#define FLEXSPI_STS0_ARBCMDSRC_MASK (0xcu) +#define FLEXSPI_STS0_ARBCMDSRC_SHIFT (2u) + +#define FLEXSPI_STS0_ARBCMDSRC(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS0_ARBCMDSRC_SHIFT)) & FLEXSPI_STS0_ARBCMDSRC_MASK) + +#define FLEXSPI_STS1_AHBCMDERRID_MASK (0xfu) +#define FLEXSPI_STS1_AHBCMDERRID_SHIFT (0u) + +#define FLEXSPI_STS1_AHBCMDERRID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS1_AHBCMDERRID_SHIFT)) & FLEXSPI_STS1_AHBCMDERRID_MASK) +#define FLEXSPI_STS1_AHBCMDERRCODE_MASK (0xf00u) +#define FLEXSPI_STS1_AHBCMDERRCODE_SHIFT (8u) + +#define FLEXSPI_STS1_AHBCMDERRCODE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS1_AHBCMDERRCODE_SHIFT)) & FLEXSPI_STS1_AHBCMDERRCODE_MASK) +#define FLEXSPI_STS1_IPCMDERRID_MASK (0xf0000u) +#define FLEXSPI_STS1_IPCMDERRID_SHIFT (16u) + +#define FLEXSPI_STS1_IPCMDERRID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS1_IPCMDERRID_SHIFT)) & FLEXSPI_STS1_IPCMDERRID_MASK) +#define FLEXSPI_STS1_IPCMDERRCODE_MASK (0xf000000u) +#define FLEXSPI_STS1_IPCMDERRCODE_SHIFT (24u) + +#define FLEXSPI_STS1_IPCMDERRCODE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS1_IPCMDERRCODE_SHIFT)) & FLEXSPI_STS1_IPCMDERRCODE_MASK) + +#define FLEXSPI_STS2_ASLVLOCK_MASK (0x1u) +#define FLEXSPI_STS2_ASLVLOCK_SHIFT (0u) + +#define FLEXSPI_STS2_ASLVLOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_ASLVLOCK_SHIFT)) & FLEXSPI_STS2_ASLVLOCK_MASK) +#define FLEXSPI_STS2_AREFLOCK_MASK (0x2u) +#define FLEXSPI_STS2_AREFLOCK_SHIFT (1u) + +#define FLEXSPI_STS2_AREFLOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_AREFLOCK_SHIFT)) & FLEXSPI_STS2_AREFLOCK_MASK) +#define FLEXSPI_STS2_ASLVSEL_MASK (0xfcu) +#define FLEXSPI_STS2_ASLVSEL_SHIFT (2u) + +#define FLEXSPI_STS2_ASLVSEL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_ASLVSEL_SHIFT)) & FLEXSPI_STS2_ASLVSEL_MASK) +#define FLEXSPI_STS2_AREFSEL_MASK (0x3f00u) +#define FLEXSPI_STS2_AREFSEL_SHIFT (8u) + +#define FLEXSPI_STS2_AREFSEL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_AREFSEL_SHIFT)) & FLEXSPI_STS2_AREFSEL_MASK) +#define FLEXSPI_STS2_BSLVLOCK_MASK (0x10000u) +#define FLEXSPI_STS2_BSLVLOCK_SHIFT (16u) + +#define FLEXSPI_STS2_BSLVLOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_BSLVLOCK_SHIFT)) & FLEXSPI_STS2_BSLVLOCK_MASK) +#define FLEXSPI_STS2_BREFLOCK_MASK (0x20000u) +#define FLEXSPI_STS2_BREFLOCK_SHIFT (17u) + +#define FLEXSPI_STS2_BREFLOCK(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_BREFLOCK_SHIFT)) & FLEXSPI_STS2_BREFLOCK_MASK) +#define FLEXSPI_STS2_BSLVSEL_MASK (0xfc0000u) +#define FLEXSPI_STS2_BSLVSEL_SHIFT (18u) + +#define FLEXSPI_STS2_BSLVSEL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_BSLVSEL_SHIFT)) & FLEXSPI_STS2_BSLVSEL_MASK) +#define FLEXSPI_STS2_BREFSEL_MASK (0x3f000000u) +#define FLEXSPI_STS2_BREFSEL_SHIFT (24u) + +#define FLEXSPI_STS2_BREFSEL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_STS2_BREFSEL_SHIFT)) & FLEXSPI_STS2_BREFSEL_MASK) + +#define FLEXSPI_AHBSPNDSTS_ACTIVE_MASK (0x1u) +#define FLEXSPI_AHBSPNDSTS_ACTIVE_SHIFT (0u) + +#define FLEXSPI_AHBSPNDSTS_ACTIVE(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBSPNDSTS_ACTIVE_SHIFT)) & FLEXSPI_AHBSPNDSTS_ACTIVE_MASK) +#define FLEXSPI_AHBSPNDSTS_BUFID_MASK (0xeU) +#define FLEXSPI_AHBSPNDSTS_BUFID_SHIFT (1u) + +#define FLEXSPI_AHBSPNDSTS_BUFID(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBSPNDSTS_BUFID_SHIFT)) & FLEXSPI_AHBSPNDSTS_BUFID_MASK) +#define FLEXSPI_AHBSPNDSTS_DATLFT_MASK (0xffff0000u) +#define FLEXSPI_AHBSPNDSTS_DATLFT_SHIFT (16u) + +#define FLEXSPI_AHBSPNDSTS_DATLFT(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_AHBSPNDSTS_DATLFT_SHIFT)) & FLEXSPI_AHBSPNDSTS_DATLFT_MASK) + +#define FLEXSPI_IPRXFSTS_FILL_MASK (0xffu) +#define FLEXSPI_IPRXFSTS_FILL_SHIFT (0u) + +#define FLEXSPI_IPRXFSTS_FILL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPRXFSTS_FILL_SHIFT)) & FLEXSPI_IPRXFSTS_FILL_MASK) +#define FLEXSPI_IPRXFSTS_RDCNTR_MASK (0xffff0000u) +#define FLEXSPI_IPRXFSTS_RDCNTR_SHIFT (16u) + +#define FLEXSPI_IPRXFSTS_RDCNTR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPRXFSTS_RDCNTR_SHIFT)) & FLEXSPI_IPRXFSTS_RDCNTR_MASK) + +#define FLEXSPI_IPTXFSTS_FILL_MASK (0xffu) +#define FLEXSPI_IPTXFSTS_FILL_SHIFT (0u) + +#define FLEXSPI_IPTXFSTS_FILL(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPTXFSTS_FILL_SHIFT)) & FLEXSPI_IPTXFSTS_FILL_MASK) +#define FLEXSPI_IPTXFSTS_WRCNTR_MASK (0xffff0000u) +#define FLEXSPI_IPTXFSTS_WRCNTR_SHIFT (16u) + +#define FLEXSPI_IPTXFSTS_WRCNTR(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_IPTXFSTS_WRCNTR_SHIFT)) & FLEXSPI_IPTXFSTS_WRCNTR_MASK) + +#define FLEXSPI_RFDR_RXDATA_MASK (0xffffffffu) +#define FLEXSPI_RFDR_RXDATA_SHIFT (0u) + +#define FLEXSPI_RFDR_RXDATA(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_RFDR_RXDATA_SHIFT)) & FLEXSPI_RFDR_RXDATA_MASK) + +#define FLEXSPI_RFDR_COUNT (32u) + +#define FLEXSPI_TFDR_TXDATA_MASK (0xffffffffu) +#define FLEXSPI_TFDR_TXDATA_SHIFT (0u) + +#define FLEXSPI_TFDR_TXDATA(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_TFDR_TXDATA_SHIFT)) & FLEXSPI_TFDR_TXDATA_MASK) + +#define FLEXSPI_TFDR_COUNT (32u) + +#define FLEXSPI_LUT_COUNT (128u) + +#endif /* __ARCH_ARM_SRC_IMX9_HARDWARE_IMX9_FLEXSPI_H */ diff --git a/arch/arm64/src/imx9/imx9_flexspi.c b/arch/arm64/src/imx9/imx9_flexspi.c new file mode 100644 index 0000000000000..9ccb0a439c8ea --- /dev/null +++ b/arch/arm64/src/imx9/imx9_flexspi.c @@ -0,0 +1,1258 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_flexspi.c + * + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "arm64_internal.h" +#include "barriers.h" + +#include "imx9_gpio.h" +#include "imx9_ccm.h" +#include "imx9_clockconfig.h" +#include "imx9_flexspi.h" +#include "imx9_iomuxc.h" +#include "hardware/imx9_ccm.h" +#include "hardware/imx9_flexspi.h" +#include "hardware/imx9_pinmux.h" + +#ifdef CONFIG_IMX9_FLEXSPI + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* The state of the FlexSPI controller. + * + */ + +struct imx9_flexspidev_s +{ + struct flexspi_dev_s flexspi; /* Externally visible part of the FlexSPI + * interface */ + + struct flexspi_type_s *base; /* FlexSPI controller register base address */ + + bool initialized; /* TRUE: Controller has been initialized */ + + mutex_t lock; /* Assures mutually exclusive access to + * FlexSPI */ +}; + +/* FlexSPI methods */ + +static int imx9_flexspi_lock(struct flexspi_dev_s *dev, bool lock); +static int imx9_flexspi_transfer_blocking(struct flexspi_dev_s *dev, + struct flexspi_transfer_s *xfer); +static void imx9_flexspi_software_reset(struct flexspi_dev_s *dev); +static void imx9_flexspi_update_lut(struct flexspi_dev_s *dev, + uint32_t index, + const uint32_t *cmd, + uint32_t count); +static void imx9_flexspi_set_device_config(struct flexspi_dev_s *dev, + struct flexspi_device_config_s *config, + enum flexspi_port_e port); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* FlexSPI0 driver operations */ + +static const struct flexspi_ops_s g_flexspi0ops = +{ + .lock = imx9_flexspi_lock, + .transfer_blocking = imx9_flexspi_transfer_blocking, + .software_reset = imx9_flexspi_software_reset, + .update_lut = imx9_flexspi_update_lut, + .set_device_config = imx9_flexspi_set_device_config, +}; + +/* This is the overall state of the FlexSPI0 controller */ + +static struct imx9_flexspidev_s g_flexspi0dev = +{ + .flexspi = + { + .ops = &g_flexspi0ops, + }, + .base = (struct flexspi_type_s *)IMX9_FLEXSPI_BASE, + .lock = NXMUTEX_INITIALIZER, +}; + +#define FREQ_1MHz (1000000ul) +#define FLEXSPI_DLLCR_DEFAULT (0x100ul) +#define FLEXSPI_LUT_KEY_VAL (0x5af05af0ul) + +enum +{ + FLEXSPI_DELAY_CELL_UNIT_MIN = 75, /* 75ps */ + + FLEXSPI_DELAY_CELL_UNIT_MAX = 225, /* 225ps */ +}; + +enum +{ + FLEXSPI_FLASH_A_SAMPLE_CLOCK_SLAVE_DELAY_LOCKED = + FLEXSPI_STS2_ASLVLOCK_MASK, /* Flash A sample clock slave delay line locked */ + + FLEXSPI_FLASH_A_SAMPLE_CLOCK_REF_DELAY_LOCKED = + FLEXSPI_STS2_AREFLOCK_MASK, /* Flash A sample clock reference delay line locked */ + + FLEXSPI_FLASH_B_SAMPLE_CLOCK_SLAVE_DELAY_LOCKED = + FLEXSPI_STS2_BSLVLOCK_MASK, /* Flash B sample clock slave delay line locked */ + + FLEXSPI_FLASH_B_SAMPLE_CLOCK_REF_DELAY_LOCKED = + FLEXSPI_STS2_BREFLOCK_MASK, /* Flash B sample clock reference delay line locked */ +}; + +/* FLEXSPI interrupt status flags */ + +enum flexspi_flags_e +{ + FLEXSPI_KEYERROR_FLAG = FLEXSPI_INTEN_KEYERROR_MASK , + + FLEXSPI_KEYDONE_FLAG = FLEXSPI_INTEN_KEYDONE_MASK, + + FLEXSPI_SEQUENCE_EXECUTION_TIMEOUT_FLAG = FLEXSPI_INTEN_SEQTIMEOUTEN_MASK, /* Sequence execution timeout */ + + FLEXSPI_AHB_BUS_ERROR_FLAG = FLEXSPI_INTEN_AHBBUSERROREN_MASK, /* AHB Bus error flag */ + + FLEXSPI_SCK_STOPPED_BECAUSE_TX_EMPTY_FLAG = + FLEXSPI_INTEN_SCKSTOPBYWREN_MASK, /* SCK is stopped during command + * sequence because Async TX FIFO empty */ + + FLEXSPI_SCK_STOPPED_BECAUSE_RX_FULL_FLAG = + FLEXSPI_INTEN_SCKSTOPBYRDEN_MASK, /* SCK is stopped during command + * sequence because Async RX FIFO full */ + + FLEXSPI_IP_TX_FIFO_WATERMARK_EMPTY_FLAG = FLEXSPI_INTEN_IPTXWEEN_MASK, /* IP TX FIFO WaterMark empty */ + + FLEXSPI_IP_RX_FIFO_WATERMARK_AVAILABLE_FLAG = FLEXSPI_INTEN_IPRXWAEN_MASK, /* IP RX FIFO WaterMark available */ + + FLEXSPI_AHB_COMMAND_SEQUENCE_ERROR_FLAG = + FLEXSPI_INTEN_AHBCMDERREN_MASK, /* AHB triggered Command Sequences Error */ + + FLEXSPI_IP_COMMAND_SEQUENCE_ERROR_FLAG = FLEXSPI_INTEN_IPCMDERREN_MASK, /* IP triggered Command Sequences Error */ + + FLEXSPI_AHB_COMMAND_GRANT_TIMEOUT_FLAG = + FLEXSPI_INTEN_AHBCMDGEEN_MASK, /* AHB triggered Command Sequences Grant Timeout */ + + FLEXSPI_IP_COMMAND_GRANT_TIMEOUT_FLAG = + FLEXSPI_INTEN_IPCMDGEEN_MASK, /* IP triggered Command Sequences Grant Timeout */ + + FLEXSPI_IP_COMMAND_EXECUTION_DONE_FLAG = + FLEXSPI_INTEN_IPCMDDONEEN_MASK, /* IP triggered Command Sequences Execution finished */ + + FLEXSPI_ALL_INTERRUPT_FLAGS = 0x3fffu, /* All flags */ +}; + +/* Common sets of flags used by the driver */ + +enum flexspi_flag_constants_e +{ + /* Errors to check for */ + + ERROR_FLAGS = FLEXSPI_SEQUENCE_EXECUTION_TIMEOUT_FLAG | + FLEXSPI_IP_COMMAND_SEQUENCE_ERROR_FLAG | + FLEXSPI_IP_COMMAND_GRANT_TIMEOUT_FLAG, +}; + +#define FLEXSPI_AHB_BUFFER_COUNT (8) + +struct flexspi_ahb_buffer_config_s +{ + uint8_t priority; /* This priority for AHB Master Read which this AHB RX Buffer is assigned */ + + uint8_t master_index; /* AHB Master ID the AHB RX Buffer is assigned */ + + uint16_t buffer_size; /* AHB buffer size in byte */ + + bool enable_prefetch; /* AHB Read Prefetch Enable for current AHB RX Buffer corresponding Master, allows + * prefetch disable/enable separately for each master */ +}; + +/* FLEXSPI configuration structure */ + +struct flexspi_config_s +{ + enum flexspi_read_sample_clock_e rx_sample_clock; /* Sample Clock source selection for Flash Reading */ + + bool enable_sck_free_running; /* Enable/disable SCK output free-running */ + + bool enable_combination; /* Enable/disable combining PORT A and B Data Pins + * (SIOA[3:0] and SIOB[3:0]) to support Flash Octal mode */ + + bool enable_doze; /* Enable/disable doze mode support */ + + bool enable_half_speed_access; /* Enable/disable divide by 2 of the clock for half + * speed commands */ + + bool enable_sckb_diff_opt; /* Enable/disable SCKB pad use as SCKA differential clock + * output, when enable, Port B flash access is not available */ + + bool enable_same_config_for_all; /* Enable/disable same configuration for all connected devices + * when enabled, same configuration in FLASHA1CRx is applied to all */ + + uint16_t seq_timeout_cycle; /* Timeout wait cycle for command sequence execution, + * timeout after ahb_grant_timeout_cyle*1024 serial root clock cycles */ + + uint8_t ip_grant_timeout_cycle; /* Timeout wait cycle for IP command grant, timeout after + * ip_grant_timeout_cycle*1024 AHB clock cycles */ + + uint8_t tx_watermark; /* FLEXSPI IP transmit watermark value */ + + uint8_t rx_watermark; /* FLEXSPI receive watermark value */ + + struct + { + bool enable_ahb_write_ip_tx_fifo; /* Enable AHB bus write access to IP TX FIFO */ + bool enable_ahb_write_ip_rx_fifo; /* Enable AHB bus write access to IP RX FIFO */ + + uint8_t ahb_grant_timeout_cycle; /* Timeout wait cycle for AHB command grant, + * timeout after ahb_grant_timeout_cyle*1024 AHB clock cycles */ + + uint16_t ahb_bus_timeout_cycle; /* Timeout wait cycle for AHB read/write access, + * timeout after ahb_bus_timeout_cycle*1024 AHB clock cycles */ + + uint8_t resume_wait_cycle; /* Wait cycle for idle state before suspended command sequence + * resume, timeout after ahb_bus_timeout_cycle AHB clock cycles */ + + struct flexspi_ahb_buffer_config_s buffer[FLEXSPI_AHB_BUFFER_COUNT]; /* AHB buffer size */ + + bool enable_clear_ahb_buffer_opt; /* Enable/disable automatically clean AHB RX Buffer and TX Buffer + * when FLEXSPI returns STOP mode ACK */ + + bool enable_read_address_opt; /* Enable/disable remove AHB read burst start address alignment limitation. + * when enable, there is no AHB read burst start address alignment limitation */ + + bool enable_ahb_prefetch; /* Enable/disable AHB read prefetch feature, when enabled, FLEXSPI + * will fetch more data than current AHB burst */ + + bool enable_ahb_bufferable; /* Enable/disable AHB bufferable write access support, when enabled, + * FLEXSPI return before waiting for command execution finished */ + + bool enable_ahb_cachable; /* Enable AHB bus cachable read access support */ + } ahb_config; +}; + +/**************************************************************************** + * Prototypes + ****************************************************************************/ + +/* Check and clear IP command execution errors. + * + * @param base FLEXSPI base pointer. + * @param status interrupt status. + */ + +static int imx9_flexspi_check_and_clear_error(struct flexspi_type_s *base, + uint32_t status); + +/**************************************************************************** + * Variables + ****************************************************************************/ + +/**************************************************************************** + * Code + ****************************************************************************/ + +/* Software reset for the FLEXSPI logic. + * + * This function sets the software reset flags for both AHB and buffer domain + * and resets both AHB buffer and also IP FIFOs. + * + * @param base FLEXSPI peripheral base address. + */ + +static inline void imx9_flexspi_software_reset_private( + struct flexspi_type_s *base) +{ + base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK; + while (0u != (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK)) + { + } +} + +/* Returns whether the bus is idle. + * + * @param base FLEXSPI peripheral base address. + * @retval true Bus is idle. + * @retval false Bus is busy. + */ + +static inline bool imx9_flexspi_get_bus_idle_status( + struct flexspi_type_s *base) +{ + return (0u != (base->STS0 & FLEXSPI_STS0_ARBIDLE_MASK)) && + (0u != (base->STS0 & FLEXSPI_STS0_SEQIDLE_MASK)); +} + +static uint32_t imx9_flexspi_configure_dll(struct flexspi_type_s *base, + struct flexspi_device_config_s *config) +{ + bool is_unified_config = true; + uint32_t flexspi_dll_value; + uint32_t dll_value; + uint32_t temp; + + uint32_t rx_sample_clock = (base->MCR0 & FLEXSPI_MCR0_RXCLKSRC_MASK) >> + FLEXSPI_MCR0_RXCLKSRC_SHIFT; + switch (rx_sample_clock) + { + case (uint32_t)FLEXSPI_READ_SAMPLE_CLK_LOOPBACK_INTERNALLY: + case (uint32_t)FLEXSPI_READ_SAMPLE_CLK_LOOPBACK_FROM_DQS_PAD: + case (uint32_t)FLEXSPI_READ_SAMPLE_CLK_LOOPBACK_FROM_SCK_PAD: + is_unified_config = true; + break; + case (uint32_t)FLEXSPI_READ_SAMPLE_CLK_EXTERNAL_INPUT_FROM_DQS_PAD: + if (config->is_sck2_enabled) + { + is_unified_config = true; + } + else + { + is_unified_config = false; + } + break; + default: + assert(false); + break; + } + + if (is_unified_config) + { + flexspi_dll_value = FLEXSPI_DLLCR_DEFAULT; /* 1 fixed delay cells in DLL delay chain */ + } + else + { + if (config->flexspi_root_clk >= 100u * FREQ_1MHz) + { + /* DLLEN = 1, SLVDLYTARGET = 0xF, */ + + flexspi_dll_value = FLEXSPI_DLLCR_DLLEN(1) | + FLEXSPI_DLLCR_SLVDLYTARGET(0x0f); + } + else + { + temp = (uint32_t)config->data_valid_time * 1000u; /* Convert data valid time in ns to ps */ + + dll_value = temp / (uint32_t)FLEXSPI_DELAY_CELL_UNIT_MIN; + if (dll_value * (uint32_t)FLEXSPI_DELAY_CELL_UNIT_MIN < temp) + { + dll_value++; + } + flexspi_dll_value = FLEXSPI_DLLCR_OVRDEN(1) | + FLEXSPI_DLLCR_OVRDVAL(dll_value); + } + } + return flexspi_dll_value; +} + +static int imx9_flexspi_check_and_clear_error(struct flexspi_type_s *base, + uint32_t status) +{ + int result = 0; + + /* Check for error */ + + status &= (uint32_t)ERROR_FLAGS; + if (0u != status) + { + /* Select the correct error code */ + + if (0u != (status & (uint32_t)FLEXSPI_SEQUENCE_EXECUTION_TIMEOUT_FLAG)) + { + result = STATUS_FLEXSPI_SEQUENCE_EXECUTION_TIMEOUT; + } + else if (0u != (status & + (uint32_t)FLEXSPI_IP_COMMAND_SEQUENCE_ERROR_FLAG)) + { + result = STATUS_FLEXSPI_IP_COMMAND_SEQUENCE_ERROR; + } + else if (0u != (status & + (uint32_t)FLEXSPI_IP_COMMAND_GRANT_TIMEOUT_FLAG)) + { + result = STATUS_FLEXSPI_IP_COMMAND_GRANT_TIMEOUT; + } + else + { + assert(false); + } + + /* Clear the flags */ + + base->INTR |= status; + + /* Reset fifos. These flags clear automatically */ + + base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK; + base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK; + } + + return result; +} + +/* Initializes the FLEXSPI module and internal state. + * + * This function enables the clock for FLEXSPI and also configures the + * FLEXSPI with the input configure parameters. Users should call this + * function before any FLEXSPI operations. + * + * param base FLEXSPI peripheral base address. + * param config FLEXSPI configure structure. + */ + +void imx9_flexspi_init(struct flexspi_type_s *base, + const struct flexspi_config_s *config) +{ + uint32_t config_value = 0; + uint8_t i = 0; + + /* Reset peripheral before configuring it */ + + base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK; + imx9_flexspi_software_reset_private(base); + + /* Configure MCR0 configuration items */ + + config_value = FLEXSPI_MCR0_RXCLKSRC(config->rx_sample_clock) | + FLEXSPI_MCR0_DOZEEN(config->enable_doze) | + FLEXSPI_MCR0_IPGRANTWAIT(config->ip_grant_timeout_cycle) | + FLEXSPI_MCR0_AHBGRANTWAIT( + config->ahb_config.ahb_grant_timeout_cycle) | + FLEXSPI_MCR0_SCKFREERUNEN(config->enable_sck_free_running) | + FLEXSPI_MCR0_HSEN(config->enable_half_speed_access) | + FLEXSPI_MCR0_COMBINATIONEN(config->enable_combination) | + FLEXSPI_MCR0_ATDFEN( + config->ahb_config.enable_ahb_write_ip_tx_fifo) | + FLEXSPI_MCR0_ARDFEN( + config->ahb_config.enable_ahb_write_ip_rx_fifo) | + FLEXSPI_MCR0_MDIS_MASK; + base->MCR0 = config_value; + + /* Configure MCR1 configurations */ + + config_value = + FLEXSPI_MCR1_SEQWAIT(config->seq_timeout_cycle) | + FLEXSPI_MCR1_AHBBUSWAIT(config->ahb_config.ahb_bus_timeout_cycle); + + base->MCR1 = config_value; + + /* Configure MCR2 configurations */ + + config_value = base->MCR2; + config_value &= ~(FLEXSPI_MCR2_RESUMEWAIT_MASK | + FLEXSPI_MCR2_SCKBDIFFOPT_MASK | + FLEXSPI_MCR2_SAMEDEVICEEN_MASK | + FLEXSPI_MCR2_CLRAHBBUFOPT_MASK); + + config_value |= FLEXSPI_MCR2_RESUMEWAIT( + config->ahb_config.resume_wait_cycle) | + FLEXSPI_MCR2_SCKBDIFFOPT( + config->enable_sckb_diff_opt) | + FLEXSPI_MCR2_SAMEDEVICEEN( + config->enable_same_config_for_all) | + FLEXSPI_MCR2_CLRAHBBUFOPT( + config->ahb_config.enable_clear_ahb_buffer_opt); + + base->MCR2 = config_value; + + /* Configure AHB control items */ + + config_value = base->AHBCR; + config_value &= ~(FLEXSPI_AHBCR_READADDROPT_MASK | + FLEXSPI_AHBCR_PREFETCHEN_MASK | + FLEXSPI_AHBCR_BUFFERABLEEN_MASK | + FLEXSPI_AHBCR_CACHABLEEN_MASK); + + config_value |= FLEXSPI_AHBCR_READADDROPT( + config->ahb_config.enable_read_address_opt) | + FLEXSPI_AHBCR_PREFETCHEN( + config->ahb_config.enable_ahb_prefetch) | + FLEXSPI_AHBCR_BUFFERABLEEN( + config->ahb_config.enable_ahb_bufferable) | + FLEXSPI_AHBCR_CACHABLEEN( + config->ahb_config.enable_ahb_cachable); + + base->AHBCR = config_value; + + /* Configure AHB rx buffers */ + + for (i = 0; i < (uint32_t)FLEXSPI_AHB_BUFFER_COUNT; i++) + { + config_value = base->AHBRXBUFCR0[i]; + + config_value &= ~(FLEXSPI_AHBRXBUFCR0_PREFETCHEN_MASK | + FLEXSPI_AHBRXBUFCR0_PRIORITY_MASK | + FLEXSPI_AHBRXBUFCR0_MSTRID_MASK | + FLEXSPI_AHBRXBUFCR0_BUFSZ_MASK); + + config_value |= FLEXSPI_AHBRXBUFCR0_PREFETCHEN( + config->ahb_config.buffer[i].enable_prefetch) | + FLEXSPI_AHBRXBUFCR0_PRIORITY( + config->ahb_config.buffer[i].priority) | + FLEXSPI_AHBRXBUFCR0_MSTRID( + config->ahb_config.buffer[i].master_index) | + FLEXSPI_AHBRXBUFCR0_BUFSZ((uint32_t) + config->ahb_config.buffer[i].buffer_size / 8u); + + base->AHBRXBUFCR0[i] = config_value; + } + + /* Configure IP FIFO watermarks */ + + base->IPRXFCR &= ~FLEXSPI_IPRXFCR_RXWMRK_MASK; + base->IPRXFCR |= + FLEXSPI_IPRXFCR_RXWMRK((uint32_t)config->rx_watermark / 8u - 1u); + base->IPTXFCR &= ~FLEXSPI_IPTXFCR_TXWMRK_MASK; + base->IPTXFCR |= + FLEXSPI_IPTXFCR_TXWMRK((uint32_t)config->tx_watermark / 8u - 1u); + + /* Reset flash size on all ports */ + + for (i = 0; i < (uint32_t)FLEXSPI_PORT_COUNT; i++) + { + base->FLSHCR0[i] = 0; + } +} + +/* Gets default settings for FLEXSPI. + * + * param config FLEXSPI configuration structure. + */ + +void imx9_flexspi_get_default_config(struct flexspi_config_s *config) +{ + /* Initializes the configure structure to zero */ + + memset(config, 0, sizeof(*config)); + + config->rx_sample_clock = FLEXSPI_READ_SAMPLE_CLK_LOOPBACK_FROM_DQS_PAD; + config->enable_sck_free_running = false; + config->enable_combination = false; + config->enable_doze = true; + config->enable_half_speed_access = false; + config->enable_sckb_diff_opt = false; + config->enable_same_config_for_all = false; + config->seq_timeout_cycle = 0xffff; + config->ip_grant_timeout_cycle = 0xff; + config->tx_watermark = 8; + config->rx_watermark = 8; + config->ahb_config.enable_ahb_write_ip_tx_fifo = false; + config->ahb_config.enable_ahb_write_ip_rx_fifo = false; + config->ahb_config.ahb_grant_timeout_cycle = 0xff; + config->ahb_config.ahb_bus_timeout_cycle = 0xffff; + config->ahb_config.resume_wait_cycle = 0x20; + memset(config->ahb_config.buffer, 0, + sizeof(config->ahb_config.buffer)); + + /* Use invalid master ID 0xF and buffer size 0 for the first several + * buffers. + */ + + for (uint8_t i = 0; i < ((uint8_t)FLEXSPI_AHB_BUFFER_COUNT - 2u); i++) + { + /* Default enable AHB prefetch */ + + config->ahb_config.buffer[i].enable_prefetch = true; + + /* Invalid master index which is no used, so will never hit */ + + config->ahb_config.buffer[i].master_index = 0xf; + + /* Default buffer size 0 for buffer0 to + * buffer(FLEXSPI_AHB_BUFFER_COUNT - 3) + */ + + config->ahb_config.buffer[i].buffer_size = 0; + } + + for (uint8_t i = ((uint8_t)FLEXSPI_AHB_BUFFER_COUNT - 2); + i < (uint8_t)FLEXSPI_AHB_BUFFER_COUNT; i++) + { + config->ahb_config.buffer[i].enable_prefetch = true; /* Default enable + * AHB prefetch. + */ + + config->ahb_config.buffer[i].buffer_size = 256u; /* Default buffer + * size 256 bytes. + */ + } + + config->ahb_config.enable_clear_ahb_buffer_opt = false; + config->ahb_config.enable_read_address_opt = false; + config->ahb_config.enable_ahb_prefetch = false; + config->ahb_config.enable_ahb_bufferable = false; + config->ahb_config.enable_ahb_cachable = false; +} + +/* Configures the connected device parameter. + * + * This function configures the connected device relevant parameters, such + * as the size, command, and so on. The flash configuration value cannot have + * a default value. The user needs to configure it according to the connected + * device. + * + * param base FLEXSPI peripheral base address. + * param config Device configuration parameters. + * param port FLEXSPI Operation port. + */ + +void imx9_flexspi_set_device_config_private(struct flexspi_type_s *base, + struct flexspi_device_config_s *config, + enum flexspi_port_e port) +{ + uint32_t config_value = 0; + uint32_t status_value = 0; + uint8_t index = (uint8_t)port >> 1u; /* PortA with index 0, PortB with index 1 */ + + /* Wait for bus idle before change flash configuration */ + + while (!imx9_flexspi_get_bus_idle_status(base)) + { + } + + /* Configure flash size */ + + base->FLSHCR0[port] = config->flash_size; + + /* Configure flash parameters */ + + base->FLSHCR1[port] = + FLEXSPI_FLSHCR1_CSINTERVAL(config->cs_interval) | + FLEXSPI_FLSHCR1_CSINTERVALUNIT(config->cs_interval_unit) | + FLEXSPI_FLSHCR1_TCSH(config->cs_hold_time) | + FLEXSPI_FLSHCR1_TCSS(config->cs_setup_time) | + FLEXSPI_FLSHCR1_CAS(config->columnspace) | + FLEXSPI_FLSHCR1_WA(config->enable_word_address); + + /* Configure AHB operation items */ + + config_value = base->FLSHCR2[port]; + + config_value &= ~(FLEXSPI_FLSHCR2_AWRWAITUNIT_MASK | + FLEXSPI_FLSHCR2_AWRWAIT_MASK | + FLEXSPI_FLSHCR2_AWRSEQNUM_MASK | + FLEXSPI_FLSHCR2_AWRSEQID_MASK | + FLEXSPI_FLSHCR2_ARDSEQNUM_MASK | + FLEXSPI_FLSHCR2_ARDSEQID_MASK); + + config_value |= + FLEXSPI_FLSHCR2_AWRWAITUNIT(config->ahb_write_wait_unit) | + FLEXSPI_FLSHCR2_AWRWAIT(config->ahb_write_wait_interval); + + if (config->awr_seq_number > 0u) + { + config_value |= FLEXSPI_FLSHCR2_AWRSEQID( + (uint32_t)config->awr_seq_index) | + FLEXSPI_FLSHCR2_AWRSEQNUM( + (uint32_t)config->awr_seq_number - 1u); + } + + if (config->ard_seq_number > 0u) + { + config_value |= FLEXSPI_FLSHCR2_ARDSEQID( + (uint32_t)config->ard_seq_index) | + FLEXSPI_FLSHCR2_ARDSEQNUM( + (uint32_t)config->ard_seq_number - 1u); + } + + base->FLSHCR2[port] = config_value; + + /* Configure DLL */ + + config_value = imx9_flexspi_configure_dll(base, config); + base->DLLCR[index] = config_value; + + /* Configure write mask */ + + if (config->enable_write_mask) + { + base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMOPT1_MASK; + } + else + { + base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMOPT1_MASK; + } + + if (index == 0u) /* Port A */ + { + base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMENA_MASK; + base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMENA(config->enable_write_mask); + } + else + { + base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMENB_MASK; + base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMENB(config->enable_write_mask); + } + + /* Set RX Sample Clock */ + + config_value = base->MCR0; + config_value &= ~FLEXSPI_MCR0_RXCLKSRC_MASK; + config_value |= FLEXSPI_MCR0_RXCLKSRC(config->rx_sample_clock); + + /* Exit stop mode */ + + config_value &= ~FLEXSPI_MCR0_MDIS_MASK; + + base->MCR0 = config_value; + + /* According to ERR011377, need to delay at least 100 NOPs to ensure the + * DLL is locked. + */ + + status_value = + (index == 0u) ? + ((uint32_t)FLEXSPI_FLASH_A_SAMPLE_CLOCK_SLAVE_DELAY_LOCKED | + (uint32_t)FLEXSPI_FLASH_A_SAMPLE_CLOCK_REF_DELAY_LOCKED) : + ((uint32_t)FLEXSPI_FLASH_B_SAMPLE_CLOCK_SLAVE_DELAY_LOCKED | + (uint32_t)FLEXSPI_FLASH_B_SAMPLE_CLOCK_REF_DELAY_LOCKED); + + if (0u != (config_value & FLEXSPI_DLLCR_DLLEN_MASK)) + { + /* Wait slave delay line locked and slave reference delay line locked */ + + while ((base->STS2 & status_value) != status_value) + { + } + + /* Wait at least 100 NOPs */ + + for (uint8_t delay = 100u; delay > 0u; delay--) + { + asm("NOP"); + } + } +} + +/* Updates the LUT table. + * + * param base FLEXSPI peripheral base address. + * param index From which index start to update. + * It could be any index of the LUT table, which also allows + * user to update command content inside a command. Each command + * consists of up to 8 instructions and occupy 4*32-bit memory. + * param cmd Command sequence array. + * param count Number of sequences. + */ + +void imx9_flexspi_update_lut_private(struct flexspi_type_s *base, + uint32_t index, + const uint32_t *cmd, + uint32_t count) +{ + assert(index < 128u); + + uint32_t i = 0; + volatile uint32_t *lut_base; + + /* Wait for bus idle before change flash configuration */ + + while (!imx9_flexspi_get_bus_idle_status(base)) + { + } + + /* Unlock LUT for update */ + + base->LUTKEY = FLEXSPI_LUT_KEY_VAL; + base->LUTCR = 0x02; + + lut_base = &base->LUT[index]; + for (i = 0; i < count; i++) + { + *lut_base++ = *cmd++; + } + + /* Lock LUT */ + + base->LUTKEY = FLEXSPI_LUT_KEY_VAL; + base->LUTCR = 0x01; +} + +/* Sends a buffer of data bytes using blocking method. + * note This function blocks via polling until all bytes have been sent. + * param base FLEXSPI peripheral base address + * param buffer The data bytes to send + * param size The number of data bytes to send + * retval 0 write success without error + * STATUS_FLEXSPI_SEQUENCE_EXECUTION_TIMEOUT sequence execution timeout + * STATUS_FLEXSPI_IP_COMMAND_SEQUENCE_ERROR IP command sequence error + * detected + * STATUS_FLEXSPI_IP_COMMAND_GRANT_TIMEOUT IP command grant + * timeout detected. + */ + +static int imx9_flexspi_write_blocking(struct flexspi_type_s *base, + uint32_t *buffer, size_t size) +{ + uint32_t tx_watermark = ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> + FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1u; + uint32_t status; + int result = 0; + uint32_t i = 0; + + /* Send data buffer */ + + while (0u != size) + { + /* Wait until there is room in the fifo. This also checks for errors */ + + while (0u == ((status = base->INTR) & + (uint32_t)FLEXSPI_IP_TX_FIFO_WATERMARK_EMPTY_FLAG)) + { + } + + result = imx9_flexspi_check_and_clear_error(base, status); + + if (0 != result) + { + return result; + } + + /* Write watermark level data into tx fifo */ + + if (size >= 8u * tx_watermark) + { + for (i = 0u; i < 2u * tx_watermark; i++) + { + base->TFDR[i] = *buffer++; + } + + size = size - 8u * tx_watermark; + } + else + { + for (i = 0u; i < (size / 4u + 1u); i++) + { + base->TFDR[i] = *buffer++; + } + size = 0u; + } + + /* Push a watermark level data into IP TX FIFO */ + + base->INTR |= (uint32_t)FLEXSPI_IP_TX_FIFO_WATERMARK_EMPTY_FLAG; + } + + return result; +} + +/* Receives a buffer of data bytes using a blocking method. + * note This function blocks via polling until all bytes have been sent. + * param base FLEXSPI peripheral base address + * param buffer The data bytes to send + * param size The number of data bytes to receive + * retval 0 read success without error + * retval STATUS_FLEXSPI_SEQUENCE_EXECUTION_TIMEOUT sequence execution + * timeout retval STATUS_FLEXSPI_IP_COMMAND_SEQUENCE_ERROR IP command + * sequence error detected retval STATUS_FLEXSPI_IP_COMMAND_GRANT_TIMEOUT + * IP command grant timeout detected. + */ + +static int imx9_flexspi_read_blocking(struct flexspi_type_s *base, + uint32_t *buffer, size_t size) +{ + uint32_t rx_watermark = ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> + FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1u; + uint32_t status; + int result = 0; + uint32_t i = 0; + bool is_return = false; + + /* Send data buffer */ + + while (0u != size) + { + if (size >= 8u * rx_watermark) + { + /* Wait until there is room in the fifo. This also checks for + * errors. + */ + + while (0u == ((status = base->INTR) & + (uint32_t)FLEXSPI_IP_RX_FIFO_WATERMARK_AVAILABLE_FLAG)) + { + result = imx9_flexspi_check_and_clear_error(base, status); + + if (0 != result) + { + is_return = true; + break; + } + } + } + else + { + /* Wait fill level. This also checks for errors */ + + while (size > ((((base->IPRXFSTS) & FLEXSPI_IPRXFSTS_FILL_MASK) >> + FLEXSPI_IPRXFSTS_FILL_SHIFT) * 8u)) + { + result = imx9_flexspi_check_and_clear_error(base, base->INTR); + + if (0 != result) + { + is_return = true; + break; + } + } + } + + if (is_return) + { + break; + } + + result = imx9_flexspi_check_and_clear_error(base, base->INTR); + + if (0 != result) + { + break; + } + + /* Read watermark level data from rx fifo */ + + if (size >= 8u * rx_watermark) + { + for (i = 0u; i < 2u * rx_watermark; i++) + { + *buffer++ = base->RFDR[i]; + } + + size = size - 8u * rx_watermark; + } + else + { + for (i = 0u; i < ((size + 3u) / 4u); i++) + { + *buffer++ = base->RFDR[i]; + } + size = 0; + } + + /* Pop out a watermark level datas from IP RX FIFO */ + + base->INTR |= (uint32_t)FLEXSPI_IP_RX_FIFO_WATERMARK_AVAILABLE_FLAG; + } + + return result; +} + +/* Brief Execute command to transfer a buffer data bytes using a blocking + * method. param base FLEXSPI peripheral base address param xfer pointer to + * the transfer structure. retval 0 command transfer success without error + * retval STATUS_FLEXSPI_SEQUENCE_EXECUTION_TIMEOUT sequence execution + * timeout retval STATUS_FLEXSPI_IP_COMMAND_SEQUENCE_ERROR IP command + * sequence error detected retval STATUS_FLEXSPI_IP_COMMAND_GRANT_TIMEOUT + * IP command grant timeout detected. + */ + +int imx9_flexspi_transfer_blocking_private(struct flexspi_type_s *base, + struct flexspi_transfer_s *xfer) +{ + uint32_t config_value = 0; + int result = 0; + + /* Clear sequence pointer before sending data to external devices */ + + base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK; + + /* Clear former pending status before start this transfer */ + + base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | + FLEXSPI_INTR_IPCMDERR_MASK | + FLEXSPI_INTR_AHBCMDGE_MASK | + FLEXSPI_INTR_IPCMDGE_MASK; + + /* Configure base address */ + + base->IPCR0 = xfer->device_address; + + /* Reset fifos */ + + base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK; + base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK; + + /* Configure data size */ + + if ((xfer->cmd_type == FLEXSPI_READ) || + (xfer->cmd_type == FLEXSPI_WRITE) || + (xfer->cmd_type == FLEXSPI_CONFIG)) + { + config_value = FLEXSPI_IPCR1_IDATSZ(xfer->data_size); + } + + /* Configure sequence ID */ + + config_value |= + FLEXSPI_IPCR1_ISEQID((uint32_t)xfer->seq_index) | \ + FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->seq_number - 1u); + base->IPCR1 = config_value; + + /* Start Transfer */ + + base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK; + + if ((xfer->cmd_type == FLEXSPI_WRITE) || + (xfer->cmd_type == FLEXSPI_CONFIG)) + { + result = imx9_flexspi_write_blocking(base, xfer->data, + xfer->data_size); + } + else if (xfer->cmd_type == FLEXSPI_READ) + { + result = imx9_flexspi_read_blocking(base, xfer->data, + xfer->data_size); + } + + /* Wait for bus idle */ + + while (!imx9_flexspi_get_bus_idle_status(base)) + { + } + + if (xfer->cmd_type == FLEXSPI_COMMAND) + { + result = imx9_flexspi_check_and_clear_error(base, base->INTR); + } + + return result; +} + +/**************************************************************************** + * Name: imx9_flexspi_lock + * + * Description: + * On FlexSPI buses where there are multiple devices, it will be necessary + * to lock FlexSPI to have exclusive access to the buses for a sequence of + * transfers. The bus should be locked before the chip is selected. + * + * Input Parameters: + * dev - Device-specific state data + * lock - true: Lock FlexSPI bus, false: unlock FlexSPI bus + * + * Returned Value: + * Semaphore status + * + ****************************************************************************/ + +static int imx9_flexspi_lock(struct flexspi_dev_s *dev, bool lock) +{ + struct imx9_flexspidev_s *priv = (struct imx9_flexspidev_s *)dev; + int ret; + + spiinfo("lock=%d\n", lock); + if (lock) + { + ret = nxmutex_lock(&priv->lock); + } + else + { + ret = nxmutex_unlock(&priv->lock); + } + + return ret; +} + +/**************************************************************************** + * Name: imx9_flexspi_transfer_blocking + * + * Description: + * Perform one FlexSPI transfer + * + * Input Parameters: + * dev - Device-specific state data + * xfer - Describes the transfer to be performed. + * + * Returned Value: + * 0 on SUCCESS, STATUS_FLEXSPI_SEQUENCE_EXECUTION_TIMEOUT, + * STATUS_FLEXSPI_IP_COMMAND_SEQUENCE_ERROR or + * STATUS_FLEXSPI_IP_COMMAND_GRANT_TIMEOUT otherwise + * + ****************************************************************************/ + +static int imx9_flexspi_transfer_blocking(struct flexspi_dev_s *dev, + struct flexspi_transfer_s *xfer) +{ + struct imx9_flexspidev_s *priv = (struct imx9_flexspidev_s *)dev; + + return (int)imx9_flexspi_transfer_blocking_private(priv->base, xfer); +} + +/**************************************************************************** + * Name: imx9_flexspi_software_reset + * + * Description: + * Performs a software reset of FlexSPI + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_flexspi_software_reset(struct flexspi_dev_s *dev) +{ + struct imx9_flexspidev_s *priv = (struct imx9_flexspidev_s *)dev; + + imx9_flexspi_software_reset_private(priv->base); +} + +/**************************************************************************** + * Name: imx9_flexspi_update_lut + * + * Description: + * Perform FlexSPI LUT table update + * + * Input Parameters: + * dev - Device-specific state data + * index - Index start to update + * cmd - Command array + * count - Size of the array + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void imx9_flexspi_update_lut(struct flexspi_dev_s *dev, + uint32_t index, + const uint32_t *cmd, + uint32_t count) +{ + struct imx9_flexspidev_s *priv = (struct imx9_flexspidev_s *)dev; + + imx9_flexspi_update_lut_private(priv->base, index, cmd, count); +} + +/**************************************************************************** + * Name: imx9_flexspi_set_device_config + * + * Description: + * Perform FlexSPI device config + * + * Input Parameters: + * dev - Device-specific state data + * config - Config data for external device + * port - Port + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void imx9_flexspi_set_device_config(struct flexspi_dev_s *dev, + struct flexspi_device_config_s *config, + enum flexspi_port_e port) +{ + struct imx9_flexspidev_s *priv = (struct imx9_flexspidev_s *)dev; + + imx9_flexspi_set_device_config_private(priv->base, config, port); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_flexspi_initialize + * + * Description: + * Initialize the selected FlexSPI port in master mode + * + * Input Parameters: + * intf - Interface number(must be zero) + * + * Returned Value: + * Valid FlexSPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct flexspi_dev_s *imx9_flexspi_initialize(int intf) +{ + struct imx9_flexspidev_s *priv; + struct flexspi_config_s flexspi_config; + + /* The supported i.MX9 parts have only a single FlexSPI port. */ + + DEBUGASSERT(intf == 0); + + if (intf != 0) + { + return NULL; + } + + /* If this function is called multiple times, the following operations + * will be performed multiple times. + */ + + /* Select FlexSPI */ + + priv = &g_flexspi0dev; + + /* Enable clocking to the FlexSPI peripheral */ + + imx9_ccm_gate_on(CCM_LPCG_FLEXSPI1, true); + + /* Configure clock to safe 50MHz, src clock is 800Mhz */ + + imx9_ccm_configure_root_clock(CCM_CR_FLEXSPI1, SYS_PLL1PFD1, 16); + + /* Has the FlexSPI hardware been initialized? */ + + if (!priv->initialized) + { + /* Perform hardware initialization. Puts the FlexSPI into an active + * state. + */ + + imx9_flexspi_get_default_config(&flexspi_config); + imx9_flexspi_init(priv->base, &flexspi_config); + priv->initialized = true; + } + + return &priv->flexspi; +} + +#endif /* CONFIG_IMX9_FLEXSPI */ diff --git a/arch/arm64/src/imx9/imx9_flexspi.h b/arch/arm64/src/imx9/imx9_flexspi.h new file mode 100644 index 0000000000000..012197d599772 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_flexspi.h @@ -0,0 +1,573 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_flexspi.h + * + * 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_ARM64_SRC_IMX9_IMX9_FLEXSPI_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_FLEXSPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "chip.h" + +#ifdef CONFIG_IMX9_FLEXSPI + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* LUT - LUT 0..LUT 63 */ + +#define FLEXSPI_LUT_OPERAND0_MASK (0xffU) +#define FLEXSPI_LUT_OPERAND0_SHIFT (0U) + +/* OPERAND0 */ + +#define FLEXSPI_LUT_OPERAND0(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_OPERAND0_SHIFT)) & FLEXSPI_LUT_OPERAND0_MASK) +#define FLEXSPI_LUT_NUM_PADS0_MASK (0x300U) +#define FLEXSPI_LUT_NUM_PADS0_SHIFT (8U) + +/* NUM_PADS0 */ + +#define FLEXSPI_LUT_NUM_PADS0(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_NUM_PADS0_SHIFT)) & FLEXSPI_LUT_NUM_PADS0_MASK) +#define FLEXSPI_LUT_OPCODE0_MASK (0xfc00U) +#define FLEXSPI_LUT_OPCODE0_SHIFT (10U) + +/* OPCODE0 */ + +#define FLEXSPI_LUT_OPCODE0(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_OPCODE0_SHIFT)) & FLEXSPI_LUT_OPCODE0_MASK) +#define FLEXSPI_LUT_OPERAND1_MASK (0xff0000U) +#define FLEXSPI_LUT_OPERAND1_SHIFT (16U) + +/* OPERAND1 */ + +#define FLEXSPI_LUT_OPERAND1(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_OPERAND1_SHIFT)) & FLEXSPI_LUT_OPERAND1_MASK) +#define FLEXSPI_LUT_NUM_PADS1_MASK (0x3000000U) +#define FLEXSPI_LUT_NUM_PADS1_SHIFT (24U) + +/* NUM_PADS1 - NUM_PADS1 */ + +#define FLEXSPI_LUT_NUM_PADS1(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_NUM_PADS1_SHIFT)) & FLEXSPI_LUT_NUM_PADS1_MASK) +#define FLEXSPI_LUT_OPCODE1_MASK (0xfc000000U) +#define FLEXSPI_LUT_OPCODE1_SHIFT (26U) + +/* OPCODE1 */ + +#define FLEXSPI_LUT_OPCODE1(x) (((uint32_t)(((uint32_t)(x)) << FLEXSPI_LUT_OPCODE1_SHIFT)) & FLEXSPI_LUT_OPCODE1_MASK) + +/* Formula to form FLEXSPI instructions in LUT table */ + +#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ + (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | \ + FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ + FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) + +/* Access macros ************************************************************/ + +/**************************************************************************** + * Name: FLEXSPI_LOCK + * + * Description: + * On FlexSPI buses where there are multiple devices, it will be necessary + * to lock FlexSPI to have exclusive access to the buses for a sequence of + * transfers. The bus should be locked before the chip is selected. + * + * Input Parameters: + * dev - Device-specific state data + * lock - true: Lock FlexSPI bus, false: unlock FlexSPI bus + * + * Returned Value: + * None + * + ****************************************************************************/ + +#define FLEXSPI_LOCK(d,l) (d)->ops->lock(d,l) + +/**************************************************************************** + * Name: FLEXSPI_TRANSFER + * + * Description: + * Perform one FlexSPI transfer + * + * Input Parameters: + * dev - Device-specific state data + * xfer - Describes the transfer to be performed. + * + * Returned Value: + * 0 on SUCCESS, STATUS_FLEXSPI_SEQUENCE_EXECUTION_TIMEOUT, + * STATUS_FLEXSPI_IP_COMMAND_SEQUENCE_ERROR or + * STATUS_FLEXSPI_IP_COMMAND_GRANT_TIMEOUT otherwise + * + ****************************************************************************/ + +#define FLEXSPI_TRANSFER(d,x) (d)->ops->transfer_blocking(d,x) + +/**************************************************************************** + * Name: FLEXSPI_SOFTWARE_RESET + * + * Description: + * Perform FlexSPI software reset + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * none + * + ****************************************************************************/ + +#define FLEXSPI_SOFTWARE_RESET(d) (d)->ops->software_reset(d) + +/**************************************************************************** + * Name: FLEXSPI_UPDATE_LUT + * + * Description: + * Perform FlexSPI LUT table update + * + * Input Parameters: + * dev - Device-specific state data + * index - Index start to update + * cmd - Command array + * count - Size of the array + * + * Returned Value: + * none + * + ****************************************************************************/ + +#define FLEXSPI_UPDATE_LUT(d,i,c,n) (d)->ops->update_lut(d,i,c,n) + +/**************************************************************************** + * Name: FLEXSPI_SET_DEVICE_CONFIG + * + * Description: + * Perform FlexSPI device config + * + * Input Parameters: + * dev - Device-specific state data + * config - Config data for external device + * port - Port + * + * Returned Value: + * none + * + ****************************************************************************/ + +#define FLEXSPI_SET_DEVICE_CONFIG(d,c,p) (d)->ops->set_device_config(d,c,p) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* CMD definition of FLEXSPI, use to form LUT instruction, flexspi_command */ + +enum +{ + FLEXSPI_COMMAND_STOP = 0x00, /* Stop execution, deassert CS */ + FLEXSPI_COMMAND_SDR = 0x01, /* Transmit Command code to Flash, + * using SDR mode. + */ + + FLEXSPI_COMMAND_RADDR_SDR = 0x02, /* Transmit Row Address to Flash, + * using SDR mode. + */ + + FLEXSPI_COMMAND_CADDR_SDR = 0x03, /* Transmit Column Address to + * Flash, using SDR mode. + */ + + FLEXSPI_COMMAND_MODE1_SDR = 0x04, /* Transmit 1-bit Mode bits to + * Flash, using SDR mode. + */ + + FLEXSPI_COMMAND_MODE2_SDR = 0x05, /* Transmit 2-bit Mode bits to + * Flash, using SDR mode. + */ + + FLEXSPI_COMMAND_MODE4_SDR = 0x06, /* Transmit 4-bit Mode bits to + * Flash, using SDR mode. + */ + + FLEXSPI_COMMAND_MODE8_SDR = 0x07, /* Transmit 8-bit Mode bits to + * Flash, using SDR mode. + */ + + FLEXSPI_COMMAND_WRITE_SDR = 0x08, /* Transmit Programming Data to + * Flash, using SDR mode. + */ + + FLEXSPI_COMMAND_READ_SDR = 0x09, /* Receive Read Data from Flash, + * using SDR mode. + */ + + FLEXSPI_COMMAND_LEARN_SDR = 0x0a, /* Receive Read Data or Preamble + * bit from Flash, SDR mode. + */ + + FLEXSPI_COMMAND_DATSZ_SDR = 0x0b, /* Transmit Read/Program Data size + * (byte) to Flash, SDR mode. + */ + + FLEXSPI_COMMAND_DUMMY_SDR = 0x0c, /* Leave data lines undriven by + * FlexSPI controller. + */ + + FLEXSPI_COMMAND_DUMMY_RWDS_SDR = 0x0d, /* Leave data lines undriven by + * FlexSPI controller, dummy cycles + * decided by RWDS. + */ + + FLEXSPI_COMMAND_DDR = 0x21, /* Transmit Command code to Flash, + * using DDR mode. + */ + + FLEXSPI_COMMAND_RADDR_DDR = 0x22, /* Transmit Row Address to Flash, + * using DDR mode. + */ + + FLEXSPI_COMMAND_CADDR_DDR = 0x23, /* Transmit Column Address to + * Flash, using DDR mode. + */ + + FLEXSPI_COMMAND_MODE1_DDR = 0x24, /* Transmit 1-bit Mode bits to + * Flash, using DDR mode. + */ + + FLEXSPI_COMMAND_MODE2_DDR = 0x25, /* Transmit 2-bit Mode bits to + * Flash, using DDR mode. + */ + + FLEXSPI_COMMAND_MODE4_DDR = 0x26, /* Transmit 4-bit Mode bits to + * Flash, using DDR mode. + */ + + FLEXSPI_COMMAND_MODE8_DDR = 0x27, /* Transmit 8-bit Mode bits to + * Flash, using DDR mode. + */ + + FLEXSPI_COMMAND_WRITE_DDR = 0x28, /* Transmit Programming Data to + * Flash, using DDR mode. + */ + + FLEXSPI_COMMAND_READ_DDR = 0x29, /* Receive Read Data from Flash, + * using DDR mode. + */ + + FLEXSPI_COMMAND_LEARN_DDR = 0x2a, /* Receive Read Data or Preamble + * bit from Flash, DDR mode. + */ + + FLEXSPI_COMMAND_DATSZ_DDR = 0x2b, /* Transmit Read/Program Data size + * (byte) to Flash, DDR mode. + */ + + FLEXSPI_COMMAND_DUMMY_DDR = 0x2c, /* Leave data lines undriven by + * FlexSPI controller. + */ + + FLEXSPI_COMMAND_DUMMY_RWDS_DDR = 0x2d, /* Leave data lines undriven by + * FlexSPI controller, dummy cycles + * decided by RWDS. + */ + + FLEXSPI_COMMAND_JUMP_ON_CS = 0x1f, /* Stop execution, deassert CS and + * save operand[7:0] as the + * instruction start pointer for + * next sequence + */ +}; + +/* Pad definition of FLEXSPI, use to form LUT instruction */ + +enum flexspi_pad_e +{ + FLEXSPI_1PAD = 0x00, /* Transmit command/address and transmit/receive data + * only through DATA0/DATA1. + */ + + FLEXSPI_2PAD = 0x01, /* Transmit command/address and transmit/receive data + * only through DATA[1:0]. + */ + + FLEXSPI_4PAD = 0x02, /* Transmit command/address and transmit/receive data + * only through DATA[3:0]. + */ + + FLEXSPI_8PAD = 0x03, /* Transmit command/address and transmit/receive data + * only through DATA[7:0]. + */ +}; + +/* FLEXSPI operation port select */ + +enum flexspi_port_e +{ + FLEXSPI_PORT_A1 = 0x0, /* Access flash on A1 port */ + FLEXSPI_PORT_A2, /* Access flash on A2 port */ + FLEXSPI_PORT_B1, /* Access flash on B1 port */ + FLEXSPI_PORT_B2, /* Access flash on B2 port */ + FLEXSPI_PORT_COUNT +}; + +/* Command type */ + +enum flexspi_command_type_e +{ + FLEXSPI_COMMAND, /* FlexSPI operation: Only command, both TX and Rx buffer + * are ignored. + */ + + FLEXSPI_CONFIG, /* FlexSPI operation: Configure device mode, the TX fifo + * size is fixed in LUT. + */ + + FLEXSPI_READ, /* FlexSPI operation: Read, only Rx Buffer is + * effective. + */ + + FLEXSPI_WRITE, /* FlexSPI operation: Read, only Tx Buffer is + * effective. + */ +}; + +/* Status structure of FLEXSPI */ + +enum +{ + STATUS_FLEXSPI_BUSY = 0, /* FLEXSPI is busy */ + + STATUS_FLEXSPI_SEQUENCE_EXECUTION_TIMEOUT = 1, /* Sequence execution + * timeout error occurred + * during FLEXSPI transfer. + */ + + STATUS_FLEXSPI_IP_COMMAND_SEQUENCE_ERROR = 2, /* IP command Sequence + * execution timeout error + * occurred during FLEXSPI + * transfer. + */ + + STATUS_FLEXSPI_IP_COMMAND_GRANT_TIMEOUT = 3, /* IP command grant timeout + * error occurred during + * FLEXSPI transfer. + */ +}; + +/* Transfer structure for FLEXSPI */ + +struct flexspi_transfer_s +{ + uint32_t device_address; /* Operation device address */ + enum flexspi_port_e port; /* Operation port */ + enum flexspi_command_type_e cmd_type; /* Execution command type */ + uint8_t seq_index; /* Sequence ID for command */ + uint8_t seq_number; /* Sequence number for command */ + uint32_t *data; /* Data buffer */ + size_t data_size; /* Data size in bytes */ +}; + +/* FLEXSPI interval unit for flash device select */ + +enum flexspi_cs_interval_cycle_unit_e +{ + FLEXSPI_CS_INTERVAL_UNIT1_SCK_CYCLE = 0x0, /* Chip selection interval: + * CSINTERVAL * 1 serial + * clock cycle. + */ + + FLEXSPI_CS_INTERVAL_UNIT256_SCK_CYCLE = 0x1, /* Chip selection interval: + * CSINTERVAL * 256 serial + * clock cycle. + */ +}; + +/* FLEXSPI AHB wait interval unit for writing */ + +enum flexspi_ahb_write_wait_unit_e +{ + FLEXSPI_AHB_WRITE_WAIT_UNIT2_AHB_CYCLE = 0x0, /* AWRWAIT unit is 2 + * ahb clock cycle. + */ + + FLEXSPI_AHB_WRITE_WAIT_UNIT8_AHB_CYCLE = 0x1, /* AWRWAIT unit is 8 + * ahb clock cycle. + */ + + FLEXSPI_AHB_WRITE_WAIT_UNIT32_AHB_CYCLE = 0x2, /* AWRWAIT unit is 32 + * ahb clock cycle. + */ + + FLEXSPI_AHB_WRITE_WAIT_UNIT128_AHB_CYCLE = 0x3, /* AWRWAIT unit is 128 + * ahb clock cycle. + */ + + FLEXSPI_AHB_WRITE_WAIT_UNIT512_AHB_CYCLE = 0x4, /* AWRWAIT unit is 512 + * ahb clock cycle. + */ + + FLEXSPI_AHB_WRITE_WAIT_UNIT2048_AHB_CYCLE = 0x5, /* AWRWAIT unit is 2048 + * ahb clock cycle. + */ + + FLEXSPI_AHB_WRITE_WAIT_UNIT8192_AHB_CYCLE = 0x6, /* AWRWAIT unit is 8192 + * ahb clock cycle. + */ + + FLEXSPI_AHB_WRITE_WAIT_UNIT32768_AHB_CYCLE = 0x7, /* AWRWAIT unit is 32768 + * ahb clock cycle. + */ +}; + +/* FLEXSPI sample clock source selection for Flash Reading */ + +enum flexspi_read_sample_clock_e +{ + FLEXSPI_READ_SAMPLE_CLK_LOOPBACK_INTERNALLY = 0x0u, /* Dummy Read strobe generated by FlexSPI Controller + * and loopback internally */ + + FLEXSPI_READ_SAMPLE_CLK_LOOPBACK_FROM_DQS_PAD = 0x1u, /* Dummy Read strobe generated by FlexSPI Controller + * and loopback from DQS pad */ + + FLEXSPI_READ_SAMPLE_CLK_LOOPBACK_FROM_SCK_PAD = 0x2u, /* SCK output clock and loopback from SCK pad */ + + FLEXSPI_READ_SAMPLE_CLK_EXTERNAL_INPUT_FROM_DQS_PAD = 0x3u, /* Flash provided Read strobe and input from DQS pad */ +}; + +/* External device configuration items */ + +struct flexspi_device_config_s +{ + uint32_t flexspi_root_clk; /* FLEXSPI serial root clock */ + bool is_sck2_enabled; /* FLEXSPI use SCK2 */ + uint32_t flash_size; /* Flash size in KByte */ + + enum flexspi_cs_interval_cycle_unit_e cs_interval_unit; /* CS interval unit, 1 + * or 256 cycle. + */ + + uint16_t cs_interval; /* CS line assert interval, multiply CS + * interval unit to get the CS line assert + * interval cycles. + */ + + uint8_t cs_hold_time; /* CS line hold time */ + uint8_t cs_setup_time; /* CS line setup time */ + uint8_t data_valid_time; /* Data valid time for external device */ + uint8_t columnspace; /* Column space size */ + bool enable_word_address; /* If enable word address */ + uint8_t awr_seq_index; /* Sequence ID for AHB write command */ + uint8_t awr_seq_number; /* Sequence number for AHB write command */ + uint8_t ard_seq_index; /* Sequence ID for AHB read command */ + uint8_t ard_seq_number; /* Sequence number for AHB read command */ + + enum flexspi_ahb_write_wait_unit_e ahb_write_wait_unit; /* AHB write wait unit */ + + uint16_t ahb_write_wait_interval; /* AHB write wait interval, multiply AHB + * write interval unit to get the AHB + * write wait cycles. + */ + + bool enable_write_mask; /* Enable/Disable FLEXSPI drive DQS pin as write mask + * when writing to external device. + */ + + enum flexspi_read_sample_clock_e rx_sample_clock; /* Sample Clock source selection for Flash Reading */ +}; + +/* The FlexSPI vtable */ + +struct flexspi_dev_s; +struct flexspi_ops_s +{ + int (*lock)(struct flexspi_dev_s *dev, bool lock); + int (*transfer_blocking)(struct flexspi_dev_s *dev, + struct flexspi_transfer_s *xfer); + void (*software_reset)(struct flexspi_dev_s *dev); + void (*update_lut)(struct flexspi_dev_s *dev, + uint32_t index, const uint32_t *cmd, + uint32_t count); + void (*set_device_config)(struct flexspi_dev_s *dev, + struct flexspi_device_config_s *config, + enum flexspi_port_e port); +}; + +/* FlexSPI private data. This structure only defines the initial fields of + * the structure visible to the FlexSPI client. The specific implementation + * may add additional, device specific fields + */ + +struct flexspi_dev_s +{ + const struct flexspi_ops_s *ops; +}; + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_flexspi_initialize + * + * Description: + * Initialize the selected FlexSPI port in master mode + * + * Input Parameters: + * intf - Interface number(must be zero) + * + * Returned Value: + * Valid FlexSPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct flexspi_dev_s; +struct flexspi_dev_s *imx9_flexspi_initialize(int intf); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_IMX9_FLEXSPI */ +#endif /* __ARCH_ARM_SRC_IMX9_IMX9_FLEXSPI_H */ From 13926030f6a645a7dfc8fc5ec937e09ae683a677 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 3 Jul 2024 15:27:44 +0300 Subject: [PATCH 2/2] arch/arm64/src/imx9: Add an mtd driver for NOR flash on FlexSPI interface This is an initial FlexSPI SPI NOR MTD driver for IMX9 This supprts M25P SPI NOR on FlexSPI for now, and can later be extended to other SPINOR devices if needed. The following configurations are needed to use this driver: CONFIG_IMX9_FLEXSPI_NOR=y CONFIG_MTD_M25P=y In addition, board initialization logic needs to call the imx9_flexspi_nor_initialize to receive a pointer to the mtd device. Signed-off-by: Jukka Laitinen Co-authored-by: Jouni Ukkonen --- arch/arm64/src/imx9/Kconfig | 4 + arch/arm64/src/imx9/Make.defs | 4 + arch/arm64/src/imx9/imx9_flexspi_nor.c | 1081 ++++++++++++++++++++++++ arch/arm64/src/imx9/imx9_flexspi_nor.h | 83 ++ 4 files changed, 1172 insertions(+) create mode 100644 arch/arm64/src/imx9/imx9_flexspi_nor.c create mode 100644 arch/arm64/src/imx9/imx9_flexspi_nor.h diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index 67ee9c7454e2b..0370495e9780b 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -250,6 +250,10 @@ config IMX9_FLEXSPI bool "ENABLE FLEXSPI interface" default n +config IMX9_FLEXSPI_NOR + bool "Enable NOR flash on FLEXSPI interface" + select IMX9_FLEXSPI + default n config IMX9_FLEXIO1_PWM depends on PWM diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs index f97bb2a676ad6..89e12744d997e 100644 --- a/arch/arm64/src/imx9/Make.defs +++ b/arch/arm64/src/imx9/Make.defs @@ -71,3 +71,7 @@ endif ifeq ($(CONFIG_IMX9_FLEXSPI), y) CHIP_CSRCS += imx9_flexspi.c endif + +ifeq ($(CONFIG_IMX9_FLEXSPI_NOR), y) + CHIP_CSRCS += imx9_flexspi_nor.c +endif diff --git a/arch/arm64/src/imx9/imx9_flexspi_nor.c b/arch/arm64/src/imx9/imx9_flexspi_nor.c new file mode 100644 index 0000000000000..4bf471c197f80 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_flexspi_nor.c @@ -0,0 +1,1081 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_flexspi_nor.c + * + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "chip.h" +#include "imx9_flexspi.h" +#include "imx9_iomuxc.h" +#include "hardware/imx9_flexspi.h" +#include "hardware/imx9_pinmux.h" + +#ifdef CONFIG_IMX9_FLEXSPI_NOR + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_M25P_SUBSECTOR_ERASE +#error This driver currently requires CONFIG_M25P_SUBSECTOR_ERASE +#endif + +# if !defined(ARMV8A_DCACHE_LINESIZE) || ARMV8A_DCACHE_LINESIZE == 0 +# undef ARMV8A_DCACHE_LINESIZE +# define ARMV8A_DCACHE_LINESIZE 64 +# endif + +#define ALIGN_MASK (ARMV8A_DCACHE_LINESIZE - 1) +#define ALIGN_UP(n) (((n)+ALIGN_MASK) & ~ALIGN_MASK) + +/* Configuration ************************************************************/ + +/* Per the data sheet, M25P10 parts can be driven with either SPI mode 0 + * (CPOL=0 and CPHA=0) or mode 3 (CPOL=1 and CPHA=1). But I have heard that + * other devices can operated in mode 0 or 1. + * So you may need to specify CONFIG_M25P_SPIMODE to + * select the best mode for your device. + * If CONFIG_M25P_SPIMODE is not defined, mode 0 will be used. + */ + +#ifndef CONFIG_M25P_SPIMODE +# define CONFIG_M25P_SPIMODE SPIDEV_MODE0 +#endif + +#ifndef CONFIG_M25P_SPIFREQUENCY +# define CONFIG_M25P_SPIFREQUENCY 20000000 +#endif + +/* Various manufacturers may have produced the parts. + * 0x20 is the manufacturer ID for the STMicro MP25x serial FLASH. + * If, for example, you are using the a Macronix International MX25 + * serial FLASH, the correct manufacturer ID would be 0xc2. + */ + +#ifndef CONFIG_M25P_MANUFACTURER +# define CONFIG_M25P_MANUFACTURER 0x20 +#endif + +#ifndef CONFIG_M25P_MEMORY_TYPE +# define CONFIG_M25P_MEMORY_TYPE 0x20 +#endif + +#ifndef CONFIG_MT25Q_MEMORY_TYPE +# define CONFIG_MT25Q_MEMORY_TYPE 0xBA +#endif + +#ifndef CONFIG_MT25QU_MEMORY_TYPE +# define CONFIG_MT25QU_MEMORY_TYPE 0xBB +#endif + +/* M25P Registers ***********************************************************/ + +/* Identification register values */ + +#define M25P_MANUFACTURER CONFIG_M25P_MANUFACTURER +#define M25P_MEMORY_TYPE CONFIG_M25P_MEMORY_TYPE +#define MT25Q_MEMORY_TYPE CONFIG_MT25Q_MEMORY_TYPE +#define MT25QU_MEMORY_TYPE CONFIG_MT25QU_MEMORY_TYPE +#define M25P_RES_ID 0x13 +#define M25P_M25P1_CAPACITY 0x11 /* 1 M-bit */ +#define M25P_EN25F80_CAPACITY 0x14 /* 8 M-bit */ +#define M25P_M25P16_CAPACITY 0x15 /* 16 M-bit */ +#define M25P_M25P32_CAPACITY 0x16 /* 32 M-bit */ +#define M25P_M25P64_CAPACITY 0x17 /* 64 M-bit */ +#define M25P_M25P128_CAPACITY 0x18 /* 128 M-bit */ +#define M25P_MT25Q128_CAPACITY 0x18 /* 128 M-bit */ +#define M25P_MT25Q256_CAPACITY 0x19 /* 256 M-bit */ +#define M25P_MT25Q512_CAPACITY 0x20 /* 512 M-bit */ +#define M25P_MT25Q1G_CAPACITY 0x21 /* 1 G-bit */ + +/* M25P1 capacity is 131,072 bytes: + * (4 sectors) * (32,768 bytes per sector) + * (512 pages) * (256 bytes per page) + */ + +#define M25P_M25P1_SECTOR_SHIFT 15 /* Sector size 1 << 15 = 65,536 */ +#define M25P_M25P1_NSECTORS 4 +#define M25P_M25P1_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define M25P_M25P1_NPAGES 512 + +/* EN25F80 capacity is 1,048,576 bytes: + * (16 sectors) * (65,536 bytes per sector) + * (512 pages) * (256 bytes per page) + */ + +#define M25P_EN25F80_SECTOR_SHIFT 16 /* Sector size 1 << 15 = 65,536 */ +#define M25P_EN25F80_NSECTORS 16 +#define M25P_EN25F80_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define M25P_EN25F80_NPAGES 4096 +#define M25P_EN25F80_SUBSECT_SHIFT 12 /* Sub-Sector size 1 << 12 = 4,096 */ +#define M25P_EN25F80_NSUBSECTORS 256 + +/* M25P16 capacity is 2,097,152 bytes: + * (32 sectors) * (65,536 bytes per sector) + * (8192 pages) * (256 bytes per page) + */ + +#define M25P_M25P16_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */ +#define M25P_M25P16_NSECTORS 32 +#define M25P_M25P16_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define M25P_M25P16_NPAGES 8192 +#define M25P_M25PX16_SUBSECT_SHIFT 12 /* Sub-Sector size 1 << 12 = 4,096 */ + +/* M25P32 capacity is 4,194,304 bytes: + * (64 sectors) * (65,536 bytes per sector) + * (16384 pages) * (256 bytes per page) + */ + +#define M25P_M25P32_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */ +#define M25P_M25P32_NSECTORS 64 +#define M25P_M25P32_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define M25P_M25P32_NPAGES 16384 +#define M25P_M25PX32_SUBSECT_SHIFT 12 /* Sub-Sector size 1 << 12 = 4,096 */ + +/* M25P64 capacity is 8,338,608 bytes: + * (128 sectors) * (65,536 bytes per sector) + * (32768 pages) * (256 bytes per page) + */ + +#define M25P_M25P64_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */ +#define M25P_M25P64_NSECTORS 128 +#define M25P_M25P64_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define M25P_M25P64_NPAGES 32768 + +/* M25P128 capacity is 16,777,216 bytes: + * (64 sectors) * (262,144 bytes per sector) + * (65536 pages) * (256 bytes per page) + */ + +#define M25P_M25P128_SECTOR_SHIFT 18 /* Sector size 1 << 18 = 262,144 */ +#define M25P_M25P128_NSECTORS 64 +#define M25P_M25P128_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define M25P_M25P128_NPAGES 65536 + +/* MT25Q128 capacity is 16,777,216 bytes: + * (256 sectors) * (65,536 bytes per sector) + * (65536 pages) * (256 bytes per page) + */ + +#define M25P_MT25Q128_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */ +#define M25P_MT25Q128_NSECTORS 256 +#define M25P_MT25Q128_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define M25P_MT25Q128_NPAGES 65536 +#define M25P_MT25Q128_SUBSECT_SHIFT 12 /* Sub-Sector size 1 << 12 = 4,096 */ + +/* MT25Q256 capacity is 33,554,432 bytes: + * (512 sectors) * (65,536 bytes per sector) + * (131072 pages) * (256 bytes per page) + */ + +#define M25P_MT25Q256_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */ +#define M25P_MT25Q256_NSECTORS 512 +#define M25P_MT25Q256_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define M25P_MT25Q256_NPAGES 131072 +#define M25P_MT25Q256_SUBSECT_SHIFT 12 /* Sub-Sector size 1 << 12 = 4,096 */ + +/* MT25Q512 capacity is 67,108,864 bytes: + * (1024 sectors) * (65,536 bytes per sector) + * (262144 pages) * (256 bytes per page) + */ + +#define M25P_MT25Q512_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */ +#define M25P_MT25Q512_NSECTORS 1024 +#define M25P_MT25Q512_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define M25P_MT25Q512_NPAGES 262144 +#define M25P_MT25Q512_SUBSECT_SHIFT 12 /* Sub-Sector size 1 << 12 = 4,096 */ + +/* MT25Q1G capacity is 134,217,728 bytes: + * (2048 sectors) * (65,536 bytes per sector) + * (524288 pages) * (256 bytes per page) + */ + +#define M25P_MT25Q1G_SECTOR_SHIFT 16 /* Sector size 1 << 16 = 65,536 */ +#define M25P_MT25Q1G_NSECTORS 2048 +#define M25P_MT25Q1G_PAGE_SHIFT 8 /* Page size 1 << 8 = 256 */ +#define M25P_MT25Q1G_NPAGES 524288 +#define M25P_MT25Q1G_SUBSECT_SHIFT 12 /* Sub-Sector size 1 << 12 = 4,096 */ + +/* Instructions */ + +/* Command Value N Description Addr Dummy Data */ +#define M25P_WREN 0x06 /* 1 Write Enable 0 0 0 */ +#define M25P_WRDI 0x04 /* 1 Write Disable 0 0 0 */ +#define M25P_RDID 0x9f /* 1 Read Identification 0 0 1-3 */ +#define M25P_RDSR 0x05 /* 1 Read Status Register 0 0 >=1 */ +#define M25P_WRSR 0x01 /* 1 Write Status Register 0 0 1 */ +#define M25P_READ 0x03 /* 1 Read Data Bytes 3 0 >=1 */ +#define M25P_FAST_READ 0x0b /* 1 Higher speed read 3 1 >=1 */ +#define M25P_PP 0x02 /* 1 Page Program 3 0 1-256 */ +#define M25P_SE 0xd8 /* 1 Sector Erase 3 0 0 */ +#define M25P_BE 0xc7 /* 1 Bulk Erase 0 0 0 */ +#define M25P_DP 0xb9 /* 2 Deep power down 0 0 0 */ +#define M25P_RES 0xab /* 2 Read Electronic Signature 0 3 >=1 */ +#define M25P_SSE 0x20 /* 3 Sub-Sector Erase 0 0 0 */ +#define M25P_WECR 0x61 /* 1 Write Enhanched config 0 0 1 */ + +/* Quad commands */ +#define M25P_Q_FAST_RD 0x6b /* 1 Quad output fast read 3/4 0 1-256 */ +#define M25P_Q_FAST_PP 0x32 /* 1 Quad input fast program 3/4 0 1-256 */ +#define M25P_Q_ENTER 0x35 /* 1 Enter Quad input/output 0 0 0 */ + +/* NOTE 1: All parts. + * NOTE 2: M25P632/M25P64 + * NOTE 3: EN25F80. In EN25F80 terminology, 0xd8 is a block erase and 0x20 + * is a sector erase. + */ + +enum +{ + /* SPI instructions */ + + READ_ID, + READ_STATUS_REG, + WRITE_STATUS_REG, + WRITE_ENABLE, + ERASE_SECTOR, + ERASE_CHIP, + ENTER_DDR, + READ_FAST, + + /* Quad SPI instructions */ + + READ_FAST_QUAD_OUTPUT, + PAGE_PROGRAM_QUAD_INPUT, + ENTER_QPI, +}; + +/* TODO: Re-define commands if using other than M25 NOR */ + +static const uint32_t g_flexspi_nor_lut[][4] = +{ + [READ_ID] = + { + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_SDR, FLEXSPI_1PAD, M25P_RDID, + FLEXSPI_COMMAND_READ_SDR, FLEXSPI_1PAD, 0x04), + }, + + [READ_STATUS_REG] = + { + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_SDR, FLEXSPI_1PAD, M25P_RDSR, + FLEXSPI_COMMAND_READ_SDR, FLEXSPI_1PAD, 0x04), + }, + + [WRITE_STATUS_REG] = + { + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_SDR, FLEXSPI_1PAD, M25P_WRSR, + FLEXSPI_COMMAND_WRITE_SDR, FLEXSPI_1PAD, 0x04), + }, + + [WRITE_ENABLE] = + { + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_SDR, FLEXSPI_1PAD, M25P_WREN, + FLEXSPI_COMMAND_STOP, FLEXSPI_1PAD, 0), + }, + + [ERASE_SECTOR] = + { + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_SDR, FLEXSPI_1PAD, M25P_SSE, /* note: sub-sector erase */ + FLEXSPI_COMMAND_RADDR_SDR, FLEXSPI_1PAD, 0x18), + }, + + [ERASE_CHIP] = + { + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_SDR, FLEXSPI_1PAD, M25P_BE, + FLEXSPI_COMMAND_STOP, FLEXSPI_1PAD, 0), + }, + + [READ_FAST_QUAD_OUTPUT] = + { + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_SDR, FLEXSPI_1PAD, M25P_Q_FAST_RD, + FLEXSPI_COMMAND_RADDR_SDR, FLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_DUMMY_SDR, FLEXSPI_4PAD, 0x08, + FLEXSPI_COMMAND_READ_SDR, FLEXSPI_4PAD, 0x04), + }, + + [PAGE_PROGRAM_QUAD_INPUT] = + { + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_SDR, FLEXSPI_1PAD, M25P_Q_FAST_PP, + FLEXSPI_COMMAND_RADDR_SDR, FLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_WRITE_SDR, FLEXSPI_4PAD, 0x04, + FLEXSPI_COMMAND_STOP, FLEXSPI_1PAD, 0), + }, + + [ENTER_QPI] = + { + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_SDR, FLEXSPI_1PAD, M25P_Q_ENTER, + FLEXSPI_COMMAND_STOP, FLEXSPI_1PAD, 0), + }, + + [ENTER_DDR] = + { + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_SDR, FLEXSPI_1PAD, M25P_WECR, + FLEXSPI_COMMAND_WRITE_SDR, FLEXSPI_1PAD, 0x8), + }, + + [READ_FAST] = + { + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_SDR, FLEXSPI_1PAD, M25P_FAST_READ, + FLEXSPI_COMMAND_RADDR_SDR, FLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(FLEXSPI_COMMAND_DUMMY_SDR, FLEXSPI_1PAD, 0x08, + FLEXSPI_COMMAND_READ_SDR, FLEXSPI_1PAD, 0x04) + }, +}; + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* FlexSPI NOR device private data */ + +struct imx9_flexspi_nor_dev_s +{ + struct mtd_dev_s mtd; + struct flexspi_dev_s *flexspi; /* Saved FlexSPI interface instance */ + uint8_t *ahb_base; + enum flexspi_port_e port; + struct flexspi_device_config_s *config; + uint8_t sectorshift; /* 16 or 18 */ + uint8_t pageshift; /* 8 */ + uint16_t nsectors; /* 128 or 64 */ + uint32_t npages; /* 32,768 or 65,536 */ +#ifdef CONFIG_M25P_SUBSECTOR_ERASE + uint8_t subsectorshift; /* 0, 12 or 13 (4K or 8K) */ +#endif +}; + +/**************************************************************************** + * Private Functions Prototypes + ****************************************************************************/ + +/* MTD driver methods */ + +static int imx9_flexspi_nor_erase(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks); +static ssize_t imx9_flexspi_nor_read(struct mtd_dev_s *dev, + off_t offset, + size_t nbytes, + uint8_t *buffer); +static ssize_t imx9_flexspi_nor_bread(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + uint8_t *buffer); +static ssize_t imx9_flexspi_nor_bwrite(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + const uint8_t *buffer); +static int imx9_flexspi_nor_ioctl(struct mtd_dev_s *dev, + int cmd, + unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct flexspi_device_config_s g_flexspi_device_config = +{ + .flexspi_root_clk = 50000000, + .flash_size = 1024 * 64, /* size in kB */ + .cs_interval_unit = FLEXSPI_CS_INTERVAL_UNIT1_SCK_CYCLE, + .cs_interval = 0, + .cs_hold_time = 3, + .cs_setup_time = 3, + .data_valid_time = 0, + .columnspace = 0, + .enable_word_address = 0, + .awr_seq_index = 0, + .awr_seq_number = 0, + .ard_seq_index = READ_FAST_QUAD_OUTPUT, + .ard_seq_number = 1, + .ahb_write_wait_unit = FLEXSPI_AHB_WRITE_WAIT_UNIT2_AHB_CYCLE, + .ahb_write_wait_interval = 0 +}; + +static struct imx9_flexspi_nor_dev_s g_flexspi_nor = +{ + .mtd = + { + .erase = imx9_flexspi_nor_erase, + .bread = imx9_flexspi_nor_bread, + .bwrite = imx9_flexspi_nor_bwrite, + .read = imx9_flexspi_nor_read, + .ioctl = imx9_flexspi_nor_ioctl, +#ifdef CONFIG_MTD_BYTE_WRITE + .write = NULL, +#endif + .name = "imx9_flexspi_nor" + }, + .flexspi = (void *)0, + .ahb_base = (uint8_t *) CONFIG_FSPI_PER_BASEADDR, + .port = FLEXSPI_PORT_A1, + .config = &g_flexspi_device_config +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int imx9_flexspi_nor_get_id( + struct imx9_flexspi_nor_dev_s *priv) +{ + static uint32_t buffer = 0; + int stat; + + uint8_t manufacturer; + uint8_t memory; + uint8_t capacity; + + struct flexspi_transfer_s transfer = + { + .device_address = 0, + .port = priv->port, + .cmd_type = FLEXSPI_READ, + .seq_number = 1, + .seq_index = READ_ID, + .data = &buffer, + .data_size = 3, + }; + + stat = FLEXSPI_TRANSFER(priv->flexspi, &transfer); + if (stat != 0) + { + return -EIO; + } + + manufacturer = buffer; + memory = buffer >> 8; + capacity = buffer >> 16; + + /* Check for a valid manufacturer and memory type */ + + if (manufacturer == M25P_MANUFACTURER && memory == M25P_MEMORY_TYPE) + { + /* Okay.. is it a FLASH capacity that we understand? */ + +#ifdef CONFIG_M25P_SUBSECTOR_ERASE + priv->subsectorshift = 0; +#endif + + if (capacity == M25P_M25P1_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->sectorshift = M25P_M25P1_SECTOR_SHIFT; + priv->nsectors = M25P_M25P1_NSECTORS; + priv->pageshift = M25P_M25P1_PAGE_SHIFT; + priv->npages = M25P_M25P1_NPAGES; + return OK; + } + else if (capacity == M25P_EN25F80_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->pageshift = M25P_EN25F80_PAGE_SHIFT; + priv->npages = M25P_EN25F80_NPAGES; + priv->sectorshift = M25P_EN25F80_SECTOR_SHIFT; + priv->nsectors = M25P_EN25F80_NSECTORS; +#ifdef CONFIG_M25P_SUBSECTOR_ERASE + priv->subsectorshift = M25P_EN25F80_SUBSECT_SHIFT; +#endif + return OK; + } + else if (capacity == M25P_M25P16_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->sectorshift = M25P_M25P16_SECTOR_SHIFT; + priv->nsectors = M25P_M25P16_NSECTORS; + priv->pageshift = M25P_M25P16_PAGE_SHIFT; + priv->npages = M25P_M25P16_NPAGES; +#ifdef CONFIG_M25P_SUBSECTOR_ERASE + priv->subsectorshift = M25P_M25PX16_SUBSECT_SHIFT; +#endif + return OK; + } + else if (capacity == M25P_M25P32_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->sectorshift = M25P_M25P32_SECTOR_SHIFT; + priv->nsectors = M25P_M25P32_NSECTORS; + priv->pageshift = M25P_M25P32_PAGE_SHIFT; + priv->npages = M25P_M25P32_NPAGES; +#ifdef CONFIG_M25P_SUBSECTOR_ERASE + priv->subsectorshift = M25P_M25PX32_SUBSECT_SHIFT; +#endif + return OK; + } + else if (capacity == M25P_M25P64_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->sectorshift = M25P_M25P64_SECTOR_SHIFT; + priv->nsectors = M25P_M25P64_NSECTORS; + priv->pageshift = M25P_M25P64_PAGE_SHIFT; + priv->npages = M25P_M25P64_NPAGES; + return OK; + } + else if (capacity == M25P_M25P128_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->sectorshift = M25P_M25P128_SECTOR_SHIFT; + priv->nsectors = M25P_M25P128_NSECTORS; + priv->pageshift = M25P_M25P128_PAGE_SHIFT; + priv->npages = M25P_M25P128_NPAGES; + return OK; + } + } + else if (manufacturer == M25P_MANUFACTURER && + (memory == MT25Q_MEMORY_TYPE || memory == MT25QU_MEMORY_TYPE)) + { + /* Also okay.. is it a FLASH capacity that we understand? */ + +#ifdef CONFIG_M25P_SUBSECTOR_ERASE + priv->subsectorshift = 0; +#endif + if (capacity == M25P_MT25Q128_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->sectorshift = M25P_MT25Q128_SECTOR_SHIFT; + priv->nsectors = M25P_MT25Q128_NSECTORS; + priv->pageshift = M25P_MT25Q128_PAGE_SHIFT; + priv->npages = M25P_MT25Q128_NPAGES; +#ifdef CONFIG_M25P_SUBSECTOR_ERASE + priv->subsectorshift = M25P_MT25Q128_SUBSECT_SHIFT; +#endif + return OK; + } + else if (capacity == M25P_MT25Q256_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->sectorshift = M25P_MT25Q256_SECTOR_SHIFT; + priv->nsectors = M25P_MT25Q256_NSECTORS; + priv->pageshift = M25P_MT25Q256_PAGE_SHIFT; + priv->npages = M25P_MT25Q256_NPAGES; +#ifdef CONFIG_M25P_SUBSECTOR_ERASE + priv->subsectorshift = M25P_MT25Q256_SUBSECT_SHIFT; +#endif + return OK; + } + else if (capacity == M25P_MT25Q512_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->sectorshift = M25P_MT25Q512_SECTOR_SHIFT; + priv->nsectors = M25P_MT25Q512_NSECTORS; + priv->pageshift = M25P_MT25Q512_PAGE_SHIFT; + priv->npages = M25P_MT25Q512_NPAGES; +#ifdef CONFIG_M25P_SUBSECTOR_ERASE + priv->subsectorshift = M25P_MT25Q512_SUBSECT_SHIFT; +#endif + return OK; + } + else if (capacity == M25P_MT25Q1G_CAPACITY) + { + /* Save the FLASH geometry */ + + priv->sectorshift = M25P_MT25Q1G_SECTOR_SHIFT; + priv->nsectors = M25P_MT25Q1G_NSECTORS; + priv->pageshift = M25P_MT25Q1G_PAGE_SHIFT; + priv->npages = M25P_MT25Q1G_NPAGES; +#ifdef CONFIG_M25P_SUBSECTOR_ERASE + priv->subsectorshift = M25P_MT25Q1G_SUBSECT_SHIFT; +#endif + return OK; + } + } + + return -ENODEV; +} + +static int imx9_flexspi_nor_read_status( + const struct imx9_flexspi_nor_dev_s *dev, + uint32_t *status) +{ + int stat; + + struct flexspi_transfer_s transfer = + { + .device_address = 0, + .port = dev->port, + .cmd_type = FLEXSPI_READ, + .seq_number = 1, + .seq_index = READ_STATUS_REG, + .data = status, + .data_size = 1, + }; + + stat = FLEXSPI_TRANSFER(dev->flexspi, &transfer); + if (stat != 0) + { + return -EIO; + } + + return 0; +} + +static int imx9_flexspi_nor_write_status( + const struct imx9_flexspi_nor_dev_s *dev, + uint32_t *status) +{ + int stat; + + struct flexspi_transfer_s transfer = + { + .device_address = 0, + .port = dev->port, + .cmd_type = FLEXSPI_WRITE, + .seq_number = 1, + .seq_index = WRITE_STATUS_REG, + .data = status, + .data_size = 1, + }; + + stat = FLEXSPI_TRANSFER(dev->flexspi, &transfer); + if (stat != 0) + { + return -EIO; + } + + return 0; +} + +static int imx9_flexspi_nor_write_enable( + const struct imx9_flexspi_nor_dev_s *dev) +{ + int stat; + + struct flexspi_transfer_s transfer = + { + .device_address = 0, + .port = dev->port, + .cmd_type = FLEXSPI_COMMAND, + .seq_number = 1, + .seq_index = WRITE_ENABLE, + .data = NULL, + .data_size = 0, + }; + + stat = FLEXSPI_TRANSFER(dev->flexspi, &transfer); + if (stat != 0) + { + return -EIO; + } + + return 0; +} + +static int imx9_flexspi_nor_erase_sector( + const struct imx9_flexspi_nor_dev_s *dev, + off_t offset) +{ + int stat; + + struct flexspi_transfer_s transfer = + { + .device_address = offset, + .port = dev->port, + .cmd_type = FLEXSPI_COMMAND, + .seq_number = 1, + .seq_index = ERASE_SECTOR, + .data = NULL, + .data_size = 0, + }; + + stat = FLEXSPI_TRANSFER(dev->flexspi, &transfer); + if (stat != 0) + { + return -EIO; + } + + return 0; +} + +static int imx9_flexspi_nor_erase_chip( + const struct imx9_flexspi_nor_dev_s *dev) +{ + int stat; + + struct flexspi_transfer_s transfer = + { + .device_address = 0, + .port = dev->port, + .cmd_type = FLEXSPI_COMMAND, + .seq_number = 1, + .seq_index = ERASE_CHIP, + .data = NULL, + .data_size = 0, + }; + + stat = FLEXSPI_TRANSFER(dev->flexspi, &transfer); + if (stat != 0) + { + return -EIO; + } + + return 0; +} + +static int imx9_flexspi_nor_page_program( + const struct imx9_flexspi_nor_dev_s *dev, + off_t offset, + const void *buffer, + size_t len) +{ + int stat; + + struct flexspi_transfer_s transfer = + { + .device_address = offset, + .port = dev->port, + .cmd_type = FLEXSPI_WRITE, + .seq_number = 1, + .seq_index = PAGE_PROGRAM_QUAD_INPUT, + .data = (uint32_t *) buffer, + .data_size = len, + }; + + up_clean_dcache((uintptr_t)buffer, (uintptr_t)buffer + len); + + stat = FLEXSPI_TRANSFER(dev->flexspi, &transfer); + if (stat != 0) + { + return -EIO; + } + + return 0; +} + +static int imx9_flexspi_nor_wait_bus_busy( + const struct imx9_flexspi_nor_dev_s *dev) +{ + uint32_t status = 0; + int ret; + + do + { + ret = imx9_flexspi_nor_read_status(dev, &status); + if (ret) + { + return ret; + } + } + while (status & 1); + + return 0; +} + +static int imx9_flexspi_nor_enable_quad_mode( + const struct imx9_flexspi_nor_dev_s *dev) +{ + uint32_t status = 0x40; + + imx9_flexspi_nor_write_status(dev, &status); + imx9_flexspi_nor_wait_bus_busy(dev); + FLEXSPI_SOFTWARE_RESET(dev->flexspi); + + return 0; +} + +static ssize_t imx9_flexspi_nor_read(struct mtd_dev_s *dev, + off_t offset, + size_t nbytes, + uint8_t *buffer) +{ + struct imx9_flexspi_nor_dev_s *priv = + (struct imx9_flexspi_nor_dev_s *)dev; + uint8_t *src; + + finfo("offset: %08lx nbytes: %d\n", (long)offset, (int)nbytes); + + if (priv->port >= FLEXSPI_PORT_COUNT) + { + return -EIO; + } + + src = priv->ahb_base + offset; + DEBUGASSERT(((uintptr_t)src & ALIGN_MASK) == 0); + + up_invalidate_dcache((uintptr_t)src, + (uintptr_t)src + ALIGN_UP(nbytes)); + + memcpy(buffer, src, nbytes); + + finfo("return nbytes: %d\n", (int)nbytes); + return (ssize_t)nbytes; +} + +static ssize_t imx9_flexspi_nor_bread(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + uint8_t *buffer) +{ + struct imx9_flexspi_nor_dev_s *priv = + (struct imx9_flexspi_nor_dev_s *)dev; + ssize_t nbytes; + + finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); + + /* On this device, we can handle the block read just like the byte-oriented + * read + */ + + nbytes = imx9_flexspi_nor_read(dev, startblock << priv->pageshift, + nblocks << priv->pageshift, buffer); + if (nbytes > 0) + { + nbytes >>= priv->pageshift; + } + + return nbytes; +} + +static ssize_t imx9_flexspi_nor_bwrite(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + const uint8_t *src) +{ + struct imx9_flexspi_nor_dev_s *priv = + (struct imx9_flexspi_nor_dev_s *)dev; + size_t pgsize = 1 << priv->pageshift; + size_t len = nblocks << priv->pageshift; + off_t offset = startblock << priv->pageshift; + int i; + + finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); + + while (len) + { + i = MIN(pgsize, len); + imx9_flexspi_nor_write_enable(priv); + imx9_flexspi_nor_page_program(priv, offset, src, i); + imx9_flexspi_nor_wait_bus_busy(priv); + FLEXSPI_SOFTWARE_RESET(priv->flexspi); + offset += i; + src += i; + len -= i; + } + + return nblocks; +} + +static int imx9_flexspi_nor_erase(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks) +{ + struct imx9_flexspi_nor_dev_s *priv = + (struct imx9_flexspi_nor_dev_s *)dev; + size_t blocksleft = nblocks; + uint8_t *dst = priv->ahb_base + (startblock << priv->subsectorshift); + + finfo("startblock: %08lx nblocks: %d\n", (long)startblock, (int)nblocks); + + while (blocksleft-- > 0) + { + /* Erase each sector */ + + imx9_flexspi_nor_write_enable(priv); + imx9_flexspi_nor_erase_sector(priv, + startblock << priv->subsectorshift); + imx9_flexspi_nor_wait_bus_busy(priv); + FLEXSPI_SOFTWARE_RESET(priv->flexspi); + startblock++; + } + + up_invalidate_dcache((uintptr_t)dst, + (uintptr_t)dst + (nblocks << priv->subsectorshift)); + + return (int)nblocks; +} + +static int imx9_flexspi_nor_ioctl(struct mtd_dev_s *dev, + int cmd, + unsigned long arg) +{ + struct imx9_flexspi_nor_dev_s *priv = + (struct imx9_flexspi_nor_dev_s *)dev; + int ret = -EINVAL; /* Assume good command with bad parameters */ + + switch (cmd) + { + case MTDIOC_GEOMETRY: + { + struct mtd_geometry_s *geo = + (struct mtd_geometry_s *)((uintptr_t)arg); + if (geo) + { + memset(geo, 0, sizeof(*geo)); + + /* Populate the geometry structure with information need to + * know the capacity and how to access the device. + * + * NOTE: + * that the device is treated as though it where just an array + * of fixed size blocks. That is most likely not true, but the + * client will expect the device logic to do whatever is + * necessary to make it appear so. + */ + + geo->blocksize = (1 << priv->pageshift); +#ifdef CONFIG_M25P_SUBSECTOR_ERASE + if (priv->subsectorshift > 0) + { + geo->erasesize = (1 << priv->subsectorshift); + geo->neraseblocks = priv->nsectors * + (1 << (priv->sectorshift - + priv->subsectorshift)); + } + else +#endif + { + geo->erasesize = (1 << priv->sectorshift); + geo->neraseblocks = priv->nsectors; + } + + ret = OK; + + finfo("blocksize: %u erasesize: %u neraseblocks: %u\n", + geo->blocksize, geo->erasesize, geo->neraseblocks); + } + } + break; + + case BIOC_PARTINFO: + + break; + + case MTDIOC_BULKERASE: + { + /* Erase the entire device */ + + imx9_flexspi_nor_write_enable(priv); + ret = imx9_flexspi_nor_erase_chip(priv); + if (ret) + { + ferr("bulk erase failed\n"); + } + + imx9_flexspi_nor_wait_bus_busy(priv); + FLEXSPI_SOFTWARE_RESET(priv->flexspi); + } + break; + + case MTDIOC_PROTECT: + + /* TODO */ + + break; + + case MTDIOC_UNPROTECT: + + /* TODO */ + + break; + + default: + ret = -ENOTTY; /* Bad/unsupported command */ + break; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_flexspi_nor_initialize + * + * Description: + * Initialize a NOR FLASH on FlexSPI interface + * + * Input Parameters: + * None + * + * Returned Value: + * Pointer to an mtd device, Null on any error + * + ****************************************************************************/ + +struct mtd_dev_s *imx9_flexspi_nor_initialize(int intf) +{ + /* Configure multiplexed pins as connected on the board */ + + imx9_iomux_configure(MUX_FLEXSPI_IO0); + imx9_iomux_configure(MUX_FLEXSPI_IO1); + imx9_iomux_configure(MUX_FLEXSPI_IO2); + imx9_iomux_configure(MUX_FLEXSPI_IO3); + imx9_iomux_configure(MUX_FLEXSPI_CMD); + imx9_iomux_configure(MUX_FLEXSPI_CLK); + + g_flexspi_nor.flexspi = imx9_flexspi_initialize(intf); + if (!g_flexspi_nor.flexspi) + { + return NULL; + } + + FLEXSPI_SET_DEVICE_CONFIG(g_flexspi_nor.flexspi, + g_flexspi_nor.config, + g_flexspi_nor.port); + FLEXSPI_UPDATE_LUT(g_flexspi_nor.flexspi, + 0, + (const uint32_t *)g_flexspi_nor_lut, + sizeof(g_flexspi_nor_lut) / 4); + FLEXSPI_SOFTWARE_RESET(g_flexspi_nor.flexspi); + + if (imx9_flexspi_nor_get_id(&g_flexspi_nor)) + { + return NULL; + } + + if (imx9_flexspi_nor_enable_quad_mode(&g_flexspi_nor)) + { + return NULL; + } + + return &g_flexspi_nor.mtd; +} + +#endif /* CONFIG_IMX9_FLEXSPI_NOR */ diff --git a/arch/arm64/src/imx9/imx9_flexspi_nor.h b/arch/arm64/src/imx9/imx9_flexspi_nor.h new file mode 100644 index 0000000000000..71f8d31ac46cf --- /dev/null +++ b/arch/arm64/src/imx9/imx9_flexspi_nor.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_flexspi_nor.h + * + * 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_ARM64_SRC_IMX9_IMX9_FLEXSPI_NOR_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_FLEXSPI_NOR_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifdef CONFIG_IMX9_FLEXSPI_NOR + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_flexspi_nor_initialize + * + * Description: + * Initialize a NOR FLASH on FlexSPI interface + * + * Input Parameters: + * intf: FlexSPI interface number + * + * Returned Value: + * Pointer to an mtd device, NULL on any error + * + ****************************************************************************/ + +struct mtd_dev_s *imx9_flexspi_nor_initialize(int intf); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_IMX9_FLEXSPI_NOR */ +#endif /* __ARCH_ARM_SRC_IMX9_IMX9_FLEXSPI_NOR_H */