diff --git a/boards/arm/mimxrt685_evk/Kconfig.defconfig b/boards/arm/mimxrt685_evk/Kconfig.defconfig index 378320fb1ce36..7708c7a7168c8 100644 --- a/boards/arm/mimxrt685_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt685_evk/Kconfig.defconfig @@ -14,6 +14,16 @@ config XTAL_SYS_CLK_HZ config SYSOSC_SETTLING_US default 260 +config FLASH_MCUX_FLEXSPI_MX25UM51345G + default y if FLASH + +config FLASH_MCUX_FLEXSPI_XIP + default y if FLASH + +choice FLASH_MCUX_FLEXSPI_XIP_MEM_TARGET + default FLASH_MCUX_FLEXSPI_XIP_MEM_SRAM +endchoice + if GPIO_MCUX_LPC config GPIO_MCUX_LPC_PORT0 diff --git a/boards/arm/mimxrt685_evk/doc/index.rst b/boards/arm/mimxrt685_evk/doc/index.rst index 5f728f37c39c6..a6c186138b39c 100644 --- a/boards/arm/mimxrt685_evk/doc/index.rst +++ b/boards/arm/mimxrt685_evk/doc/index.rst @@ -71,6 +71,8 @@ features: +-----------+------------+-------------------------------------+ | GPIO | on-chip | gpio | +-----------+------------+-------------------------------------+ +| FLASH | on-chip | OctalSPI Flash | ++-----------+------------+-------------------------------------+ | USART | on-chip | serial port-polling | +-----------+------------+-------------------------------------+ | I2C | on-chip | i2c | @@ -127,6 +129,28 @@ functionality of a pin. +---------+-----------------+----------------------------+ | PIO0_9 | I2S | I2S DATAIN | +---------+-----------------+----------------------------+ +| PIO1_11 | FLEXSPI0B_DATA0 | OctalSPI Flash | ++---------+-----------------+----------------------------+ +| PIO1_12 | FLEXSPI0B_DATA1 | OctalSPI Flash | ++---------+-----------------+----------------------------+ +| PIO1_13 | FLEXSPI0B_DATA2 | OctalSPI Flash | ++---------+-----------------+----------------------------+ +| PIO1_14 | FLEXSPI0B_DATA3 | OctalSPI Flash | ++---------+-----------------+----------------------------+ +| PIO1_29 | FLEXSPI0B_SCLK | OctalSPI Flash | ++---------+-----------------+----------------------------+ +| PIO2_12 | PIO2_12 | OctalSPI Flash | ++---------+-----------------+----------------------------+ +| PIO2_17 | FLEXSPI0B_DATA4 | OctalSPI Flash | ++---------+-----------------+----------------------------+ +| PIO2_18 | FLEXSPI0B_DATA5 | OctalSPI Flash | ++---------+-----------------+----------------------------+ +| PIO2_19 | FLEXSPI0B_SS0_N | OctalSPI Flash | ++---------+-----------------+----------------------------+ +| PIO2_22 | FLEXSPI0B_DATA6 | OctalSPI Flash | ++---------+-----------------+----------------------------+ +| PIO2_23 | FLEXSPI0B_DATA7 | OctalSPI Flash | ++---------+-----------------+----------------------------+ System Clock ============ diff --git a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts index 08ea139bdf751..cb469b976e1c6 100644 --- a/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts +++ b/boards/arm/mimxrt685_evk/mimxrt685_evk_cm33.dts @@ -170,6 +170,30 @@ i2s1: &flexcomm3 { dma-names = "tx"; }; +&flexspi { + reg = <0x50134000 0x4000>, <0x18000000 DT_SIZE_M(64)>; + mx25um51345g: mx25um51345g@2 { + compatible = "nxp,imx-flexspi-mx25um51345g"; + size = <536870912>; + label = "MX25UM51345G"; + reg = <2>; + spi-max-frequency = <200000000>; + status = "okay"; + jedec-id = [c2 81 3a]; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + storage_partition: partition@3f00000 { + label = "storage"; + reg = <0x03f00000 DT_SIZE_M(1)>; + }; + }; + }; +}; + &gpio0 { status = "okay"; }; diff --git a/boards/arm/mimxrt685_evk/pinmux.c b/boards/arm/mimxrt685_evk/pinmux.c index 2aa6d71321435..79373d268ee6f 100644 --- a/boards/arm/mimxrt685_evk/pinmux.c +++ b/boards/arm/mimxrt685_evk/pinmux.c @@ -396,6 +396,239 @@ static int mimxrt685_evk_pinmux_init(const struct device *dev) /* PORT0 PIN9 (coords: L3) is configured as FC1_RXD_SDA_MOSI_DATA */ IOPCTL_PinMuxSet(IOPCTL, 0U, 9U, port0_pin9_config); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(flexspi), okay) && CONFIG_FLASH +const uint32_t port1_pin11_config = (/* Pin is configured as FLEXSPI0B_DATA0 */ + IOPCTL_PIO_FUNC6 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Full drive enable */ + IOPCTL_PIO_FULLDRIVE_EN | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); +/* PORT1 PIN11 (coords: L2) is configured as FLEXSPI0B_DATA0 */ +IOPCTL_PinMuxSet(IOPCTL, 1U, 11U, port1_pin11_config); + +const uint32_t port1_pin12_config = (/* Pin is configured as FLEXSPI0B_DATA1 */ + IOPCTL_PIO_FUNC6 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Full drive enable */ + IOPCTL_PIO_FULLDRIVE_EN | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); +/* PORT1 PIN12 (coords: M2) is configured as FLEXSPI0B_DATA1 */ +IOPCTL_PinMuxSet(IOPCTL, 1U, 12U, port1_pin12_config); + +const uint32_t port1_pin13_config = (/* Pin is configured as FLEXSPI0B_DATA2 */ + IOPCTL_PIO_FUNC6 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Full drive enable */ + IOPCTL_PIO_FULLDRIVE_EN | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); +/* PORT1 PIN13 (coords: N1) is configured as FLEXSPI0B_DATA2 */ +IOPCTL_PinMuxSet(IOPCTL, 1U, 13U, port1_pin13_config); + +const uint32_t port1_pin14_config = (/* Pin is configured as FLEXSPI0B_DATA3 */ + IOPCTL_PIO_FUNC6 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Full drive enable */ + IOPCTL_PIO_FULLDRIVE_EN | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); +/* PORT1 PIN14 (coords: N2) is configured as FLEXSPI0B_DATA3 */ +IOPCTL_PinMuxSet(IOPCTL, 1U, 14U, port1_pin14_config); + +const uint32_t port1_pin29_config = (/* Pin is configured as FLEXSPI0B_SCLK */ + IOPCTL_PIO_FUNC5 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Full drive enable */ + IOPCTL_PIO_FULLDRIVE_EN | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); +/* PORT1 PIN29 (coords: U3) is configured as FLEXSPI0B_SCLK */ +IOPCTL_PinMuxSet(IOPCTL, 1U, 29U, port1_pin29_config); + +const uint32_t port2_pin12_config = (/* Pin is configured as PIO2_12 */ + IOPCTL_PIO_FUNC0 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Disable input buffer function */ + IOPCTL_PIO_INBUF_DI | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Normal drive */ + IOPCTL_PIO_FULLDRIVE_DI | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); +/* PORT2 PIN12 (coords: T3) is configured as PIO2_12 */ +IOPCTL_PinMuxSet(IOPCTL, 2U, 12U, port2_pin12_config); + +const uint32_t port2_pin17_config = (/* Pin is configured as FLEXSPI0B_DATA4 */ + IOPCTL_PIO_FUNC6 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Full drive enable */ + IOPCTL_PIO_FULLDRIVE_EN | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); +/* PORT2 PIN17 (coords: U1) is configured as FLEXSPI0B_DATA4 */ +IOPCTL_PinMuxSet(IOPCTL, 2U, 17U, port2_pin17_config); + +const uint32_t port2_pin18_config = (/* Pin is configured as FLEXSPI0B_DATA5 */ + IOPCTL_PIO_FUNC6 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Full drive enable */ + IOPCTL_PIO_FULLDRIVE_EN | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); +/* PORT2 PIN18 (coords: R2) is configured as FLEXSPI0B_DATA5 */ +IOPCTL_PinMuxSet(IOPCTL, 2U, 18U, port2_pin18_config); + +const uint32_t port2_pin19_config = (/* Pin is configured as FLEXSPI0B_SS0_N */ + IOPCTL_PIO_FUNC6 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Full drive enable */ + IOPCTL_PIO_FULLDRIVE_EN | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); +/* PORT2 PIN19 (coords: T2) is configured as FLEXSPI0B_SS0_N */ +IOPCTL_PinMuxSet(IOPCTL, 2U, 19U, port2_pin19_config); + +const uint32_t port2_pin22_config = (/* Pin is configured as FLEXSPI0B_DATA6 */ + IOPCTL_PIO_FUNC6 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Full drive enable */ + IOPCTL_PIO_FULLDRIVE_EN | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); +/* PORT2 PIN22 (coords: P3) is configured as FLEXSPI0B_DATA6 */ +IOPCTL_PinMuxSet(IOPCTL, 2U, 22U, port2_pin22_config); + +const uint32_t port2_pin23_config = (/* Pin is configured as FLEXSPI0B_DATA7 */ + IOPCTL_PIO_FUNC6 | + /* Disable pull-up / pull-down function */ + IOPCTL_PIO_PUPD_DI | + /* Enable pull-down function */ + IOPCTL_PIO_PULLDOWN_EN | + /* Enables input buffer function */ + IOPCTL_PIO_INBUF_EN | + /* Normal mode */ + IOPCTL_PIO_SLEW_RATE_NORMAL | + /* Full drive enable */ + IOPCTL_PIO_FULLDRIVE_EN | + /* Analog mux is disabled */ + IOPCTL_PIO_ANAMUX_DI | + /* Pseudo Output Drain is disabled */ + IOPCTL_PIO_PSEDRAIN_DI | + /* Input function is not inverted */ + IOPCTL_PIO_INV_DI); +/* PORT2 PIN23 (coords: P5) is configured as FLEXSPI0B_DATA7 */ +IOPCTL_PinMuxSet(IOPCTL, 2U, 23U, port2_pin23_config); #endif return 0; diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 44681b4d77105..42d303e08f13d 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -18,11 +18,16 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NIOS2_QSPI soc_flash_nios2_qspi.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_GECKO flash_gecko.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_RV32M1 soc_flash_rv32m1.c) zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_QSPI flash_stm32_qspi.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_MX25UM51345G flash_mcux_flexspi_mx25um51345g.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_NOR flash_mcux_flexspi_nor.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ESP32 flash_esp32.c) if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) - zephyr_code_relocate(flash_mcux_flexspi_nor.c ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) + if(CONFIG_FLASH_MCUX_FLEXSPI_MX25UM51345G) + zephyr_code_relocate(flash_mcux_flexspi_mx25um51345g.c ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) + else() + zephyr_code_relocate(flash_mcux_flexspi_nor.c ${CONFIG_FLASH_MCUX_FLEXSPI_XIP_MEM}_TEXT) + endif() endif() if(CONFIG_SOC_FLASH_STM32) @@ -46,6 +51,11 @@ zephyr_include_directories_ifdef( ${ZEPHYR_BASE}/drivers/memc ) +zephyr_include_directories_ifdef( + CONFIG_FLASH_MCUX_FLEXSPI_MX25UM51345G + ${ZEPHYR_BASE}/drivers/memc +) + zephyr_include_directories_ifdef( CONFIG_SOC_FLASH_NRF_RADIO_SYNC_TICKER ${ZEPHYR_BASE}/subsys/bluetooth diff --git a/drivers/flash/Kconfig.mcux b/drivers/flash/Kconfig.mcux index 88a3491c2e076..37986f57352cb 100644 --- a/drivers/flash/Kconfig.mcux +++ b/drivers/flash/Kconfig.mcux @@ -34,10 +34,17 @@ config FLASH_MCUX_FLEXSPI_NOR select MEMC select MEMC_MCUX_FLEXSPI +config FLASH_MCUX_FLEXSPI_MX25UM51345G + bool "MCUX FlexSPI MX25UM51345G driver" + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_DRIVER_ENABLED + select MEMC + select MEMC_MCUX_FLEXSPI + config FLASH_MCUX_FLEXSPI_NOR_WRITE_BUFFER bool "MCUX FlexSPI NOR write RAM buffer" default y - depends on FLASH_MCUX_FLEXSPI_NOR + depends on (FLASH_MCUX_FLEXSPI_NOR || FLASH_MCUX_FLEXSPI_MX25UM51345G) help Copy the data to a RAM buffer before writing it to the flash. This prevents faults when the data to write would be located on the @@ -46,7 +53,7 @@ config FLASH_MCUX_FLEXSPI_NOR_WRITE_BUFFER config FLASH_MCUX_FLEXSPI_XIP bool "MCUX FlexSPI flash access with xip" depends on MEMC_MCUX_FLEXSPI - depends on (CODE_FLEXSPI || CODE_FLEXSPI2) + depends on (CODE_FLEXSPI || CODE_FLEXSPI2 || SOC_SERIES_IMX_RT6XX) select XIP help Allows using the flash API while running in XIP. diff --git a/drivers/flash/flash_mcux_flexspi_mx25um51345g.c b/drivers/flash/flash_mcux_flexspi_mx25um51345g.c new file mode 100644 index 0000000000000..398ff85832a15 --- /dev/null +++ b/drivers/flash/flash_mcux_flexspi_mx25um51345g.c @@ -0,0 +1,551 @@ +/* + * Copyright 2021 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_imx_flexspi_mx25um51345g + +#include +#include +#include +#include "spi_nor.h" +#include "memc_mcux_flexspi.h" + +#ifdef CONFIG_HAS_MCUX_CACHE +#include +#endif + +#define NOR_WRITE_SIZE 1 +#define NOR_ERASE_VALUE 0xff + +#ifdef CONFIG_FLASH_MCUX_FLEXSPI_NOR_WRITE_BUFFER +static uint8_t nor_write_buf[SPI_NOR_PAGE_SIZE]; +#endif + +LOG_MODULE_REGISTER(flash_flexspi_nor, CONFIG_FLASH_LOG_LEVEL); + +enum { + /* Instructions matching with XIP layout */ + READ, + WRITE_ENABLE_OPI, + WRITE_ENABLE, + ERASE_SECTOR, + PAGE_PROGRAM_INPUT, + PAGE_PROGRAM, + READ_ID_OPI, + ENTER_OPI, + READ_STATUS_REG, + ERASE_CHIP, +}; + +struct flash_flexspi_nor_config { + char *controller_label; + flexspi_port_t port; + flexspi_device_config_t config; + struct flash_pages_layout layout; + struct flash_parameters flash_parameters; +}; + +struct flash_flexspi_nor_data { + const struct device *controller; +}; + +static const uint32_t flash_flexspi_nor_lut[][4] = { + [READ_ID_OPI] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x9F, + kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x60), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x20, + kFLEXSPI_Command_DUMMY_DDR, kFLEXSPI_8PAD, 0x16), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0), + }, + + [READ_STATUS_REG] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0x05, + kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0xFA), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_8PAD, 0x20, + kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_8PAD, 0x14), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_8PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0), + }, + + [WRITE_ENABLE] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x06, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + }, + + [WRITE_ENABLE_OPI] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0x06, + kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0xF9), + }, + + [ERASE_SECTOR] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0x21, + kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0xDE), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_8PAD, 0x20, + kFLEXSPI_Command_STOP, kFLEXSPI_8PAD, 0), + }, + + [ERASE_CHIP] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0x60, + kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0x9F), + }, + + [READ] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0xEC, + kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0x13), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_8PAD, 0x20, + kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_8PAD, 0x14), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_8PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x0), + }, + + [PAGE_PROGRAM] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0x12, + kFLEXSPI_Command_SDR, kFLEXSPI_8PAD, 0xED), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_8PAD, 0x20, + kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_8PAD, 0x04), + }, + + [ENTER_OPI] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x72, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x20), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_1PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + }, + +}; + +static int flash_flexspi_nor_get_vendor_id(const struct device *dev, + uint8_t *vendor_id) +{ + const struct flash_flexspi_nor_config *config = dev->config; + struct flash_flexspi_nor_data *data = dev->data; + uint32_t buffer = 0; + int ret; + + flexspi_transfer_t transfer = { + .deviceAddress = 0, + .port = config->port, + .cmdType = kFLEXSPI_Read, + .SeqNumber = 1, + .seqIndex = READ_ID_OPI, + .data = &buffer, + .dataSize = 1, + }; + + LOG_DBG("Reading id"); + + ret = memc_flexspi_transfer(data->controller, &transfer); + *vendor_id = buffer; + + return ret; +} + +static int flash_flexspi_nor_read_status(const struct device *dev, + uint32_t *status) +{ + const struct flash_flexspi_nor_config *config = dev->config; + struct flash_flexspi_nor_data *data = dev->data; + + flexspi_transfer_t transfer = { + .deviceAddress = 0, + .port = config->port, + .cmdType = kFLEXSPI_Read, + .SeqNumber = 1, + .seqIndex = READ_STATUS_REG, + .data = status, + .dataSize = 1, + }; + + LOG_DBG("Reading status register"); + + return memc_flexspi_transfer(data->controller, &transfer); +} + +static int flash_flexspi_nor_write_status(const struct device *dev, + uint32_t *status) +{ + const struct flash_flexspi_nor_config *config = dev->config; + struct flash_flexspi_nor_data *data = dev->data; + + flexspi_transfer_t transfer = { + .deviceAddress = 0, + .port = config->port, + .cmdType = kFLEXSPI_Write, + .SeqNumber = 1, + .seqIndex = ENTER_OPI, + .data = status, + .dataSize = 1, + }; + + LOG_DBG("Writing status register"); + + return memc_flexspi_transfer(data->controller, &transfer); +} + +static int flash_flexspi_nor_write_enable(const struct device *dev, + bool enableOctal) +{ + const struct flash_flexspi_nor_config *config = dev->config; + struct flash_flexspi_nor_data *data = dev->data; + flexspi_transfer_t transfer; + + transfer.deviceAddress = 0; + transfer.port = config->port; + transfer.cmdType = kFLEXSPI_Command; + transfer.SeqNumber = 1; + if (enableOctal) { + transfer.seqIndex = WRITE_ENABLE_OPI; + } else { + transfer.seqIndex = WRITE_ENABLE; + } + transfer.data = NULL; + transfer.dataSize = 0; + + LOG_DBG("Enabling write"); + + return memc_flexspi_transfer(data->controller, &transfer); +} + +static int flash_flexspi_nor_erase_sector(const struct device *dev, + off_t offset) +{ + const struct flash_flexspi_nor_config *config = dev->config; + struct flash_flexspi_nor_data *data = dev->data; + + flexspi_transfer_t transfer = { + .deviceAddress = offset, + .port = config->port, + .cmdType = kFLEXSPI_Command, + .SeqNumber = 1, + .seqIndex = ERASE_SECTOR, + .data = NULL, + .dataSize = 0, + }; + + LOG_DBG("Erasing sector at 0x%08x", offset); + + return memc_flexspi_transfer(data->controller, &transfer); +} + +static int flash_flexspi_nor_erase_chip(const struct device *dev) +{ + const struct flash_flexspi_nor_config *config = dev->config; + struct flash_flexspi_nor_data *data = dev->data; + + flexspi_transfer_t transfer = { + .deviceAddress = 0, + .port = config->port, + .cmdType = kFLEXSPI_Command, + .SeqNumber = 1, + .seqIndex = ERASE_CHIP, + .data = NULL, + .dataSize = 0, + }; + + LOG_DBG("Erasing chip"); + + return memc_flexspi_transfer(data->controller, &transfer); +} + +static int flash_flexspi_nor_page_program(const struct device *dev, + off_t offset, const void *buffer, size_t len) +{ + const struct flash_flexspi_nor_config *config = dev->config; + struct flash_flexspi_nor_data *data = dev->data; + + flexspi_transfer_t transfer = { + .deviceAddress = offset, + .port = config->port, + .cmdType = kFLEXSPI_Write, + .SeqNumber = 1, + .seqIndex = PAGE_PROGRAM, + .data = (uint32_t *) buffer, + .dataSize = len, + }; + + LOG_DBG("Page programming %d bytes to 0x%08x", len, offset); + + return memc_flexspi_transfer(data->controller, &transfer); +} + +static int flash_flexspi_nor_wait_bus_busy(const struct device *dev) +{ + uint32_t status = 0; + int ret; + + do { + ret = flash_flexspi_nor_read_status(dev, &status); + LOG_DBG("status: 0x%x", status); + if (ret) { + LOG_ERR("Could not read status"); + return ret; + } + } while (status & BIT(0)); + + return 0; +} + +static int flash_flexspi_enable_octal_mode(const struct device *dev) +{ + struct flash_flexspi_nor_data *data = dev->data; + /* FLASH_ENABLE_OCTAL_CMD: (01 = STR OPI Enable) */ + uint32_t status = 0x01; + + flash_flexspi_nor_write_enable(dev, false); + flash_flexspi_nor_write_status(dev, &status); + flash_flexspi_nor_wait_bus_busy(dev); + memc_flexspi_reset(data->controller); + + return 0; +} + +static int flash_flexspi_nor_read(const struct device *dev, off_t offset, + void *buffer, size_t len) +{ + const struct flash_flexspi_nor_config *config = dev->config; + struct flash_flexspi_nor_data *data = dev->data; + uint8_t *src = memc_flexspi_get_ahb_address(data->controller, + config->port, + offset); + + memcpy(buffer, src, len); + + return 0; +} + +static int flash_flexspi_nor_write(const struct device *dev, off_t offset, + const void *buffer, size_t len) +{ + const struct flash_flexspi_nor_config *config = dev->config; + struct flash_flexspi_nor_data *data = dev->data; + size_t size = len; + uint8_t *src = (uint8_t *) buffer; + int i; + unsigned int key = 0; + + uint8_t *dst = memc_flexspi_get_ahb_address(data->controller, + config->port, + offset); + + if (memc_flexspi_is_running_xip(data->controller)) { + key = irq_lock(); + } + + while (len) { + i = MIN(SPI_NOR_PAGE_SIZE, len); +#ifdef CONFIG_FLASH_MCUX_FLEXSPI_NOR_WRITE_BUFFER + memcpy(nor_write_buf, src, i); +#endif + flash_flexspi_nor_write_enable(dev, true); +#ifdef CONFIG_FLASH_MCUX_FLEXSPI_NOR_WRITE_BUFFER + flash_flexspi_nor_page_program(dev, offset, nor_write_buf, i); +#else + flash_flexspi_nor_page_program(dev, offset, src, i); +#endif + flash_flexspi_nor_wait_bus_busy(dev); + memc_flexspi_reset(data->controller); + src += i; + offset += i; + len -= i; + } + + if (memc_flexspi_is_running_xip(data->controller)) { + irq_unlock(key); + } + +#ifdef CONFIG_HAS_MCUX_CACHE + DCACHE_InvalidateByRange((uint32_t) dst, size); +#endif + + return 0; +} + +static int flash_flexspi_nor_erase(const struct device *dev, off_t offset, + size_t size) +{ + const struct flash_flexspi_nor_config *config = dev->config; + struct flash_flexspi_nor_data *data = dev->data; + int num_sectors = size / SPI_NOR_SECTOR_SIZE; + int i; + unsigned int key = 0; + + uint8_t *dst = memc_flexspi_get_ahb_address(data->controller, + config->port, + offset); + + if (offset % SPI_NOR_SECTOR_SIZE) { + LOG_ERR("Invalid offset"); + return -EINVAL; + } + + if (size % SPI_NOR_SECTOR_SIZE) { + LOG_ERR("Invalid size"); + return -EINVAL; + } + + if (memc_flexspi_is_running_xip(data->controller)) { + key = irq_lock(); + } + + if ((offset == 0) && (size == config->config.flashSize * KB(1))) { + flash_flexspi_nor_write_enable(dev, true); + flash_flexspi_nor_erase_chip(dev); + flash_flexspi_nor_wait_bus_busy(dev); + memc_flexspi_reset(data->controller); + } else { + for (i = 0; i < num_sectors; i++) { + flash_flexspi_nor_write_enable(dev, true); + flash_flexspi_nor_erase_sector(dev, offset); + flash_flexspi_nor_wait_bus_busy(dev); + memc_flexspi_reset(data->controller); + offset += SPI_NOR_SECTOR_SIZE; + } + } + + if (memc_flexspi_is_running_xip(data->controller)) { + irq_unlock(key); + } + +#ifdef CONFIG_HAS_MCUX_CACHE + DCACHE_InvalidateByRange((uint32_t) dst, size); +#endif + + return 0; +} + +static const struct flash_parameters *flash_flexspi_nor_get_parameters( + const struct device *dev) +{ + const struct flash_flexspi_nor_config *config = dev->config; + + return &config->flash_parameters; +} + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static void flash_flexspi_nor_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, size_t *layout_size) +{ + const struct flash_flexspi_nor_config *config = dev->config; + + *layout = &config->layout; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +static int flash_flexspi_nor_init(const struct device *dev) +{ + const struct flash_flexspi_nor_config *config = dev->config; + struct flash_flexspi_nor_data *data = dev->data; + uint8_t vendor_id; + + data->controller = device_get_binding(config->controller_label); + if (data->controller == NULL) { + LOG_ERR("Could not find controller"); + return -EINVAL; + } + + if (!memc_flexspi_is_running_xip(data->controller) && + memc_flexspi_set_device_config(data->controller, &config->config, + config->port)) { + LOG_ERR("Could not set device configuration"); + return -EINVAL; + } + + if (memc_flexspi_update_lut(data->controller, 0, + (const uint32_t *) flash_flexspi_nor_lut, + sizeof(flash_flexspi_nor_lut) / 4)) { + LOG_ERR("Could not update lut"); + return -EINVAL; + } + + memc_flexspi_reset(data->controller); + + if (flash_flexspi_enable_octal_mode(dev)) { + LOG_ERR("Could not enable octal mode"); + return -EIO; + } + + if (flash_flexspi_nor_get_vendor_id(dev, &vendor_id)) { + LOG_ERR("Could not read vendor id"); + return -EIO; + } + LOG_DBG("Vendor id: 0x%0x", vendor_id); + + return 0; +} + +static const struct flash_driver_api flash_flexspi_nor_api = { + .erase = flash_flexspi_nor_erase, + .write = flash_flexspi_nor_write, + .read = flash_flexspi_nor_read, + .get_parameters = flash_flexspi_nor_get_parameters, +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = flash_flexspi_nor_pages_layout, +#endif +}; + +#define CONCAT3(x, y, z) x ## y ## z + +#define CS_INTERVAL_UNIT(unit) \ + CONCAT3(kFLEXSPI_CsIntervalUnit, unit, SckCycle) + +#define AHB_WRITE_WAIT_UNIT(unit) \ + CONCAT3(kFLEXSPI_AhbWriteWaitUnit, unit, AhbCycle) + +#define FLASH_FLEXSPI_DEVICE_CONFIG(n) \ + { \ + .flexspiRootClk = MHZ(120), \ + .flashSize = DT_INST_PROP(n, size) / 8 / KB(1), \ + .CSIntervalUnit = \ + CS_INTERVAL_UNIT( \ + DT_INST_PROP(n, cs_interval_unit)), \ + .CSInterval = DT_INST_PROP(n, cs_interval), \ + .CSHoldTime = DT_INST_PROP(n, cs_hold_time), \ + .CSSetupTime = DT_INST_PROP(n, cs_setup_time), \ + .dataValidTime = DT_INST_PROP(n, data_valid_time), \ + .columnspace = DT_INST_PROP(n, column_space), \ + .enableWordAddress = DT_INST_PROP(n, word_addressable), \ + .AWRSeqIndex = 0, \ + .AWRSeqNumber = 0, \ + .ARDSeqIndex = READ, \ + .ARDSeqNumber = 1, \ + .AHBWriteWaitUnit = \ + AHB_WRITE_WAIT_UNIT( \ + DT_INST_PROP(n, ahb_write_wait_unit)), \ + .AHBWriteWaitInterval = \ + DT_INST_PROP(n, ahb_write_wait_interval), \ + } \ + +#define FLASH_FLEXSPI_NOR(n) \ + static const struct flash_flexspi_nor_config \ + flash_flexspi_nor_config_##n = { \ + .controller_label = DT_INST_BUS_LABEL(n), \ + .port = DT_INST_REG_ADDR(n), \ + .config = FLASH_FLEXSPI_DEVICE_CONFIG(n), \ + .layout = { \ + .pages_count = DT_INST_PROP(n, size) / 8 \ + / SPI_NOR_SECTOR_SIZE, \ + .pages_size = SPI_NOR_SECTOR_SIZE, \ + }, \ + .flash_parameters = { \ + .write_block_size = NOR_WRITE_SIZE, \ + .erase_value = NOR_ERASE_VALUE, \ + }, \ + }; \ + \ + static struct flash_flexspi_nor_data \ + flash_flexspi_nor_data_##n; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + flash_flexspi_nor_init, \ + NULL, \ + &flash_flexspi_nor_data_##n, \ + &flash_flexspi_nor_config_##n, \ + POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &flash_flexspi_nor_api); + +DT_INST_FOREACH_STATUS_OKAY(FLASH_FLEXSPI_NOR) diff --git a/drivers/memc/memc_mcux_flexspi.c b/drivers/memc/memc_mcux_flexspi.c index ee819196b42ed..60859749ce123 100644 --- a/drivers/memc/memc_mcux_flexspi.c +++ b/drivers/memc/memc_mcux_flexspi.c @@ -140,6 +140,8 @@ static int memc_flexspi_init(const struct device *dev) #define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi)) #elif defined(CONFIG_XIP) && defined(CONFIG_CODE_FLEXSPI2) #define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi2)) +#elif defined(CONFIG_SOC_SERIES_IMX_RT6XX) +#define MEMC_FLEXSPI_CFG_XIP(node_id) IS_ENABLED(CONFIG_XIP) #else #define MEMC_FLEXSPI_CFG_XIP(node_id) false #endif diff --git a/dts/bindings/mtd/nxp,imx-flexspi-mx25um51345g.yaml b/dts/bindings/mtd/nxp,imx-flexspi-mx25um51345g.yaml new file mode 100644 index 0000000000000..a7cea2d55a483 --- /dev/null +++ b/dts/bindings/mtd/nxp,imx-flexspi-mx25um51345g.yaml @@ -0,0 +1,8 @@ +# Copyright 2021 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP FlexSPI MX25UM51345G + +compatible: "nxp,imx-flexspi-mx25um51345g" + +include: ["nxp,imx-flexspi-device.yaml", soc-nv-flash.yaml] diff --git a/samples/subsys/fs/littlefs/sample.yaml b/samples/subsys/fs/littlefs/sample.yaml index a4f6bb47b8dd5..8786f0eabec45 100644 --- a/samples/subsys/fs/littlefs/sample.yaml +++ b/samples/subsys/fs/littlefs/sample.yaml @@ -4,5 +4,5 @@ tests: sample.filesystem.littlefs: build_only: true platform_allow: nrf52840dk_nrf52840 particle_xenon disco_l475_iot1 - mimxrt1060_evk mimxrt1064_evk qemu_x86 native_posix + mimxrt685_evk_cm33 mimxrt1060_evk mimxrt1064_evk qemu_x86 native_posix tags: filesystem