diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index 3f012563c9bbc..0370495e9780b 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -246,6 +246,15 @@ endmenu # LPUART Configuration endmenu # LPUART +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 bool "Enable FLEXIO1 based PWM generation" diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs index 38466ba3704aa..89e12744d997e 100644 --- a/arch/arm64/src/imx9/Make.defs +++ b/arch/arm64/src/imx9/Make.defs @@ -67,3 +67,11 @@ endif ifeq ($(CONFIG_IMX9_USDHC),y) CHIP_CSRCS += imx9_usdhc.c 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/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 */ 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 */