diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-memory_map.dtsi b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-memory_map.dtsi index 80211205ca3..f2937402554 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-memory_map.dtsi +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-memory_map.dtsi @@ -174,6 +174,15 @@ zephyr,memory-region = "DMA_RAM3x_RAD"; zephyr,memory-attr = <( DT_MEM_DMA )>; }; + + xip_region: memory@60000000 { + compatible = "nordic,owned-memory"; + reg = <0x60000000 0x20000000>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x60000000 0x20000000>; + }; }; }; diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-pinctrl.dtsi b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-pinctrl.dtsi index 9b574a18ec5..f62df87dfe2 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-pinctrl.dtsi +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-pinctrl.dtsi @@ -73,12 +73,37 @@ /omit-if-no-ref/ exmif_default: exmif_default { group1 { psels = , + , + , , - ; + , + , + , + , + , + , + ; nordic,drive-mode = ; }; }; + /omit-if-no-ref/ exmif_sleep: exmif_sleep { + group1 { + low-power-enable; + psels = , + , + , + , + , + , + , + , + , + , + ; + }; + }; + /omit-if-no-ref/ can120_default: can120_default { group1 { psels = , diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts index 9c3556b27c4..be44d00f480 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts @@ -262,15 +262,15 @@ ipc0: &cpuapp_cpurad_ipc { }; &exmif { - cs-gpios = <&gpio6 3 GPIO_ACTIVE_LOW>; pinctrl-0 = <&exmif_default>; - pinctrl-names = "default"; + pinctrl-1 = <&exmif_sleep>; + pinctrl-names = "default", "sleep"; status = "okay"; + mx25uw63: mx25uw6345g@0 { - compatible = "jedec,spi-nor"; - status = "disabled"; + compatible = "jedec,mspi-nor"; + status = "okay"; reg = <0>; - spi-max-frequency = ; jedec-id = [c2 84 37]; sfdp-bfp = [ e5 20 8a ff ff ff ff 03 00 ff 00 ff 00 ff 00 ff @@ -283,6 +283,15 @@ ipc0: &cpuapp_cpurad_ipc { has-dpd; t-enter-dpd = <10000>; t-exit-dpd = <30000>; + reset-gpios = <&gpio6 12 GPIO_ACTIVE_LOW>; + + mspi-max-frequency = ; + mspi-io-mode = "MSPI_IO_MODE_OCTAL"; + mspi-data-rate = "MSPI_DATA_RATE_SINGLE"; + mspi-hardware-ce-num = <1>; + mspi-cpp-mode = "MSPI_CPP_MODE_0"; + mspi-endian = "MSPI_BIG_ENDIAN"; + mspi-ce-polarity = "MSPI_CE_ACTIVE_LOW"; }; }; diff --git a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280-pinctrl.dtsi b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280-pinctrl.dtsi index 48067a7052c..143fd45f33e 100644 --- a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280-pinctrl.dtsi +++ b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280-pinctrl.dtsi @@ -54,12 +54,37 @@ /omit-if-no-ref/ exmif_default: exmif_default { group1 { psels = , + , + , , - ; + , + , + , + , + , + , + ; nordic,drive-mode = ; }; }; + /omit-if-no-ref/ exmif_sleep: exmif_sleep { + group1 { + low-power-enable; + psels = , + , + , + , + , + , + , + , + , + , + ; + }; + }; + /omit-if-no-ref/ can120_default: can120_default { group1 { psels = , diff --git a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts index 2ce9b912269..61bed44b905 100644 --- a/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts +++ b/boards/nordic/nrf9280pdk/nrf9280pdk_nrf9280_cpuapp.dts @@ -253,15 +253,15 @@ ipc0: &cpuapp_cpurad_ipc { }; &exmif { - cs-gpios = <&gpio6 3 GPIO_ACTIVE_LOW>; pinctrl-0 = <&exmif_default>; - pinctrl-names = "default"; + pinctrl-1 = <&exmif_sleep>; + pinctrl-names = "default", "sleep"; status = "okay"; + mx25uw63: mx25uw6345g@0 { - compatible = "jedec,spi-nor"; - status = "disabled"; + compatible = "jedec,mspi-nor"; + status = "okay"; reg = <0>; - spi-max-frequency = ; jedec-id = [c2 84 37]; sfdp-bfp = [ e5 20 8a ff ff ff ff 03 00 ff 00 ff 00 ff 00 ff @@ -274,6 +274,15 @@ ipc0: &cpuapp_cpurad_ipc { has-dpd; t-enter-dpd = <10000>; t-exit-dpd = <30000>; + reset-gpios = <&gpio6 12 GPIO_ACTIVE_LOW>; + + mspi-max-frequency = ; + mspi-io-mode = "MSPI_IO_MODE_OCTAL"; + mspi-data-rate = "MSPI_DATA_RATE_SINGLE"; + mspi-hardware-ce-num = <1>; + mspi-cpp-mode = "MSPI_CPP_MODE_0"; + mspi-endian = "MSPI_BIG_ENDIAN"; + mspi-ce-polarity = "MSPI_CE_ACTIVE_LOW"; }; }; diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 64b9c149db3..aa2f8de7f75 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -16,10 +16,56 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/flash.h) zephyr_library() +# zephyr-keep-sorted-start +zephyr_library_sources_ifdef(CONFIG_FLASH_JESD216 jesd216.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_PAGE_LAYOUT flash_page_layout.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_SHELL flash_shell.c) +zephyr_library_sources_ifdef(CONFIG_USERSPACE flash_handlers.c) +# zephyr-keep-sorted-stop + +# zephyr-keep-sorted-start +zephyr_library_sources_ifdef(CONFIG_FLASH_AMBIQ flash_ambiq.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_ANDES_QSPI flash_andes_qspi.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_CAD_QSPI_NOR flash_cadence_qspi_nor.c flash_cadence_qspi_nor_ll.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_CDNS_NAND flash_cadence_nand.c flash_cadence_nand_ll.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_INFINEON_CAT1 flash_ifx_cat1.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_HYPERFLASH flash_mcux_flexspi_hyperflash.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_FLASH_MSPI_ATXP032 flash_mspi_atxp032.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_EMUL_DEVICE flash_mspi_emul_device.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_NOR flash_mspi_nor.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_NOR flash_npcx_fiu_nor.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_QSPI flash_npcx_fiu_qspi.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_RPI_PICO flash_rpi_pico.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_OSPI flash_stm32_ospi.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_QSPI flash_stm32_qspi.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_XSPI flash_stm32_xspi.c) +zephyr_library_sources_ifdef(CONFIG_INFINEON_CAT1_QSPI_FLASH flash_ifx_cat1_qspi.c) +zephyr_library_sources_ifdef(CONFIG_NORDIC_QSPI_NOR nrf_qspi_nor.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_CC13XX_CC26XX soc_flash_cc13xx_cc26xx.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ESP32 flash_esp32.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_GECKO flash_gecko.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ITE_IT8XXX2 flash_ite_it8xxx2.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_LPC soc_flash_lpc.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_MCUX soc_flash_mcux.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NIOS2_QSPI soc_flash_nios2_qspi.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF soc_flash_nrf.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_MRAM soc_flash_nrf_mram.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_RRAM soc_flash_nrf_rram.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NUMAKER soc_flash_numaker.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NUMAKER_RMC soc_flash_numaker_rmc.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_RV32M1 soc_flash_rv32m1.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM flash_sam.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM0 flash_sam0.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SI32 flash_si32.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SMARTBOND flash_smartbond.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_TELINK_B91 soc_flash_b91.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_XMC4XXX soc_flash_xmc4xxx.c) +zephyr_library_sources_ifdef(CONFIG_SPI_FLASH_AT45 spi_flash_at45.c) zephyr_library_sources_ifdef(CONFIG_SPI_NOR spi_nor.c) -zephyr_library_sources_ifdef(CONFIG_NORDIC_QSPI_NOR nrf_qspi_nor.c) +# zephyr-keep-sorted-stop + if(CONFIG_FLASH_SIMULATOR) zephyr_library_sources(flash_simulator.c) if(CONFIG_NATIVE_LIBRARY) @@ -28,36 +74,7 @@ if(CONFIG_FLASH_SIMULATOR) zephyr_library_sources(flash_simulator_native.c) endif() endif() -zephyr_library_sources_ifdef(CONFIG_SPI_FLASH_AT45 spi_flash_at45.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ITE_IT8XXX2 flash_ite_it8xxx2.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF soc_flash_nrf.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_MCUX soc_flash_mcux.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_LPC soc_flash_lpc.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_PAGE_LAYOUT flash_page_layout.c) -zephyr_library_sources_ifdef(CONFIG_USERSPACE flash_handlers.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM0 flash_sam0.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SAM flash_sam.c) -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_NPCX_FIU_QSPI flash_npcx_fiu_qspi.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_NOR flash_npcx_fiu_nor.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_QSPI flash_stm32_qspi.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_OSPI flash_stm32_ospi.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_XSPI flash_stm32_xspi.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_FLASH_MCUX_FLEXSPI_HYPERFLASH flash_mcux_flexspi_hyperflash.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ESP32 flash_esp32.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SMARTBOND flash_smartbond.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_CAD_QSPI_NOR flash_cadence_qspi_nor.c flash_cadence_qspi_nor_ll.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_XMC4XXX soc_flash_xmc4xxx.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_RPI_PICO flash_rpi_pico.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_ANDES_QSPI flash_andes_qspi.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_AMBIQ flash_ambiq.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_CDNS_NAND flash_cadence_nand.c flash_cadence_nand_ll.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_EMUL_DEVICE flash_mspi_emul_device.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_ATXP032 flash_mspi_atxp032.c) + zephyr_library_include_directories_ifdef(CONFIG_MSPI ${ZEPHYR_BASE}/drivers/mspi) if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) dt_chosen(chosen_flash PROPERTY "zephyr,flash") @@ -91,15 +108,17 @@ if(CONFIG_SOC_FLASH_STM32) zephyr_library_sources(flash_stm32.c) zephyr_library_sources_ifdef(CONFIG_FLASH_EX_OP_ENABLED flash_stm32_ex_op.c) +# zephyr-keep-sorted-start zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F1_FLASH_CONTROLLER_ENABLED flash_stm32f1x.c) zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F2_FLASH_CONTROLLER_ENABLED flash_stm32f2x.c) zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F4_FLASH_CONTROLLER_ENABLED flash_stm32f4x.c) zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32F7_FLASH_CONTROLLER_ENABLED flash_stm32f7x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G0_FLASH_CONTROLLER_ENABLED flash_stm32g0x.c) + zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G4_FLASH_CONTROLLER_ENABLED flash_stm32g4x.c) zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32L4_FLASH_CONTROLLER_ENABLED flash_stm32l4x.c) zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32L5_FLASH_CONTROLLER_ENABLED flash_stm32l5x.c) zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32WB_FLASH_CONTROLLER_ENABLED flash_stm32wbx.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G0_FLASH_CONTROLLER_ENABLED flash_stm32g0x.c) - zephyr_library_sources_ifdef(CONFIG_DT_HAS_ST_STM32G4_FLASH_CONTROLLER_ENABLED flash_stm32g4x.c) +# zephyr-keep-sorted-stop endif() endif() endif() @@ -107,9 +126,11 @@ endif() if(CONFIG_SOC_FLASH_GD32) zephyr_library_sources(flash_gd32.c) +# zephyr-keep-sorted-start zephyr_library_sources_ifdef(CONFIG_GD32_NV_FLASH_V1 flash_gd32_v1.c) zephyr_library_sources_ifdef(CONFIG_GD32_NV_FLASH_V2 flash_gd32_v2.c) zephyr_library_sources_ifdef(CONFIG_GD32_NV_FLASH_V3 flash_gd32_v3.c) +# zephyr-keep-sorted-stop endif() zephyr_library_include_directories_ifdef( @@ -133,16 +154,6 @@ zephyr_library_include_directories_ifdef( ${ZEPHYR_BASE}/drivers/memc ) -zephyr_library_sources_ifdef(CONFIG_FLASH_SHELL flash_shell.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_JESD216 jesd216.c) -zephyr_library_sources_ifdef(CONFIG_FLASH_INFINEON_CAT1 flash_ifx_cat1.c) -zephyr_library_sources_ifdef(CONFIG_INFINEON_CAT1_QSPI_FLASH flash_ifx_cat1_qspi.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NUMAKER soc_flash_numaker.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_RRAM soc_flash_nrf_rram.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_MRAM soc_flash_nrf_mram.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NUMAKER_RMC soc_flash_numaker_rmc.c) -zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_SI32 flash_si32.c) - if(CONFIG_RA_FLASH_HP) zephyr_library_sources(flash_hp_ra.c) zephyr_library_sources_ifdef(CONFIG_FLASH_EX_OP_ENABLED flash_hp_ra_ex_op.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index 99f17d71f7a..4ab3e9da14f 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -163,81 +163,46 @@ config FLASH_INIT_PRIORITY priority is used unless the driver implementation has its own initialization priority +# zephyr-keep-sorted-start +source "drivers/flash/Kconfig.ambiq" +source "drivers/flash/Kconfig.andes" +source "drivers/flash/Kconfig.at45" source "drivers/flash/Kconfig.b91" - +source "drivers/flash/Kconfig.cadence_nand" +source "drivers/flash/Kconfig.cadence_qspi_nor" source "drivers/flash/Kconfig.cc13xx_cc26xx" - -source "drivers/flash/Kconfig.at45" - source "drivers/flash/Kconfig.esp32" - +source "drivers/flash/Kconfig.gd32" +source "drivers/flash/Kconfig.gecko" +source "drivers/flash/Kconfig.ifx_cat1" source "drivers/flash/Kconfig.it8xxx2" - -source "drivers/flash/Kconfig.nrf" - source "drivers/flash/Kconfig.lpc" - source "drivers/flash/Kconfig.mcux" - source "drivers/flash/Kconfig.mspi" - source "drivers/flash/Kconfig.nios2_qspi" - -source "drivers/flash/Kconfig.npcx_fiu" - -source "drivers/flash/Kconfig.gecko" - source "drivers/flash/Kconfig.nor" - +source "drivers/flash/Kconfig.nordic_qspi_nor" +source "drivers/flash/Kconfig.npcx_fiu" +source "drivers/flash/Kconfig.nrf" +source "drivers/flash/Kconfig.nrf_mram" +source "drivers/flash/Kconfig.nrf_rram" +source "drivers/flash/Kconfig.numaker" +source "drivers/flash/Kconfig.numaker_rmc" +source "drivers/flash/Kconfig.nxp_s32" +source "drivers/flash/Kconfig.renesas_ra" source "drivers/flash/Kconfig.rpi_pico" - -source "drivers/flash/Kconfig.stm32" - -source "drivers/flash/Kconfig.stm32_qspi" - -source "drivers/flash/Kconfig.stm32_ospi" - -source "drivers/flash/Kconfig.stm32_xspi" - -source "drivers/flash/Kconfig.sam0" - +source "drivers/flash/Kconfig.rv32m1" source "drivers/flash/Kconfig.sam" - -source "drivers/flash/Kconfig.simulator" - +source "drivers/flash/Kconfig.sam0" source "drivers/flash/Kconfig.si32" - -source "drivers/flash/Kconfig.rv32m1" - -source "drivers/flash/Kconfig.nordic_qspi_nor" - +source "drivers/flash/Kconfig.simulator" source "drivers/flash/Kconfig.smartbond" - -source "drivers/flash/Kconfig.cadence_qspi_nor" - -source "drivers/flash/Kconfig.gd32" - +source "drivers/flash/Kconfig.stm32" +source "drivers/flash/Kconfig.stm32_ospi" +source "drivers/flash/Kconfig.stm32_qspi" +source "drivers/flash/Kconfig.stm32_xspi" source "drivers/flash/Kconfig.xmc4xxx" - -source "drivers/flash/Kconfig.ifx_cat1" - -source "drivers/flash/Kconfig.cadence_nand" - -source "drivers/flash/Kconfig.numaker" - -source "drivers/flash/Kconfig.nxp_s32" - -source "drivers/flash/Kconfig.andes" - -source "drivers/flash/Kconfig.ambiq" - -source "drivers/flash/Kconfig.nrf_rram" - -source "drivers/flash/Kconfig.nrf_mram" - -source "drivers/flash/Kconfig.numaker_rmc" - -source "drivers/flash/Kconfig.renesas_ra" +# zephyr-keep-sorted-stop module = FLASH module-str = flash diff --git a/drivers/flash/Kconfig.mspi b/drivers/flash/Kconfig.mspi index 158fcefb528..f9e515b5f9a 100644 --- a/drivers/flash/Kconfig.mspi +++ b/drivers/flash/Kconfig.mspi @@ -28,4 +28,22 @@ config FLASH_MSPI_ATXP032 select FLASH_JESD216 select MSPI_AMBIQ_AP3 if SOC_SERIES_APOLLO3X +menuconfig FLASH_MSPI_NOR + bool "Generic MSPI NOR Flash" + default y + depends on DT_HAS_JEDEC_MSPI_NOR_ENABLED + select FLASH_MSPI + select FLASH_HAS_EXPLICIT_ERASE + select FLASH_JESD216 + select GPIO if $(dt_compat_any_has_prop,$(DT_COMPAT_JEDEC_MSPI_NOR),reset-gpios) + +config FLASH_MSPI_NOR_INIT_PRIORITY + int + depends on FLASH_MSPI_NOR + default 80 + help + Device driver initialization priority. + Device is connected to MSPI bus, it has to + be initialized after MSPI driver. + endmenu diff --git a/drivers/flash/flash_mspi_nor.c b/drivers/flash/flash_mspi_nor.c new file mode 100644 index 00000000000..1b8bfa1852f --- /dev/null +++ b/drivers/flash/flash_mspi_nor.c @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT jedec_mspi_nor + +#include +#include +#include +#include +#include +#include + +#include "jesd216.h" +#include "spi_nor.h" + +LOG_MODULE_REGISTER(flash_mspi_nor, CONFIG_FLASH_LOG_LEVEL); + +struct flash_mspi_nor_data { + struct k_sem acquired; + struct mspi_xfer_packet packet; + struct mspi_xfer xfer; +}; + +struct flash_mspi_nor_config { + const struct device *bus; + struct mspi_dev_id mspi_id; + struct mspi_dev_cfg mspi_cfg; +#if defined(CONFIG_MSPI_XIP) + struct mspi_xip_cfg xip_cfg; +#endif + struct gpio_dt_spec reset; + uint32_t flash_size; +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + struct flash_pages_layout layout; +#endif + uint8_t jedec_id[SPI_NOR_MAX_ID_LEN]; +}; + +static int acquire(const struct device *dev) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + int rc; + + k_sem_take(&dev_data->acquired, K_FOREVER); + + rc = pm_device_runtime_get(dev_config->bus); + if (rc < 0) { + LOG_ERR("pm_device_runtime_get() failed: %d", rc); + return rc; + } + + /* This acquires the MSPI controller and configures it for the flash. */ + rc = mspi_dev_config(dev_config->bus, &dev_config->mspi_id, + MSPI_DEVICE_CONFIG_ALL, &dev_config->mspi_cfg); + if (rc < 0) { + LOG_ERR("mspi_dev_config() failed: %d", rc); + return rc; + } + + return 0; +} + +static void release(const struct device *dev) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + + /* This releases the MSPI controller. */ + (void)mspi_get_channel_status(dev_config->bus, 0); + + (void)pm_device_runtime_put(dev_config->bus); + + k_sem_give(&dev_data->acquired); +} + +static inline uint32_t dev_flash_size(const struct device *dev) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + + return dev_config->flash_size; +} + +static inline uint16_t dev_page_size(const struct device *dev) +{ + return SPI_NOR_PAGE_SIZE; +} + +static int api_read(const struct device *dev, off_t addr, void *dest, + size_t size) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + const uint32_t flash_size = dev_flash_size(dev); + int rc; + + if (size == 0) { + return 0; + } + + if ((addr < 0) || ((addr + size) > flash_size)) { + return -EINVAL; + } + + rc = acquire(dev); + if (rc < 0) { + return rc; + } + + /* TODO: get rid of all these hard-coded values for MX25Ux chips */ + dev_data->xfer.cmd_length = 2; + dev_data->xfer.addr_length = 4; + dev_data->xfer.rx_dummy = 20; + dev_data->packet.dir = MSPI_RX; + dev_data->packet.cmd = SPI_NOR_OCMD_RD; + dev_data->packet.address = addr; + dev_data->packet.data_buf = dest; + dev_data->packet.num_bytes = size; + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + + release(dev); + + if (rc < 0) { + LOG_ERR("SPI_NOR_OCMD_RD xfer failed: %d", rc); + return rc; + } + + return 0; +} + +static int wait_until_ready(const struct device *dev, k_timeout_t poll_period) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + uint8_t status_reg; + int rc; + + while (true) { + dev_data->xfer.cmd_length = 2; + dev_data->xfer.addr_length = 4; + dev_data->xfer.rx_dummy = 4; + dev_data->packet.dir = MSPI_RX; + dev_data->packet.cmd = SPI_NOR_OCMD_RDSR; + dev_data->packet.address = 0; + dev_data->packet.data_buf = &status_reg; + dev_data->packet.num_bytes = sizeof(status_reg); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + LOG_ERR("SPI_NOR_OCMD_RDSR xfer failed: %d", rc); + return rc; + } + if (!(status_reg & SPI_NOR_WIP_BIT)) { + break; + } + + k_sleep(poll_period); + } + + return 0; +} + +static int api_write(const struct device *dev, off_t addr, const void *src, + size_t size) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + const uint32_t flash_size = dev_flash_size(dev); + const uint16_t page_size = dev_page_size(dev); + int rc; + + if (size == 0) { + return 0; + } + + if ((addr < 0) || ((addr + size) > flash_size)) { + return -EINVAL; + } + + rc = acquire(dev); + if (rc < 0) { + return rc; + } + + while (size > 0) { + /* Split write into parts, each within one page only. */ + uint16_t page_offset = (uint16_t)(addr % page_size); + uint16_t page_left = page_size - page_offset; + uint16_t to_write = (uint16_t)MIN(size, page_left); + + dev_data->xfer.cmd_length = 2; + dev_data->xfer.tx_dummy = 0; + dev_data->packet.dir = MSPI_TX; + + dev_data->xfer.addr_length = 0; + dev_data->packet.cmd = SPI_NOR_OCMD_WREN; + dev_data->packet.num_bytes = 0; + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + LOG_ERR("SPI_NOR_OCMD_WREN xfer failed: %d", rc); + break; + } + + dev_data->xfer.addr_length = 4; + dev_data->packet.cmd = SPI_NOR_OCMD_PAGE_PRG; + dev_data->packet.address = addr; + dev_data->packet.data_buf = (uint8_t *)src; + dev_data->packet.num_bytes = to_write; + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + LOG_ERR("SPI_NOR_OCMD_PAGE_PRG xfer failed: %d", rc); + break; + } + + addr += to_write; + src = (const uint8_t *)src + to_write; + size -= to_write; + + rc = wait_until_ready(dev, K_MSEC(1)); + if (rc < 0) { + break; + } + } + + release(dev); + + return rc; +} + +static int api_erase(const struct device *dev, off_t addr, size_t size) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + const uint32_t flash_size = dev_flash_size(dev); + int rc = 0; + + if ((addr < 0) || ((addr + size) > flash_size)) { + return -EINVAL; + } + + if (!SPI_NOR_IS_SECTOR_ALIGNED(addr)) { + return -EINVAL; + } + + if ((size % SPI_NOR_SECTOR_SIZE) != 0) { + return -EINVAL; + } + + rc = acquire(dev); + if (rc < 0) { + return rc; + } + + while (size > 0) { + dev_data->xfer.cmd_length = 2; + dev_data->xfer.tx_dummy = 0; + dev_data->packet.dir = MSPI_TX; + dev_data->packet.num_bytes = 0; + + dev_data->xfer.addr_length = 0; + dev_data->packet.cmd = SPI_NOR_OCMD_WREN; + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + LOG_ERR("SPI_NOR_OCMD_WREN xfer failed: %d", rc); + break; + } + + if (size == flash_size) { + /* Chip erase. */ + dev_data->xfer.addr_length = 0; + dev_data->packet.cmd = SPI_NOR_OCMD_CE; + + size -= flash_size; + } else { + /* Sector erase. */ + dev_data->xfer.addr_length = 4; + dev_data->packet.cmd = SPI_NOR_OCMD_SE; + dev_data->packet.address = addr; + + addr += SPI_NOR_SECTOR_SIZE; + size -= SPI_NOR_SECTOR_SIZE; + } + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + LOG_ERR("Erase command 0x%02x xfer failed: %d", + dev_data->packet.cmd, rc); + break; + } + + rc = wait_until_ready(dev, K_MSEC(1)); + if (rc < 0) { + break; + } + } + + release(dev); + + return rc; +} + +static const +struct flash_parameters *api_get_parameters(const struct device *dev) +{ + ARG_UNUSED(dev); + + static const struct flash_parameters parameters = { + .write_block_size = 1, + .erase_value = 0xff, + }; + + return ¶meters; +} + +static int read_jedec_id(const struct device *dev, uint8_t *id) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + int rc; + + dev_data->xfer.cmd_length = 2; + dev_data->xfer.addr_length = 4; + dev_data->xfer.rx_dummy = 4; + dev_data->packet.dir = MSPI_RX; + dev_data->packet.cmd = JESD216_OCMD_READ_ID; + dev_data->packet.address = 0; + dev_data->packet.data_buf = id; + dev_data->packet.num_bytes = JESD216_READ_ID_LEN; + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + printk("mspi_transceive() failed: %d\n", rc); + return rc; + } + + return rc; +} + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static void api_page_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + + *layout = &dev_config->layout; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +#if defined(CONFIG_FLASH_JESD216_API) +static int api_sfdp_read(const struct device *dev, off_t addr, void *dest, + size_t size) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + int rc; + + if (size == 0) { + return 0; + } + + rc = acquire(dev); + if (rc < 0) { + return rc; + } + + dev_data->xfer.cmd_length = 2; + dev_data->xfer.addr_length = 4; + dev_data->xfer.rx_dummy = 20; + dev_data->packet.dir = MSPI_RX; + dev_data->packet.cmd = JESD216_OCMD_READ_SFDP; + dev_data->packet.address = addr; + dev_data->packet.data_buf = dest; + dev_data->packet.num_bytes = size; + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + printk("JESD216_OCMD_READ_SFDP xfer failed: %d\n", rc); + return rc; + } + + release(dev); + + return rc; +} + +static int api_read_jedec_id(const struct device *dev, uint8_t *id) +{ + int rc = 0; + + rc = acquire(dev); + if (rc < 0) { + return rc; + } + + rc = read_jedec_id(dev, id); + + release(dev); + + return rc; +} +#endif /* CONFIG_FLASH_JESD216_API */ + +static int dev_pm_action_cb(const struct device *dev, + enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + break; + case PM_DEVICE_ACTION_RESUME: + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int flash_chip_init(const struct device *dev) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + struct mspi_dev_cfg init_dev_cfg = dev_config->mspi_cfg; + uint8_t id[JESD216_READ_ID_LEN] = {0}; + int rc; + + init_dev_cfg.freq = MHZ(1); + init_dev_cfg.io_mode = MSPI_IO_MODE_SINGLE; + + rc = mspi_dev_config(dev_config->bus, &dev_config->mspi_id, + MSPI_DEVICE_CONFIG_ALL, &init_dev_cfg); + if (rc < 0) { + LOG_ERR("Failed to set initial device config: %d", rc); + return rc; + } + + dev_data->xfer.xfer_mode = MSPI_PIO; + dev_data->xfer.packets = &dev_data->packet; + dev_data->xfer.num_packet = 1; + dev_data->xfer.timeout = 10; + + dev_data->xfer.cmd_length = 1; + dev_data->xfer.addr_length = 0; + dev_data->xfer.tx_dummy = 0; + dev_data->xfer.rx_dummy = 0; + + dev_data->packet.dir = MSPI_RX; + dev_data->packet.cmd = JESD216_CMD_READ_ID; + dev_data->packet.data_buf = id; + dev_data->packet.num_bytes = sizeof(id); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + LOG_ERR("Failed to read JEDEC ID in single line mode: %d", rc); + return rc; + } + + /* + * If the read ID does not match the one from DTS, assume the flash + * is already in the Octa I/O mode, so switching it is not needed. + */ + if (memcmp(id, dev_config->jedec_id, sizeof(id)) == 0) { + static const uint8_t enable_sopi[] = { 0x01 }; + + dev_data->packet.dir = MSPI_TX; + dev_data->packet.cmd = SPI_NOR_CMD_WREN; + dev_data->packet.num_bytes = 0; + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + LOG_ERR("SPI_NOR_CMD_WREN xfer failed: %d", rc); + return rc; + } + + dev_data->xfer.addr_length = 4; + dev_data->packet.cmd = SPI_NOR_CMD_WR_CFGREG2; + dev_data->packet.address = 0; + dev_data->packet.data_buf = (uint8_t *)&enable_sopi; + dev_data->packet.num_bytes = sizeof(enable_sopi); + rc = mspi_transceive(dev_config->bus, &dev_config->mspi_id, + &dev_data->xfer); + if (rc < 0) { + printk("SPI_NOR_CMD_WR_CFGREG2 xfer failed: %d\n", rc); + return rc; + } + } + + rc = mspi_dev_config(dev_config->bus, &dev_config->mspi_id, + MSPI_DEVICE_CONFIG_ALL, &dev_config->mspi_cfg); + if (rc < 0) { + LOG_ERR("Failed to set device config: %d", rc); + return rc; + } + + rc = read_jedec_id(dev, id); + if (rc < 0) { + return rc; + } + + if (memcmp(id, dev_config->jedec_id, sizeof(id)) != 0) { + LOG_ERR("JEDEC ID mismatch, read: %02x %02x %02x, " + "expected: %02x %02x %02x", + id[0], id[1], id[2], + dev_config->jedec_id[0], + dev_config->jedec_id[1], + dev_config->jedec_id[2]); + return -ENODEV; + } + +#if defined(CONFIG_MSPI_XIP) + /* Enable XIP access for this chip if specified so in DT. */ + if (dev_config->xip_cfg.enable) { + rc = mspi_xip_config(dev_config->bus, &dev_config->mspi_id, + &dev_config->xip_cfg); + if (rc < 0) { + return rc; + } + } +#endif + + return 0; +} + +static int drv_init(const struct device *dev) +{ + const struct flash_mspi_nor_config *dev_config = dev->config; + struct flash_mspi_nor_data *dev_data = dev->data; + int rc; + + if (!device_is_ready(dev_config->bus)) { + LOG_ERR("Device %s is not ready", dev_config->bus->name); + return -ENODEV; + } + + if (dev_config->reset.port) { + if (!gpio_is_ready_dt(&dev_config->reset)) { + LOG_ERR("Device %s is not ready", + dev_config->reset.port->name); + return -ENODEV; + } + + if (gpio_pin_configure_dt(&dev_config->reset, + GPIO_OUTPUT_ACTIVE) < 0 || + gpio_pin_set_dt(&dev_config->reset, 0) < 0) { + return -EIO; + } + } + + rc = pm_device_runtime_get(dev_config->bus); + if (rc < 0) { + LOG_ERR("pm_device_runtime_get() failed: %d", rc); + return rc; + } + + /* Acquire the MSPI controller. */ + rc = mspi_dev_config(dev_config->bus, &dev_config->mspi_id, + MSPI_DEVICE_CONFIG_NONE, NULL); + if (rc == 0) { + rc = flash_chip_init(dev); + + /* Release the MSPI controller. */ + (void)mspi_get_channel_status(dev_config->bus, 0); + } + + (void)pm_device_runtime_put(dev_config->bus); + + if (rc < 0) { + return rc; + } + + k_sem_init(&dev_data->acquired, 1, K_SEM_MAX_LIMIT); + + return pm_device_driver_init(dev, dev_pm_action_cb); +} + +static const struct flash_driver_api drv_api = { + .read = api_read, + .write = api_write, + .erase = api_erase, + .get_parameters = api_get_parameters, +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = api_page_layout, +#endif +#if defined(CONFIG_FLASH_JESD216_API) + .sfdp_read = api_sfdp_read, + .read_jedec_id = api_read_jedec_id, +#endif +}; + +#define FLASH_SIZE_INST(inst) (DT_INST_PROP(inst, size) / 8) + +#define FLASH_MSPI_NOR_INST(inst) \ + BUILD_ASSERT(DT_INST_ENUM_IDX(inst, mspi_io_mode) == \ + MSPI_IO_MODE_OCTAL, \ + "Only Octal I/O mode is supported for now"); \ + PM_DEVICE_DT_INST_DEFINE(inst, dev_pm_action_cb); \ + static struct flash_mspi_nor_data dev##inst##_data; \ + static const struct flash_mspi_nor_config dev##inst##_config = {\ + .bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .mspi_id = MSPI_DEVICE_ID_DT_INST(inst), \ + .mspi_cfg = MSPI_DEVICE_CONFIG_DT_INST(inst), \ + IF_ENABLED(CONFIG_MSPI_XIP, \ + (.xip_cfg = MSPI_XIP_CONFIG_DT_INST(inst),)) \ + .reset = GPIO_DT_SPEC_INST_GET_OR(inst, \ + reset_gpios, {0}), \ + .flash_size = FLASH_SIZE_INST(inst), \ + IF_ENABLED(CONFIG_FLASH_PAGE_LAYOUT, \ + (.layout = { \ + /* TODO: make this size configurable */ \ + .pages_size = 65536, \ + .pages_count = FLASH_SIZE_INST(inst) / 65536, \ + },)) \ + .jedec_id = DT_INST_PROP(inst, jedec_id), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + drv_init, PM_DEVICE_DT_INST_GET(inst), \ + &dev##inst##_data, &dev##inst##_config, \ + POST_KERNEL, CONFIG_FLASH_MSPI_NOR_INIT_PRIORITY, \ + &drv_api); + +DT_INST_FOREACH_STATUS_OKAY(FLASH_MSPI_NOR_INST) diff --git a/drivers/mspi/CMakeLists.txt b/drivers/mspi/CMakeLists.txt index f248cb0b533..78f704393f4 100644 --- a/drivers/mspi/CMakeLists.txt +++ b/drivers/mspi/CMakeLists.txt @@ -4,4 +4,5 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/mspi.h) zephyr_library() zephyr_library_sources_ifdef(CONFIG_MSPI_AMBIQ_AP3 mspi_ambiq_ap3.c) +zephyr_library_sources_ifdef(CONFIG_MSPI_DW mspi_dw.c) zephyr_library_sources_ifdef(CONFIG_MSPI_EMUL mspi_emul.c) diff --git a/drivers/mspi/Kconfig b/drivers/mspi/Kconfig index 0adb2a34393..269d8d16f04 100644 --- a/drivers/mspi/Kconfig +++ b/drivers/mspi/Kconfig @@ -60,6 +60,7 @@ module-str = mspi source "subsys/logging/Kconfig.template.log_config" source "drivers/mspi/Kconfig.ambiq" +source "drivers/mspi/Kconfig.dw" source "drivers/mspi/Kconfig.mspi_emul" endif # MSPI diff --git a/drivers/mspi/Kconfig.dw b/drivers/mspi/Kconfig.dw new file mode 100644 index 00000000000..1ab82da0e85 --- /dev/null +++ b/drivers/mspi/Kconfig.dw @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config MSPI_DW + bool "DesignWare SSI controller driver" + default y + depends on DT_HAS_SNPS_DESIGNWARE_SSI_ENABLED + select PINCTRL if $(dt_compat_any_has_prop,$(DT_COMPAT_SNPS_DESIGNWARE_SSI),pinctrl-0) + imply MSPI_XIP diff --git a/drivers/mspi/mspi_dw.c b/drivers/mspi/mspi_dw.c new file mode 100644 index 00000000000..886d24462a2 --- /dev/null +++ b/drivers/mspi/mspi_dw.c @@ -0,0 +1,1355 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT snps_designware_ssi + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mspi_dw.h" +#include "mspi_dw_vendor_specific.h" + +LOG_MODULE_REGISTER(mspi_dw, CONFIG_MSPI_LOG_LEVEL); + +#define DUMMY_BYTE 0xAA + +#if defined(CONFIG_MSPI_XIP) +struct xip_params { + uint32_t read_cmd; + uint32_t write_cmd; + uint16_t rx_dummy; + uint16_t tx_dummy; + uint8_t cmd_length; + uint8_t addr_length; + enum mspi_io_mode io_mode; +}; + +struct xip_ctrl { + uint32_t read; + uint32_t write; +}; +#endif + +struct mspi_dw_data { + const struct mspi_dev_id *dev_id; + uint32_t packets_done; + uint8_t *buf_pos; + const uint8_t *buf_end; + + uint32_t ctrlr0; + uint32_t spi_ctrlr0; + uint32_t baudr; + +#if defined(CONFIG_MSPI_XIP) + uint32_t xip_freq; + struct xip_params xip_params_stored; + struct xip_params xip_params_active; + uint16_t xip_enabled; + enum mspi_cpp_mode xip_cpp; +#endif + + uint16_t dummy_bytes; + uint8_t bytes_to_discard; + uint8_t bytes_per_frame_exp; + bool standard_spi; + + struct k_sem finished; + struct k_sem ctx_lock; + struct k_sem cfg_lock; + struct mspi_xfer xfer; +}; + +struct mspi_dw_config { + DEVICE_MMIO_ROM; + void (*irq_config)(void); + uint32_t clock_frequency; +#if defined(CONFIG_PINCTRL) + const struct pinctrl_dev_config *pcfg; +#endif + const struct gpio_dt_spec *ce_gpios; + uint8_t ce_gpios_len; + uint8_t tx_fifo_depth_minus_1; + uint8_t tx_fifo_threshold; + uint8_t rx_fifo_threshold; + DECLARE_REG_ACCESS(); +}; + +/* Register access helpers. */ +#define DEFINE_MM_REG_RD_WR(reg, off) \ + DEFINE_MM_REG_RD(reg, off) \ + DEFINE_MM_REG_WR(reg, off) + +DEFINE_MM_REG_WR(ctrlr0, 0x00) +DEFINE_MM_REG_WR(ctrlr1, 0x04) +DEFINE_MM_REG_WR(ssienr, 0x08) +DEFINE_MM_REG_WR(ser, 0x10) +DEFINE_MM_REG_WR(baudr, 0x14) +DEFINE_MM_REG_RD_WR(txftlr, 0x18) +DEFINE_MM_REG_RD_WR(rxftlr, 0x1c) +DEFINE_MM_REG_RD(txflr, 0x20) +DEFINE_MM_REG_RD(rxflr, 0x24) +DEFINE_MM_REG_RD(sr, 0x28) +DEFINE_MM_REG_WR(imr, 0x2c) +DEFINE_MM_REG_RD(isr, 0x30) +DEFINE_MM_REG_RD_WR(dr, 0x60) +DEFINE_MM_REG_WR(spi_ctrlr0, 0xf4) + +#if defined(CONFIG_MSPI_XIP) +DEFINE_MM_REG_WR(xip_incr_inst, 0x100) +DEFINE_MM_REG_WR(xip_wrap_inst, 0x104) +DEFINE_MM_REG_WR(xip_ctrl, 0x108) +DEFINE_MM_REG_WR(xip_write_incr_inst, 0x140) +DEFINE_MM_REG_WR(xip_write_wrap_inst, 0x144) +DEFINE_MM_REG_WR(xip_write_ctrl, 0x148) +#endif + +static void tx_data(const struct device *dev, + const struct mspi_xfer_packet *packet) +{ + struct mspi_dw_data *dev_data = dev->data; + const struct mspi_dw_config *dev_config = dev->config; + const uint8_t *buf_pos = dev_data->buf_pos; + const uint8_t *buf_end = dev_data->buf_end; + /* When the function is called, it is known that at least one item + * can be written to the FIFO. The loop below writes to the FIFO + * the number of items that is known to fit and then updates that + * number basing on the actual FIFO level (because some data may get + * sent while the FIFO is written; especially for high frequencies + * this may often occur) and continues until the FIFO is filled up + * or the buffer end is reached. + */ + uint32_t room = 1; + uint8_t bytes_per_frame_exp = dev_data->bytes_per_frame_exp; + uint8_t tx_fifo_depth = dev_config->tx_fifo_depth_minus_1 + 1; + uint32_t data; + + do { + if (bytes_per_frame_exp == 2) { + data = sys_get_be32(buf_pos); + buf_pos += 4; + } else if (bytes_per_frame_exp == 1) { + data = sys_get_be16(buf_pos); + buf_pos += 2; + } else { + data = *buf_pos; + buf_pos += 1; + } + write_dr(dev, data); + + if (buf_pos >= buf_end) { + write_txftlr(dev, 0); + break; + } + + if (--room == 0) { + room = tx_fifo_depth + - FIELD_GET(TXFLR_TXTFL_MASK, read_txflr(dev)); + } + } while (room); + + dev_data->buf_pos = (uint8_t *)buf_pos; +} + +static bool make_rx_cycles(const struct device *dev) +{ + struct mspi_dw_data *dev_data = dev->data; + const struct mspi_dw_config *dev_config = dev->config; + uint16_t dummy_bytes = dev_data->dummy_bytes; + /* See tx_data(). */ + uint32_t room = 1; + uint8_t tx_fifo_depth = dev_config->tx_fifo_depth_minus_1 + 1; + + do { + write_dr(dev, DUMMY_BYTE); + + --dummy_bytes; + if (!dummy_bytes) { + dev_data->dummy_bytes = 0; + return true; + } + + if (--room == 0) { + room = tx_fifo_depth + - FIELD_GET(TXFLR_TXTFL_MASK, read_txflr(dev)); + } + } while (room); + + dev_data->dummy_bytes = dummy_bytes; + return false; +} + +static void read_rx_fifo(const struct device *dev, + const struct mspi_xfer_packet *packet) +{ + struct mspi_dw_data *dev_data = dev->data; + const struct mspi_dw_config *dev_config = dev->config; + uint8_t bytes_to_discard = dev_data->bytes_to_discard; + uint8_t *buf_pos = dev_data->buf_pos; + const uint8_t *buf_end = &packet->data_buf[packet->num_bytes]; + uint8_t bytes_per_frame_exp = dev_data->bytes_per_frame_exp; + /* See `room` in tx_data(). */ + uint32_t in_fifo = 1; + uint32_t remaining_frames; + + do { + uint32_t data = read_dr(dev); + + if (bytes_to_discard) { + --bytes_to_discard; + } else { + if (bytes_per_frame_exp == 2) { + sys_put_be32(data, buf_pos); + buf_pos += 4; + } else if (bytes_per_frame_exp == 1) { + sys_put_be16(data, buf_pos); + buf_pos += 2; + } else { + *buf_pos = (uint8_t)data; + buf_pos += 1; + } + + if (buf_pos >= buf_end) { + dev_data->bytes_to_discard = bytes_to_discard; + dev_data->buf_pos = buf_pos; + return; + } + } + + if (--in_fifo == 0) { + in_fifo = FIELD_GET(RXFLR_RXTFL_MASK, read_rxflr(dev)); + } + } while (in_fifo); + + remaining_frames = (bytes_to_discard + buf_end - buf_pos) + >> bytes_per_frame_exp; + if (remaining_frames - 1 < dev_config->rx_fifo_threshold) { + write_rxftlr(dev, remaining_frames - 1); + } + + dev_data->bytes_to_discard = bytes_to_discard; + dev_data->buf_pos = buf_pos; +} + +static void mspi_dw_isr(const struct device *dev) +{ + struct mspi_dw_data *dev_data = dev->data; + const struct mspi_xfer_packet *packet = + &dev_data->xfer.packets[dev_data->packets_done]; + uint32_t int_status = read_isr(dev); + + if (int_status & ISR_RXFIS_BIT) { + read_rx_fifo(dev, packet); + } + + if (dev_data->buf_pos >= dev_data->buf_end) { + write_imr(dev, 0); + /* It may happen that at this point the controller is still + * shifting out the last frame (the last interrupt occurs when + * the TX FIFO is empty). Wait if it signals that it is busy. + */ + while (read_sr(dev) & SR_BUSY_BIT) { + } + + k_sem_give(&dev_data->finished); + } else { + if (int_status & ISR_TXEIS_BIT) { + if (dev_data->dummy_bytes) { + if (make_rx_cycles(dev)) { + write_imr(dev, IMR_RXFIM_BIT); + } + } else { + tx_data(dev, packet); + } + } + } + + vendor_specific_irq_clear(dev); +} + +static int api_config(const struct mspi_dt_spec *spec) +{ + ARG_UNUSED(spec); + + return -ENOTSUP; +} + +static bool apply_io_mode(struct mspi_dw_data *dev_data, + enum mspi_io_mode io_mode) +{ + dev_data->ctrlr0 &= ~CTRLR0_SPI_FRF_MASK; + dev_data->spi_ctrlr0 &= ~SPI_CTRLR0_TRANS_TYPE_MASK; + + /* Frame format used for transferring data. */ + + if (io_mode == MSPI_IO_MODE_SINGLE) { + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_SPI_FRF_MASK, + CTRLR0_SPI_FRF_STANDARD); + dev_data->standard_spi = true; + return true; + } + + dev_data->standard_spi = false; + + switch (io_mode) { + case MSPI_IO_MODE_DUAL: + case MSPI_IO_MODE_DUAL_1_1_2: + case MSPI_IO_MODE_DUAL_1_2_2: + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_SPI_FRF_MASK, + CTRLR0_SPI_FRF_DUAL); + break; + case MSPI_IO_MODE_QUAD: + case MSPI_IO_MODE_QUAD_1_1_4: + case MSPI_IO_MODE_QUAD_1_4_4: + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_SPI_FRF_MASK, + CTRLR0_SPI_FRF_QUAD); + break; + case MSPI_IO_MODE_OCTAL: + case MSPI_IO_MODE_OCTAL_1_1_8: + case MSPI_IO_MODE_OCTAL_1_8_8: + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_SPI_FRF_MASK, + CTRLR0_SPI_FRF_OCTAL); + break; + default: + LOG_ERR("IO mode %d not supported", io_mode); + return false; + } + + /* Transfer format used for Address and Instruction: */ + + switch (io_mode) { + case MSPI_IO_MODE_DUAL_1_1_2: + case MSPI_IO_MODE_QUAD_1_1_4: + case MSPI_IO_MODE_OCTAL_1_1_8: + /* - both sent in Standard SPI mode */ + dev_data->spi_ctrlr0 |= FIELD_PREP(SPI_CTRLR0_TRANS_TYPE_MASK, + SPI_CTRLR0_TRANS_TYPE_TT0); + break; + case MSPI_IO_MODE_DUAL_1_2_2: + case MSPI_IO_MODE_QUAD_1_4_4: + case MSPI_IO_MODE_OCTAL_1_8_8: + /* - Instruction sent in Standard SPI mode, + * Address sent the same way as data + */ + dev_data->spi_ctrlr0 |= FIELD_PREP(SPI_CTRLR0_TRANS_TYPE_MASK, + SPI_CTRLR0_TRANS_TYPE_TT1); + break; + default: + /* - both sent the same way as data. */ + dev_data->spi_ctrlr0 |= FIELD_PREP(SPI_CTRLR0_TRANS_TYPE_MASK, + SPI_CTRLR0_TRANS_TYPE_TT2); + break; + } + + return true; +} + +static bool apply_cmd_length(struct mspi_dw_data *dev_data, uint32_t cmd_length) +{ + switch (cmd_length) { + case 0: + dev_data->spi_ctrlr0 |= FIELD_PREP(SPI_CTRLR0_INST_L_MASK, + SPI_CTRLR0_INST_L0); + break; + case 1: + dev_data->spi_ctrlr0 |= FIELD_PREP(SPI_CTRLR0_INST_L_MASK, + SPI_CTRLR0_INST_L8); + break; + case 2: + dev_data->spi_ctrlr0 |= FIELD_PREP(SPI_CTRLR0_INST_L_MASK, + SPI_CTRLR0_INST_L16); + break; + default: + LOG_ERR("Command length %d not supported", cmd_length); + return false; + } + + return true; +} + +static bool apply_addr_length(struct mspi_dw_data *dev_data, + uint32_t addr_length) +{ + dev_data->spi_ctrlr0 |= FIELD_PREP(SPI_CTRLR0_ADDR_L_MASK, + addr_length * 2); + + return true; +} + +#if defined(CONFIG_MSPI_XIP) +static bool apply_xip_io_mode(const struct mspi_dw_data *dev_data, + struct xip_ctrl *ctrl) +{ + enum mspi_io_mode io_mode = dev_data->xip_params_active.io_mode; + + /* Frame format used for transferring data. */ + + if (io_mode == MSPI_IO_MODE_SINGLE) { + LOG_ERR("XIP not available in single line mode"); + return false; + } + + switch (io_mode) { + case MSPI_IO_MODE_DUAL: + case MSPI_IO_MODE_DUAL_1_1_2: + case MSPI_IO_MODE_DUAL_1_2_2: + ctrl->read |= FIELD_PREP(XIP_CTRL_FRF_MASK, + XIP_CTRL_FRF_DUAL); + ctrl->write |= FIELD_PREP(XIP_WRITE_CTRL_FRF_MASK, + XIP_WRITE_CTRL_FRF_DUAL); + break; + case MSPI_IO_MODE_QUAD: + case MSPI_IO_MODE_QUAD_1_1_4: + case MSPI_IO_MODE_QUAD_1_4_4: + ctrl->read |= FIELD_PREP(XIP_CTRL_FRF_MASK, + XIP_CTRL_FRF_QUAD); + ctrl->write |= FIELD_PREP(XIP_WRITE_CTRL_FRF_MASK, + XIP_WRITE_CTRL_FRF_QUAD); + break; + case MSPI_IO_MODE_OCTAL: + case MSPI_IO_MODE_OCTAL_1_1_8: + case MSPI_IO_MODE_OCTAL_1_8_8: + ctrl->read |= FIELD_PREP(XIP_CTRL_FRF_MASK, + XIP_CTRL_FRF_OCTAL); + ctrl->write |= FIELD_PREP(XIP_WRITE_CTRL_FRF_MASK, + XIP_WRITE_CTRL_FRF_OCTAL); + break; + default: + LOG_ERR("IO mode %d not supported", io_mode); + return false; + } + + /* Transfer format used for Address and Instruction: */ + + switch (io_mode) { + case MSPI_IO_MODE_DUAL_1_1_2: + case MSPI_IO_MODE_QUAD_1_1_4: + case MSPI_IO_MODE_OCTAL_1_1_8: + /* - both sent in Standard SPI mode */ + ctrl->read |= FIELD_PREP(XIP_CTRL_TRANS_TYPE_MASK, + XIP_CTRL_TRANS_TYPE_TT0); + ctrl->write |= FIELD_PREP(XIP_WRITE_CTRL_TRANS_TYPE_MASK, + XIP_WRITE_CTRL_TRANS_TYPE_TT0); + break; + case MSPI_IO_MODE_DUAL_1_2_2: + case MSPI_IO_MODE_QUAD_1_4_4: + case MSPI_IO_MODE_OCTAL_1_8_8: + /* - Instruction sent in Standard SPI mode, + * Address sent the same way as data + */ + ctrl->read |= FIELD_PREP(XIP_CTRL_TRANS_TYPE_MASK, + XIP_CTRL_TRANS_TYPE_TT1); + ctrl->write |= FIELD_PREP(XIP_WRITE_CTRL_TRANS_TYPE_MASK, + XIP_WRITE_CTRL_TRANS_TYPE_TT1); + break; + default: + /* - both sent the same way as data. */ + ctrl->read |= FIELD_PREP(XIP_CTRL_TRANS_TYPE_MASK, + XIP_CTRL_TRANS_TYPE_TT2); + ctrl->write |= FIELD_PREP(XIP_WRITE_CTRL_TRANS_TYPE_MASK, + XIP_WRITE_CTRL_TRANS_TYPE_TT2); + break; + } + + return true; +} + +static bool apply_xip_cmd_length(const struct mspi_dw_data *dev_data, + struct xip_ctrl *ctrl) +{ + uint8_t cmd_length = dev_data->xip_params_active.cmd_length; + + switch (cmd_length) { + case 0: + ctrl->read |= FIELD_PREP(XIP_CTRL_INST_L_MASK, + XIP_CTRL_INST_L0); + ctrl->write |= FIELD_PREP(XIP_WRITE_CTRL_INST_L_MASK, + XIP_WRITE_CTRL_INST_L0); + break; + case 1: + ctrl->read |= XIP_CTRL_INST_EN_BIT + | FIELD_PREP(XIP_CTRL_INST_L_MASK, + XIP_CTRL_INST_L8); + ctrl->write |= FIELD_PREP(XIP_WRITE_CTRL_INST_L_MASK, + XIP_WRITE_CTRL_INST_L8); + break; + case 2: + ctrl->read |= XIP_CTRL_INST_EN_BIT + | FIELD_PREP(XIP_CTRL_INST_L_MASK, + XIP_CTRL_INST_L16); + ctrl->write |= FIELD_PREP(XIP_WRITE_CTRL_INST_L_MASK, + XIP_WRITE_CTRL_INST_L16); + break; + default: + LOG_ERR("Command length %d not supported", cmd_length); + return false; + } + + return true; +} + +static bool apply_xip_addr_length(const struct mspi_dw_data *dev_data, + struct xip_ctrl *ctrl) +{ + uint8_t addr_length = dev_data->xip_params_active.addr_length; + + ctrl->read |= FIELD_PREP(XIP_CTRL_ADDR_L_MASK, addr_length * 2); + ctrl->write |= FIELD_PREP(XIP_WRITE_CTRL_ADDR_L_MASK, addr_length * 2); + + return true; +} +#endif /* defined(CONFIG_MSPI_XIP) */ + +static int _api_dev_config(const struct device *dev, + const enum mspi_dev_cfg_mask param_mask, + const struct mspi_dev_cfg *cfg) +{ + const struct mspi_dw_config *dev_config = dev->config; + struct mspi_dw_data *dev_data = dev->data; + + if (param_mask & MSPI_DEVICE_CONFIG_ENDIAN) { + if (cfg->endian != MSPI_XFER_BIG_ENDIAN) { + LOG_ERR("Only big endian transfers are supported."); + return -ENOTSUP; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_CE_POL) { + if (cfg->ce_polarity != MSPI_CE_ACTIVE_LOW) { + LOG_ERR("Only active low CE is supported."); + return -ENOTSUP; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_MEM_BOUND) { + if (cfg->mem_boundary) { + LOG_ERR("Auto CE break is not supported."); + return -ENOTSUP; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_BREAK_TIME) { + if (cfg->time_to_break) { + LOG_ERR("Auto CE break is not supported."); + return -ENOTSUP; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_IO_MODE) { +#if defined(CONFIG_MSPI_XIP) + dev_data->xip_params_stored.io_mode = cfg->io_mode; +#endif + + if (!apply_io_mode(dev_data, cfg->io_mode)) { + return -EINVAL; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_CPP) { +#if defined(CONFIG_MSPI_XIP) + /* Make sure the new setting is compatible with the one used + * for XIP if it is enabled. + */ + if (!dev_data->xip_enabled) { + dev_data->xip_cpp = cfg->cpp; + } else if (dev_data->xip_cpp != cfg->cpp) { + LOG_ERR("Conflict with configuration used for XIP."); + return -EINVAL; + } +#endif + + dev_data->ctrlr0 &= ~(CTRLR0_SCPOL_BIT | CTRLR0_SCPH_BIT); + + switch (cfg->cpp) { + default: + case MSPI_CPP_MODE_0: + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_SCPOL_BIT, 0) | + FIELD_PREP(CTRLR0_SCPH_BIT, 0); + break; + case MSPI_CPP_MODE_1: + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_SCPOL_BIT, 0) | + FIELD_PREP(CTRLR0_SCPH_BIT, 1); + break; + case MSPI_CPP_MODE_2: + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_SCPOL_BIT, 1) | + FIELD_PREP(CTRLR0_SCPH_BIT, 0); + break; + case MSPI_CPP_MODE_3: + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_SCPOL_BIT, 1) | + FIELD_PREP(CTRLR0_SCPH_BIT, 1); + break; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_FREQUENCY) { + if (cfg->freq > dev_config->clock_frequency / 2 || + cfg->freq < dev_config->clock_frequency / 65534) { + LOG_ERR("Invalid frequency: %u, MIN: %u, MAX: %u", + cfg->freq, dev_config->clock_frequency / 65534, + dev_config->clock_frequency / 2); + return -EINVAL; + } + +#if defined(CONFIG_MSPI_XIP) + /* Make sure the new setting is compatible with the one used + * for XIP if it is enabled. + */ + if (!dev_data->xip_enabled) { + dev_data->xip_freq = cfg->freq; + } else if (dev_data->xip_freq != cfg->freq) { + LOG_ERR("Conflict with configuration used for XIP."); + return -EINVAL; + } +#endif + + dev_data->baudr = dev_config->clock_frequency / cfg->freq; + } + + if (param_mask & MSPI_DEVICE_CONFIG_DATA_RATE) { + /* TODO: add support for DDR */ + if (cfg->data_rate != MSPI_DATA_RATE_SINGLE) { + LOG_ERR("Only single data rate is supported."); + return -ENOTSUP; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_DQS) { + /* TODO: add support for DQS */ + if (cfg->dqs_enable) { + LOG_ERR("DQS line is not supported."); + return -ENOTSUP; + } + } + +#if defined(CONFIG_MSPI_XIP) + if (param_mask & MSPI_DEVICE_CONFIG_READ_CMD) { + dev_data->xip_params_stored.read_cmd = cfg->read_cmd; + } + if (param_mask & MSPI_DEVICE_CONFIG_WRITE_CMD) { + dev_data->xip_params_stored.write_cmd = cfg->write_cmd; + } + if (param_mask & MSPI_DEVICE_CONFIG_RX_DUMMY) { + dev_data->xip_params_stored.rx_dummy = cfg->rx_dummy; + } + if (param_mask & MSPI_DEVICE_CONFIG_TX_DUMMY) { + dev_data->xip_params_stored.tx_dummy = cfg->tx_dummy; + } + if (param_mask & MSPI_DEVICE_CONFIG_CMD_LEN) { + dev_data->xip_params_stored.cmd_length = cfg->cmd_length; + } + if (param_mask & MSPI_DEVICE_CONFIG_ADDR_LEN) { + dev_data->xip_params_stored.addr_length = cfg->addr_length; + } +#endif + + /* Always use Motorola SPI frame format. */ + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_FRF_MASK, CTRLR0_FRF_SPI); + /* Enable clock stretching. */ + dev_data->spi_ctrlr0 |= SPI_CTRLR0_CLK_STRETCH_EN_BIT; + + return 0; +} + +static int api_dev_config(const struct device *dev, + const struct mspi_dev_id *dev_id, + const enum mspi_dev_cfg_mask param_mask, + const struct mspi_dev_cfg *cfg) +{ + struct mspi_dw_data *dev_data = dev->data; + int rc; + + if (dev_id != dev_data->dev_id) { + rc = k_sem_take(&dev_data->cfg_lock, + K_MSEC(CONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE)); + if (rc < 0) { + LOG_ERR("Failed to switch controller to device"); + return -EBUSY; + } + + dev_data->dev_id = dev_id; + + if (param_mask == MSPI_DEVICE_CONFIG_NONE) { + return 0; + } + } + + (void)k_sem_take(&dev_data->ctx_lock, K_FOREVER); + + rc = _api_dev_config(dev, param_mask, cfg); + + k_sem_give(&dev_data->ctx_lock); + + if (rc < 0) { + dev_data->dev_id = NULL; + k_sem_give(&dev_data->cfg_lock); + } + + return rc; +} + +static int api_get_channel_status(const struct device *dev, uint8_t ch) +{ + ARG_UNUSED(ch); + + struct mspi_dw_data *dev_data = dev->data; + + (void)k_sem_take(&dev_data->ctx_lock, K_FOREVER); + + dev_data->dev_id = NULL; + k_sem_give(&dev_data->cfg_lock); + + k_sem_give(&dev_data->ctx_lock); + + return 0; +} + +static void tx_control_field(const struct device *dev, + uint32_t field, uint8_t len) +{ + uint8_t shift = 8 * len; + + do { + shift -= 8; + write_dr(dev, field >> shift); + } while (shift); +} + +static int start_next_packet(const struct device *dev, k_timeout_t timeout) +{ + const struct mspi_dw_config *dev_config = dev->config; + struct mspi_dw_data *dev_data = dev->data; + const struct mspi_xfer_packet *packet = + &dev_data->xfer.packets[dev_data->packets_done]; + bool xip_enabled = COND_CODE_1(CONFIG_MSPI_XIP, + (dev_data->xip_enabled != 0), + (false)); + unsigned int key; + uint8_t tx_fifo_threshold; + uint32_t packet_frames; + uint32_t imr; + int rc = 0; + + if (packet->num_bytes == 0 && + dev_data->xfer.cmd_length == 0 && + dev_data->xfer.addr_length == 0) { + return 0; + } + + dev_data->dummy_bytes = 0; + + dev_data->ctrlr0 &= ~CTRLR0_TMOD_MASK + & ~CTRLR0_DFS_MASK; + + dev_data->spi_ctrlr0 &= ~SPI_CTRLR0_WAIT_CYCLES_MASK; + + if (dev_data->standard_spi && + (dev_data->xfer.cmd_length != 0 || + dev_data->xfer.addr_length != 0)) { + dev_data->bytes_per_frame_exp = 0; + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS_MASK, 7); + } else { + if ((packet->num_bytes % 4) == 0) { + dev_data->bytes_per_frame_exp = 2; + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS_MASK, 31); + } else if ((packet->num_bytes % 2) == 0) { + dev_data->bytes_per_frame_exp = 1; + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS_MASK, 15); + } else { + dev_data->bytes_per_frame_exp = 0; + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_DFS_MASK, 7); + } + } + + packet_frames = packet->num_bytes >> dev_data->bytes_per_frame_exp; + + if (packet_frames > UINT16_MAX + 1) { + LOG_ERR("Packet length (%u) exceeds supported maximum", + packet->num_bytes); + return -EINVAL; + } + + if (packet->dir == MSPI_TX || packet->num_bytes == 0) { + imr = IMR_TXEIM_BIT; + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_TMOD_MASK, + CTRLR0_TMOD_TX); + dev_data->spi_ctrlr0 |= FIELD_PREP(SPI_CTRLR0_WAIT_CYCLES_MASK, + dev_data->xfer.tx_dummy); + + write_rxftlr(dev, 0); + tx_fifo_threshold = dev_config->tx_fifo_threshold; + } else { + uint32_t tmod; + uint8_t rx_fifo_threshold; + + /* In Standard SPI Mode, the controller does not support + * sending the command and address fields separately, they + * need to be sent as data; hence, for RX packets with these + * fields, the TX/RX transfer mode needs to be used and + * consequently, dummy bytes need to be transmitted so that + * clock cycles for the RX part are provided (the controller + * does not do it automatically in the TX/RX mode). + */ + if (dev_data->standard_spi && + (dev_data->xfer.cmd_length != 0 || + dev_data->xfer.addr_length != 0)) { + uint32_t rx_total_bytes; + + dev_data->bytes_to_discard = dev_data->xfer.cmd_length + + dev_data->xfer.addr_length; + rx_total_bytes = dev_data->bytes_to_discard + + packet->num_bytes; + + dev_data->dummy_bytes = packet->num_bytes; + + imr = IMR_TXEIM_BIT | IMR_RXFIM_BIT; + tmod = CTRLR0_TMOD_TX_RX; + tx_fifo_threshold = dev_config->tx_fifo_threshold; + /* For standard SPI, only 1-byte frames are used. */ + rx_fifo_threshold = MIN(rx_total_bytes - 1, + dev_config->rx_fifo_threshold); + } else { + imr = IMR_RXFIM_BIT; + tmod = CTRLR0_TMOD_RX; + tx_fifo_threshold = 0; + rx_fifo_threshold = MIN(packet_frames - 1, + dev_config->rx_fifo_threshold); + } + + dev_data->ctrlr0 |= FIELD_PREP(CTRLR0_TMOD_MASK, tmod); + dev_data->spi_ctrlr0 |= FIELD_PREP(SPI_CTRLR0_WAIT_CYCLES_MASK, + dev_data->xfer.rx_dummy); + + write_rxftlr(dev, FIELD_PREP(RXFTLR_RFT_MASK, + rx_fifo_threshold)); + } + + if (dev_data->dev_id->ce.port) { + rc = gpio_pin_set_dt(&dev_data->dev_id->ce, 1); + if (rc < 0) { + LOG_ERR("Failed to activate CE line (%d)", rc); + return rc; + } + } + + if (xip_enabled) { + key = irq_lock(); + write_ssienr(dev, 0); + } + + /* These registers cannot be written when the controller is enabled, + * that's why it is temporarily disabled above; with locked interrupts, + * to prevent potential XIP transfers during that period. + */ + write_ctrlr0(dev, dev_data->ctrlr0); + write_ctrlr1(dev, packet_frames > 0 + ? FIELD_PREP(CTRLR1_NDF_MASK, packet_frames - 1) + : 0); + write_spi_ctrlr0(dev, dev_data->spi_ctrlr0); + write_baudr(dev, dev_data->baudr); + write_ser(dev, BIT(dev_data->dev_id->dev_idx)); + + if (xip_enabled) { + write_ssienr(dev, SSIENR_SSIC_EN_BIT); + irq_unlock(key); + } + + dev_data->buf_pos = packet->data_buf; + dev_data->buf_end = &packet->data_buf[packet->num_bytes]; + + if ((imr & IMR_TXEIM_BIT) && dev_data->buf_pos < dev_data->buf_end) { + uint32_t start_level = tx_fifo_threshold; + + if (dev_data->dummy_bytes) { + uint32_t tx_total = dev_data->bytes_to_discard + + dev_data->dummy_bytes; + + if (start_level > tx_total - 1) { + start_level = tx_total - 1; + } + } + + write_txftlr(dev, + FIELD_PREP(TXFTLR_TXFTHR_MASK, start_level) | + FIELD_PREP(TXFTLR_TFT_MASK, tx_fifo_threshold)); + } else { + write_txftlr(dev, 0); + } + + /* Ensure that there will be no interrupt from the controller yet. */ + write_imr(dev, 0); + /* Enable the controller. This must be done before DR is written. */ + write_ssienr(dev, SSIENR_SSIC_EN_BIT); + + if (dev_data->standard_spi) { + if (dev_data->xfer.cmd_length) { + tx_control_field(dev, packet->cmd, + dev_data->xfer.cmd_length); + } + + if (dev_data->xfer.addr_length) { + tx_control_field(dev, packet->address, + dev_data->xfer.addr_length); + } + } else { + if (dev_data->xfer.cmd_length) { + write_dr(dev, packet->cmd); + } + + if (dev_data->xfer.addr_length) { + write_dr(dev, packet->address); + } + } + + if (dev_data->dummy_bytes) { + if (make_rx_cycles(dev)) { + imr = IMR_RXFIM_BIT; + } + } else if (packet->dir == MSPI_TX && packet->num_bytes) { + tx_data(dev, packet); + } + + /* Enable interrupts now and wait until the packet is done. */ + write_imr(dev, imr); + + rc = k_sem_take(&dev_data->finished, timeout); + if (rc < 0) { + rc = -ETIMEDOUT; + } + + /* Disable the controller. This will immediately halt the transfer + * if it hasn't finished yet. + */ + if (xip_enabled) { + /* If XIP is enabled, the controller must be kept enabled, + * so disable it only momentarily if there's a need to halt + * a transfer that has timeout out. + */ + if (rc == -ETIMEDOUT) { + key = irq_lock(); + + write_ssienr(dev, 0); + write_ssienr(dev, SSIENR_SSIC_EN_BIT); + + irq_unlock(key); + } + } else { + write_ssienr(dev, 0); + } + + if (dev_data->dev_id->ce.port) { + int rc2; + + /* Do not use `rc` to not overwrite potential timeout error. */ + rc2 = gpio_pin_set_dt(&dev_data->dev_id->ce, 0); + if (rc2 < 0) { + LOG_ERR("Failed to deactivate CE line (%d)", rc2); + return rc2; + } + } + + return rc; +} + +static int _api_transceive(const struct device *dev, + const struct mspi_xfer *req) +{ + struct mspi_dw_data *dev_data = dev->data; + int rc; + + dev_data->spi_ctrlr0 &= ~SPI_CTRLR0_WAIT_CYCLES_MASK + & ~SPI_CTRLR0_INST_L_MASK + & ~SPI_CTRLR0_ADDR_L_MASK; + + if (!apply_cmd_length(dev_data, req->cmd_length) || + !apply_addr_length(dev_data, req->addr_length)) { + return -EINVAL; + } + + if (dev_data->standard_spi && + (req->rx_dummy != 0 || req->tx_dummy != 0)) { + LOG_ERR("Dummy cycles unsupported in single line mode"); + return -EINVAL; + } else if (req->rx_dummy > SPI_CTRLR0_WAIT_CYCLES_MAX || + req->tx_dummy > SPI_CTRLR0_WAIT_CYCLES_MAX) { + LOG_ERR("Unsupported RX (%u) or TX (%u) dummy cycles", + req->rx_dummy, req->tx_dummy); + return -EINVAL; + } + + dev_data->xfer = *req; + + for (dev_data->packets_done = 0; + dev_data->packets_done < dev_data->xfer.num_packet; + dev_data->packets_done++) { + rc = start_next_packet(dev, K_MSEC(dev_data->xfer.timeout)); + if (rc < 0) { + return rc; + } + } + + return 0; +} + +static int api_transceive(const struct device *dev, + const struct mspi_dev_id *dev_id, + const struct mspi_xfer *req) +{ + struct mspi_dw_data *dev_data = dev->data; + int rc, rc2; + + if (dev_id != dev_data->dev_id) { + LOG_ERR("Controller is not configured for this device"); + return -EINVAL; + } + + /* TODO: add support for asynchronous transfers */ + if (req->async) { + LOG_ERR("Asynchronous transfers are not supported"); + return -ENOTSUP; + } + + rc = pm_device_runtime_get(dev); + if (rc < 0) { + LOG_ERR("pm_device_runtime_get() failed: %d", rc); + return rc; + } + + (void)k_sem_take(&dev_data->ctx_lock, K_FOREVER); + + rc = _api_transceive(dev, req); + + k_sem_give(&dev_data->ctx_lock); + + rc2 = pm_device_runtime_put(dev); + if (rc2 < 0) { + LOG_ERR("pm_device_runtime_put() failed: %d", rc2); + rc = (rc < 0 ? rc : rc2); + } + + return rc; +} + +#if defined(CONFIG_MSPI_XIP) +static int _api_xip_config(const struct device *dev, + const struct mspi_dev_id *dev_id, + const struct mspi_xip_cfg *cfg) +{ + struct mspi_dw_data *dev_data = dev->data; + int rc; + + if (!cfg->enable) { + rc = vendor_specific_xip_disable(dev, dev_id, cfg); + if (rc < 0) { + return rc; + } + + dev_data->xip_enabled &= ~BIT(dev_id->dev_idx); + + if (!dev_data->xip_enabled) { + write_ssienr(dev, 0); + + /* Since XIP is disabled, it is okay for the controller + * to be suspended. + */ + rc = pm_device_runtime_put(dev); + if (rc < 0) { + LOG_ERR("pm_device_runtime_put() failed: %d", rc); + return rc; + } + } + + return 0; + } + + if (!dev_data->xip_enabled) { + struct xip_params *params = &dev_data->xip_params_active; + struct xip_ctrl ctrl = {0}; + + *params = dev_data->xip_params_stored; + + if (!apply_xip_io_mode(dev_data, &ctrl) || + !apply_xip_cmd_length(dev_data, &ctrl) || + !apply_xip_addr_length(dev_data, &ctrl)) { + return -EINVAL; + } + + if (params->rx_dummy > SPI_CTRLR0_WAIT_CYCLES_MAX || + params->tx_dummy > SPI_CTRLR0_WAIT_CYCLES_MAX) { + LOG_ERR("Unsupported RX (%u) or TX (%u) dummy cycles", + params->rx_dummy, params->tx_dummy); + return -EINVAL; + } + + /* Increase usage count additionally to prevent the controller + * from being suspended as long as XIP is active. + */ + rc = pm_device_runtime_get(dev); + if (rc < 0) { + LOG_ERR("pm_device_runtime_get() failed: %d", rc); + return rc; + } + + ctrl.read |= FIELD_PREP(XIP_CTRL_WAIT_CYCLES_MASK, + params->rx_dummy); + ctrl.write |= FIELD_PREP(XIP_WRITE_CTRL_WAIT_CYCLES_MASK, + params->tx_dummy); + + /* Make sure the baud rate and serial clock phase/polarity + * registers are configured properly. They may not be if + * non-XIP transfers have not been performed yet. + */ + write_ctrlr0(dev, dev_data->ctrlr0); + write_baudr(dev, dev_data->baudr); + + write_xip_incr_inst(dev, params->read_cmd); + write_xip_wrap_inst(dev, params->read_cmd); + write_xip_ctrl(dev, ctrl.read); + write_xip_write_incr_inst(dev, params->write_cmd); + write_xip_write_wrap_inst(dev, params->write_cmd); + write_xip_write_ctrl(dev, ctrl.write); + } else if (dev_data->xip_params_active.read_cmd != + dev_data->xip_params_stored.read_cmd || + dev_data->xip_params_active.write_cmd != + dev_data->xip_params_stored.write_cmd || + dev_data->xip_params_active.cmd_length != + dev_data->xip_params_stored.cmd_length || + dev_data->xip_params_active.addr_length != + dev_data->xip_params_stored.addr_length || + dev_data->xip_params_active.rx_dummy != + dev_data->xip_params_stored.rx_dummy || + dev_data->xip_params_active.tx_dummy != + dev_data->xip_params_stored.tx_dummy) { + LOG_ERR("Conflict with configuration already used for XIP."); + return -EINVAL; + } + + rc = vendor_specific_xip_enable(dev, dev_id, cfg); + if (rc < 0) { + return rc; + } + + write_ssienr(dev, SSIENR_SSIC_EN_BIT); + + dev_data->xip_enabled |= BIT(dev_id->dev_idx); + + return 0; +} + +static int api_xip_config(const struct device *dev, + const struct mspi_dev_id *dev_id, + const struct mspi_xip_cfg *cfg) +{ + struct mspi_dw_data *dev_data = dev->data; + int rc, rc2; + + if (cfg->enable && dev_id != dev_data->dev_id) { + LOG_ERR("Controller is not configured for this device"); + return -EINVAL; + } + + rc = pm_device_runtime_get(dev); + if (rc < 0) { + LOG_ERR("pm_device_runtime_get() failed: %d", rc); + return rc; + } + + (void)k_sem_take(&dev_data->ctx_lock, K_FOREVER); + + rc = _api_xip_config(dev, dev_id, cfg); + + k_sem_give(&dev_data->ctx_lock); + + rc2 = pm_device_runtime_put(dev); + if (rc2 < 0) { + LOG_ERR("pm_device_runtime_put() failed: %d", rc2); + rc = (rc < 0 ? rc : rc2); + } + + return rc; +} +#endif /* defined(CONFIG_MSPI_XIP) */ + +static int dev_pm_action_cb(const struct device *dev, + enum pm_device_action action) +{ + struct mspi_dw_data *dev_data = dev->data; + + if (action == PM_DEVICE_ACTION_RESUME) { +#if defined(CONFIG_PINCTRL) + const struct mspi_dw_config *dev_config = dev->config; + int rc = pinctrl_apply_state(dev_config->pcfg, + PINCTRL_STATE_DEFAULT); + + if (rc < 0) { + LOG_ERR("Cannot apply default pins state (%d)", rc); + return rc; + } +#endif + vendor_specific_resume(dev); + + k_sem_give(&dev_data->ctx_lock); + + return 0; + } + + if (IS_ENABLED(CONFIG_PM_DEVICE) && + action == PM_DEVICE_ACTION_SUSPEND) { + bool xip_enabled = COND_CODE_1(CONFIG_MSPI_XIP, + (dev_data->xip_enabled != 0), + (false)); + +#if defined(CONFIG_PINCTRL) + const struct mspi_dw_config *dev_config = dev->config; + int rc = pinctrl_apply_state(dev_config->pcfg, + PINCTRL_STATE_SLEEP); + + if (rc < 0) { + LOG_ERR("Cannot apply sleep pins state (%d)", rc); + return rc; + } +#endif + if (xip_enabled || + k_sem_take(&dev_data->ctx_lock, K_NO_WAIT) != 0) { + LOG_ERR("Controller in use, cannot be suspended"); + return -EBUSY; + } + + vendor_specific_suspend(dev); + + return 0; + } + + return -ENOTSUP; +} + +static int dev_init(const struct device *dev) +{ + struct mspi_dw_data *dev_data = dev->data; + const struct mspi_dw_config *dev_config = dev->config; + const struct gpio_dt_spec *ce_gpio; + int rc; + + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + + vendor_specific_init(dev); + + dev_config->irq_config(); + + k_sem_init(&dev_data->finished, 0, 1); + k_sem_init(&dev_data->cfg_lock, 1, 1); + /* This semaphore will be set to 1 after the device is resumed. */ + k_sem_init(&dev_data->ctx_lock, 0, 1); + + for (ce_gpio = dev_config->ce_gpios; + ce_gpio < &dev_config->ce_gpios[dev_config->ce_gpios_len]; + ce_gpio++) { + if (!device_is_ready(ce_gpio->port)) { + LOG_ERR("CE GPIO port %s is not ready", + ce_gpio->port->name); + return -ENODEV; + } + + rc = gpio_pin_configure_dt(ce_gpio, GPIO_OUTPUT_INACTIVE); + if (rc < 0) { + return rc; + } + } + +#if defined(CONFIG_PINCTRL) + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + rc = pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_SLEEP); + if (rc < 0) { + LOG_ERR("Cannot apply sleep pins state (%d)", rc); + return rc; + } + } +#endif + + return pm_device_driver_init(dev, dev_pm_action_cb); +} + +static const struct mspi_driver_api drv_api = { + .config = api_config, + .dev_config = api_dev_config, + .get_channel_status = api_get_channel_status, + .transceive = api_transceive, +#if defined(CONFIG_MSPI_XIP) + .xip_config = api_xip_config, +#endif +}; + +#define MSPI_DW_INST_IRQ(idx, inst) \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(inst, idx, irq), \ + DT_INST_IRQ_BY_IDX(inst, idx, priority), \ + mspi_dw_isr, DEVICE_DT_INST_GET(inst), 0); \ + irq_enable(DT_INST_IRQ_BY_IDX(inst, idx, irq)) + +#define MSPI_DW_MMIO_ROM_INIT(node_id) \ + COND_CODE_1(DT_REG_HAS_NAME(node_id, core), \ + (Z_DEVICE_MMIO_NAMED_ROM_INITIALIZER(core, node_id)), \ + (DEVICE_MMIO_ROM_INIT(node_id))) + +#define MSPI_DW_CLOCK_FREQUENCY(inst) \ + COND_CODE_1(DT_NODE_HAS_PROP(DT_INST_PHANDLE(inst, clocks), \ + clock_frequency), \ + (DT_INST_PROP_BY_PHANDLE(inst, clocks, \ + clock_frequency)), \ + (DT_INST_PROP(inst, clock_frequency))) + +#define MSPI_DW_DT_INST_PROP(inst, prop) .prop = DT_INST_PROP(inst, prop) + +#define FOREACH_CE_GPIOS_ELEM(inst) \ + DT_INST_FOREACH_PROP_ELEM_SEP(inst, ce_gpios, \ + GPIO_DT_SPEC_GET_BY_IDX, (,)) +#define MSPI_DW_CE_GPIOS(inst) \ + .ce_gpios = (const struct gpio_dt_spec []) \ + { FOREACH_CE_GPIOS_ELEM(inst) }, \ + .ce_gpios_len = DT_INST_PROP_LEN(inst, ce_gpios) + +#define TX_FIFO_DEPTH(inst) DT_INST_PROP(inst, fifo_depth) +#define RX_FIFO_DEPTH(inst) DT_INST_PROP_OR(inst, rx_fifo_depth, \ + TX_FIFO_DEPTH(inst)) +#define MSPI_DW_FIFO_PROPS(inst) \ + .tx_fifo_depth_minus_1 = TX_FIFO_DEPTH(inst) - 1, \ + .tx_fifo_threshold = \ + DT_INST_PROP_OR(inst, tx_fifo_threshold, \ + 7 * TX_FIFO_DEPTH(inst) / 8 - 1), \ + .rx_fifo_threshold = \ + DT_INST_PROP_OR(inst, rx_fifo_threshold, \ + 1 * RX_FIFO_DEPTH(inst) / 8 - 1) + +#define MSPI_DW_INST(inst) \ + PM_DEVICE_DT_INST_DEFINE(inst, dev_pm_action_cb); \ + IF_ENABLED(CONFIG_PINCTRL, (PINCTRL_DT_INST_DEFINE(inst);)) \ + static void irq_config##inst(void) \ + { \ + LISTIFY(DT_INST_NUM_IRQS(inst), \ + MSPI_DW_INST_IRQ, (;), inst); \ + } \ + static struct mspi_dw_data dev##inst##_data; \ + static const struct mspi_dw_config dev##inst##_config = { \ + MSPI_DW_MMIO_ROM_INIT(DT_DRV_INST(inst)), \ + .irq_config = irq_config##inst, \ + .clock_frequency = MSPI_DW_CLOCK_FREQUENCY(inst), \ + IF_ENABLED(CONFIG_PINCTRL, \ + (.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst),)) \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, ce_gpios), \ + (MSPI_DW_CE_GPIOS(inst),)) \ + MSPI_DW_FIFO_PROPS(inst), \ + DEFINE_REG_ACCESS(inst) \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + dev_init, PM_DEVICE_DT_INST_GET(inst), \ + &dev##inst##_data, &dev##inst##_config, \ + POST_KERNEL, CONFIG_MSPI_INIT_PRIORITY, \ + &drv_api); + +DT_INST_FOREACH_STATUS_OKAY(MSPI_DW_INST) diff --git a/drivers/mspi/mspi_dw.h b/drivers/mspi/mspi_dw.h new file mode 100644 index 00000000000..6f4a2c5a981 --- /dev/null +++ b/drivers/mspi/mspi_dw.h @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This file is a part of mspi_dw.c extracted only for clarity. + * It is not supposed to be included by any file other than mspi_dw.c. + */ + +/* CTRLR0 - Control Register 0 */ +#define CTRLR0_SPI_FRF_MASK GENMASK(23, 22) +#define CTRLR0_SPI_FRF_STANDARD 0UL +#define CTRLR0_SPI_FRF_DUAL 1UL +#define CTRLR0_SPI_FRF_QUAD 2UL +#define CTRLR0_SPI_FRF_OCTAL 3UL +#define CTRLR0_TMOD_MASK GENMASK(11, 10) +#define CTRLR0_TMOD_TX_RX 0UL +#define CTRLR0_TMOD_TX 1UL +#define CTRLR0_TMOD_RX 2UL +#define CTRLR0_TMOD_EEPROM 3UL +#define CTRLR0_SCPOL_BIT BIT(9) +#define CTRLR0_SCPH_BIT BIT(8) +#define CTRLR0_FRF_MASK GENMASK(7, 6) +#define CTRLR0_FRF_SPI 0UL +#define CTRLR0_FRF_SSP 1UL +#define CTRLR0_FRF_MICROWIRE 2UL +#define CTRLR0_DFS_MASK GENMASK(4, 0) + +/* CTRLR1- Control Register 1 */ +#define CTRLR1_NDF_MASK GENMASK(15, 0) + +/* SSIENR - SSI Enable Register */ +#define SSIENR_SSIC_EN_BIT BIT(0) + +/* TXFTLR - Transmit FIFO Threshold Level */ +#define TXFTLR_TXFTHR_MASK GENMASK(23, 16) +#define TXFTLR_TFT_MASK GENMASK(7, 0) + +/* RXFTLR - Receive FIFO Threshold Level */ +#define RXFTLR_RFT_MASK GENMASK(7, 0) + +/* TXFLR - Transmit FIFO Level Register */ +#define TXFLR_TXTFL_MASK GENMASK(7, 0) + +/* RXFLR - Receive FIFO Level Register */ +#define RXFLR_RXTFL_MASK GENMASK(7, 0) + +/* SR - Status Register */ +#define SR_BUSY_BIT BIT(0) + +/* IMR - Interrupt Mask Register */ +#define IMR_TXEIM_BIT BIT(0) +#define IMR_TXOIM_BIT BIT(1) +#define IMR_RXUIM_BIT BIT(2) +#define IMR_RXOIM_BIT BIT(3) +#define IMR_RXFIM_BIT BIT(4) +#define IMR_MSTIM_BIT BIT(5) + +/* ISR - Interrupt Status Register */ +#define ISR_TXEIS_BIT BIT(0) +#define ISR_TXOIS_BIT BIT(1) +#define ISR_RXUIS_BIT BIT(2) +#define ISR_RXOIS_BIT BIT(3) +#define ISR_RXFIS_BIT BIT(4) +#define ISR_MSTIS_BIT BIT(5) + +/* SPI_CTRLR0 - SPI Control Register */ +#define SPI_CTRLR0_CLK_STRETCH_EN_BIT BIT(30) +#define SPI_CTRLR0_XIP_PREFETCH_EN_BIT BIT(29) +#define SPI_CTRLR0_XIP_MBL_BIT BIT(26) +#define SPI_CTRLR0_SPI_RXDS_SIG_EN_BIT BIT(25) +#define SPI_CTRLR0_SPI_DM_EN_BIT BIT(24) +#define SPI_CTRLR0_RXDS_VL_EN_BIT BIT(23) +#define SPI_CTRLR0_SSIC_XIP_CONT_XFER_EN_BIT BIT(21) +#define SPI_CTRLR0_XIP_INST_EN_BIT BIT(20) +#define SPI_CTRLR0_XIP_DFS_HC_BIT BIT(19) +#define SPI_CTRLR0_SPI_RXDS_EN_BIT BIT(18) +#define SPI_CTRLR0_INST_DDR_EN_BIT BIT(17) +#define SPI_CTRLR0_SPI_DDR_EN_BIT BIT(16) +#define SPI_CTRLR0_WAIT_CYCLES_MASK GENMASK(15, 11) +#define SPI_CTRLR0_WAIT_CYCLES_MAX BIT_MASK(5) +#define SPI_CTRLR0_INST_L_MASK GENMASK(9, 8) +#define SPI_CTRLR0_INST_L0 0UL +#define SPI_CTRLR0_INST_L4 1UL +#define SPI_CTRLR0_INST_L8 2UL +#define SPI_CTRLR0_INST_L16 3UL +#define SPI_CTRLR0_XIP_MD_BIT_EN_BIT BIT(7) +#define SPI_CTRLR0_ADDR_L_MASK GENMASK(5, 2) +#define SPI_CTRLR0_TRANS_TYPE_MASK GENMASK(1, 0) +#define SPI_CTRLR0_TRANS_TYPE_TT0 0UL +#define SPI_CTRLR0_TRANS_TYPE_TT1 1UL +#define SPI_CTRLR0_TRANS_TYPE_TT2 2UL +#define SPI_CTRLR0_TRANS_TYPE_TT3 3UL + +/* XIP_CTRL - XIP Control Register */ +#define XIP_CTRL_XIP_PREFETCH_EN_BIT BIT(28) +#define XIP_CTRL_XIP_MBL_MASK GENMASK(27, 26) +#define XIP_CTRL_XIP_MBL_2 0UL +#define XIP_CTRL_XIP_MBL_4 1UL +#define XIP_CTRL_XIP_MBL_8 2UL +#define XIP_CTRL_XIP_MBL_16 3UL +#define XIP_CTRL_RXDS_SIG_EN_BIT BIT(25) +#define XIP_CTRL_XIP_HYBERBUS_EN_BIT BIT(24) +#define XIP_CTRL_CONT_XFER_EN_BIT BIT(23) +#define XIP_CTRL_INST_EN_BIT BIT(22) +#define XIP_CTRL_RXDS_EN_BIT BIT(21) +#define XIP_CTRL_INST_DDR_EN_BIT BIT(20) +#define XIP_CTRL_DDR_EN_BIT BIT(19) +#define XIP_CTRL_DFS_HC_BIT BIT(18) +#define XIP_CTRL_WAIT_CYCLES_MASK GENMASK(17, 13) +#define XIP_CTRL_WAIT_CYCLES_MAX BIT_MASK(5) +#define XIP_CTRL_MD_BITS_EN_BIT BIT(12) +#define XIP_CTRL_INST_L_MASK GENMASK(10, 9) +#define XIP_CTRL_INST_L0 0UL +#define XIP_CTRL_INST_L4 1UL +#define XIP_CTRL_INST_L8 2UL +#define XIP_CTRL_INST_L16 3UL +#define XIP_CTRL_ADDR_L_MASK GENMASK(7, 4) +#define XIP_CTRL_TRANS_TYPE_MASK GENMASK(3, 2) +#define XIP_CTRL_TRANS_TYPE_TT0 0UL +#define XIP_CTRL_TRANS_TYPE_TT1 1UL +#define XIP_CTRL_TRANS_TYPE_TT2 2UL +#define XIP_CTRL_FRF_MASK GENMASK(1, 0) +#define XIP_CTRL_FRF_DUAL 1UL +#define XIP_CTRL_FRF_QUAD 2UL +#define XIP_CTRL_FRF_OCTAL 3UL + +/* XIP_CTRL - XIP Control Register */ +#define XIP_CTRL_XIP_PREFETCH_EN_BIT BIT(28) +#define XIP_CTRL_XIP_MBL_MASK GENMASK(27, 26) +#define XIP_CTRL_XIP_MBL_2 0UL +#define XIP_CTRL_XIP_MBL_4 1UL +#define XIP_CTRL_XIP_MBL_8 2UL +#define XIP_CTRL_XIP_MBL_16 3UL +#define XIP_CTRL_XIP_HYBERBUS_EN_BIT BIT(24) +#define XIP_CTRL_CONT_XFER_EN_BIT BIT(23) +#define XIP_CTRL_INST_EN_BIT BIT(22) +#define XIP_CTRL_RXDS_EN_BIT BIT(21) +#define XIP_CTRL_INST_DDR_EN_BIT BIT(20) +#define XIP_CTRL_DDR_EN_BIT BIT(19) +#define XIP_CTRL_DFS_HC_BIT BIT(18) + +/* XIP_WRITE_CTRL - XIP Write Control Register */ +#define XIP_WRITE_CTRL_WAIT_CYCLES_MASK GENMASK(20, 16) +#define XIP_WRITE_CTRL_WAIT_CYCLES_MAX BIT_MASK(5) +#define XIP_WRITE_CTRL_RXDS_SIG_EN_BIT BIT(13) +#define XIP_WRITE_CTRL_HYBERBUS_EN_BIT BIT(12) +#define XIP_WRITE_CTRL_INST_DDR_EN_BIT BIT(11) +#define XIP_WRITE_CTRL_SPI_DDR_EN_BIT BIT(10) +#define XIP_WRITE_CTRL_INST_L_MASK GENMASK(9, 8) +#define XIP_WRITE_CTRL_INST_L0 0UL +#define XIP_WRITE_CTRL_INST_L4 1UL +#define XIP_WRITE_CTRL_INST_L8 2UL +#define XIP_WRITE_CTRL_INST_L16 3UL +#define XIP_WRITE_CTRL_ADDR_L_MASK GENMASK(7, 4) +#define XIP_WRITE_CTRL_TRANS_TYPE_MASK GENMASK(3, 2) +#define XIP_WRITE_CTRL_TRANS_TYPE_TT0 0UL +#define XIP_WRITE_CTRL_TRANS_TYPE_TT1 1UL +#define XIP_WRITE_CTRL_TRANS_TYPE_TT2 2UL +#define XIP_WRITE_CTRL_FRF_MASK GENMASK(1, 0) +#define XIP_WRITE_CTRL_FRF_DUAL 1UL +#define XIP_WRITE_CTRL_FRF_QUAD 2UL +#define XIP_WRITE_CTRL_FRF_OCTAL 3UL + +/* Register access helpers. */ +#define USES_AUX_REG(inst) + DT_INST_PROP(inst, aux_reg_enable) +#define AUX_REG_INSTANCES (0 DT_INST_FOREACH_STATUS_OKAY(USES_AUX_REG)) +#define BASE_ADDR(dev) (mm_reg_t)DEVICE_MMIO_GET(dev) + +#if AUX_REG_INSTANCES != 0 +static uint32_t aux_reg_read(const struct device *dev, uint32_t off) +{ + return sys_in32(BASE_ADDR(dev) + off/4); +} +static void aux_reg_write(uint32_t data, const struct device *dev, uint32_t off) +{ + sys_out32(data, BASE_ADDR(dev) + off/4); +} +#endif + +#if AUX_REG_INSTANCES != DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) +static uint32_t reg_read(const struct device *dev, uint32_t off) +{ + return sys_read32(BASE_ADDR(dev) + off); +} +static void reg_write(uint32_t data, const struct device *dev, uint32_t off) +{ + sys_write32(data, BASE_ADDR(dev) + off); +} +#endif + +#if AUX_REG_INSTANCES == 0 +/* If no instance uses aux-reg access. */ +#define DECLARE_REG_ACCESS() +#define DEFINE_REG_ACCESS(inst) +#define DEFINE_MM_REG_RD(reg, off) \ + static inline uint32_t read_##reg(const struct device *dev) \ + { return reg_read(dev, off); } +#define DEFINE_MM_REG_WR(reg, off) \ + static inline void write_##reg(const struct device *dev, uint32_t data) \ + { reg_write(data, dev, off); } + +#elif AUX_REG_INSTANCES == DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) +/* If all instances use aux-reg access. */ +#define DECLARE_REG_ACCESS() +#define DEFINE_REG_ACCESS(inst) +#define DEFINE_MM_REG_RD(reg, off) \ + static inline uint32_t read_##reg(const struct device *dev) \ + { return aux_reg_read(dev, off); } +#define DEFINE_MM_REG_WR(reg, off) \ + static inline void write_##reg(const struct device *dev, uint32_t data) \ + { aux_reg_write(data, dev, off); } + +#else +/* If register access varies by instance. */ +#define DECLARE_REG_ACCESS() \ + uint32_t (*read)(const struct device *dev, uint32_t off); \ + void (*write)(uint32_t data, const struct device *dev, uint32_t off) +#define DEFINE_REG_ACCESS(inst) \ + COND_CODE_1(DT_INST_PROP(inst, aux_reg_enable), \ + (.read = aux_reg_read, \ + .write = aux_reg_write,), \ + (.read = reg_read, \ + .write = reg_write,)) +#define DEFINE_MM_REG_RD(reg, off) \ + static inline uint32_t read_##reg(const struct device *dev) \ + { \ + const struct mspi_dw_config *dev_config = dev->config; \ + return dev_config->read(dev, off); \ + } +#define DEFINE_MM_REG_WR(reg, off) \ + static inline void write_##reg(const struct device *dev, uint32_t data) \ + { \ + const struct mspi_dw_config *dev_config = dev->config; \ + dev_config->write(data, dev, off); \ + } +#endif diff --git a/drivers/mspi/mspi_dw_vendor_specific.h b/drivers/mspi/mspi_dw_vendor_specific.h new file mode 100644 index 00000000000..7255f926fa8 --- /dev/null +++ b/drivers/mspi/mspi_dw_vendor_specific.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This file is a part of mspi_dw.c extracted only for clarity. + * It is not supposed to be included by any file other than mspi_dw.c. + */ + +#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_exmif) + +#include + +static void vendor_specific_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + NRF_EXMIF->EVENTS_CORE = 0; + NRF_EXMIF->INTENSET = BIT(EXMIF_INTENSET_CORE_Pos); +} + +static void vendor_specific_suspend(const struct device *dev) +{ + ARG_UNUSED(dev); + + NRF_EXMIF->TASKS_STOP = 1; +} + +static void vendor_specific_resume(const struct device *dev) +{ + ARG_UNUSED(dev); + + NRF_EXMIF->TASKS_START = 1; +} + +static void vendor_specific_irq_clear(const struct device *dev) +{ + ARG_UNUSED(dev); + + NRF_EXMIF->EVENTS_CORE = 0; +} + +#if defined(CONFIG_MSPI_XIP) +static int vendor_specific_xip_enable(const struct device *dev, + const struct mspi_dev_id *dev_id, + const struct mspi_xip_cfg *cfg) +{ + ARG_UNUSED(dev); + + if (dev_id->dev_idx == 0) { + NRF_EXMIF->EXTCONF1.OFFSET = cfg->address_offset; + NRF_EXMIF->EXTCONF1.SIZE = cfg->address_offset + + cfg->size - 1; + NRF_EXMIF->EXTCONF1.ENABLE = 1; + } else if (dev_id->dev_idx == 1) { + NRF_EXMIF->EXTCONF2.OFFSET = cfg->address_offset; + NRF_EXMIF->EXTCONF2.SIZE = cfg->address_offset + + cfg->size - 1; + NRF_EXMIF->EXTCONF2.ENABLE = 1; + } else { + return -EINVAL; + } + + return 0; +} + +static int vendor_specific_xip_disable(const struct device *dev, + const struct mspi_dev_id *dev_id, + const struct mspi_xip_cfg *cfg) +{ + ARG_UNUSED(dev); + + if (dev_id->dev_idx == 0) { + NRF_EXMIF->EXTCONF1.ENABLE = 0; + } else if (dev_id->dev_idx == 1) { + NRF_EXMIF->EXTCONF2.ENABLE = 0; + } else { + return -EINVAL; + } + + return 0; +} +#endif /* defined(CONFIG_MSPI_XIP) */ + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_exmif) */ diff --git a/drivers/pinctrl/pinctrl_nrf.c b/drivers/pinctrl/pinctrl_nrf.c index d0354f600a9..42c4f24559a 100644 --- a/drivers/pinctrl/pinctrl_nrf.c +++ b/drivers/pinctrl/pinctrl_nrf.c @@ -374,6 +374,24 @@ int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, input = NRF_GPIO_PIN_INPUT_CONNECT; break; #endif /* DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_can) */ +#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_exmif) + /* Pin routing is controlled by secure domain, via UICR */ + case NRF_FUN_EXMIF_CK: + case NRF_FUN_EXMIF_DQ0: + case NRF_FUN_EXMIF_DQ1: + case NRF_FUN_EXMIF_DQ2: + case NRF_FUN_EXMIF_DQ3: + case NRF_FUN_EXMIF_DQ4: + case NRF_FUN_EXMIF_DQ5: + case NRF_FUN_EXMIF_DQ6: + case NRF_FUN_EXMIF_DQ7: + case NRF_FUN_EXMIF_CS0: + case NRF_FUN_EXMIF_CS1: + case NRF_FUN_EXMIF_RWDS: + dir = NRF_GPIO_PIN_DIR_INPUT; + input = NRF_GPIO_PIN_INPUT_DISCONNECT; + break; +#endif /* DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_exmif) */ default: return -ENOTSUP; } diff --git a/drivers/spi/spi_dw.c b/drivers/spi/spi_dw.c index 5801c2744b4..649a13aca01 100644 --- a/drivers/spi/spi_dw.c +++ b/drivers/spi/spi_dw.c @@ -41,14 +41,6 @@ LOG_MODULE_REGISTER(spi_dw); #include #endif -#ifdef CONFIG_HAS_NRFX -#include -#endif - -#ifdef CONFIG_SOC_NRF54H20_GPD -#include -#endif - static inline bool spi_dw_is_slave(struct spi_dw_data *spi) { return (IS_ENABLED(CONFIG_SPI_SLAVE) && @@ -266,7 +258,6 @@ static int spi_dw_configure(const struct device *dev, /* Baud rate and Slave select, for master only */ write_baudr(dev, SPI_DW_CLK_DIVIDER(info->clock_frequency, config->frequency)); - write_ser(dev, BIT(config->slave)); } if (spi_dw_is_slave(spi)) { @@ -509,10 +500,6 @@ void spi_dw_isr(const struct device *dev) uint32_t int_status; int error; -#ifdef CONFIG_HAS_NRFX - NRF_EXMIF->EVENTS_CORE = 0; -#endif - int_status = read_isr(dev); LOG_DBG("SPI %p int_status 0x%x - (tx: %d, rx: %d)", dev, int_status, @@ -561,18 +548,6 @@ int spi_dw_init(const struct device *dev) DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); -#ifdef CONFIG_HAS_NRFX - NRF_EXMIF->INTENSET = BIT(0); - NRF_EXMIF->TASKS_START = 1; - -#ifdef CONFIG_SOC_NRF54H20_GPD - err = nrf_gpd_request(NRF_GPD_FAST_ACTIVE1); - if (err < 0) { - return err; - } -#endif -#endif - info->config_func(); /* Masking interrupt and making sure controller is disabled */ @@ -591,11 +566,6 @@ int spi_dw_init(const struct device *dev) return 0; } -#define REG_ADDR(inst) \ - COND_CODE_1(DT_NODE_HAS_COMPAT(DT_DRV_INST(inst), nordic_nrf_exmif), \ - (Z_DEVICE_MMIO_NAMED_ROM_INITIALIZER(core, DT_DRV_INST(inst))), \ - (DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)))) - #define SPI_CFG_IRQS_SINGLE_ERR_LINE(inst) \ IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, rx_avail, irq), \ DT_INST_IRQ_BY_NAME(inst, rx_avail, priority), \ @@ -668,7 +638,7 @@ COND_CODE_1(IS_EQ(DT_NUM_IRQS(DT_DRV_INST(inst)), 1), \ SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(inst), ctx) \ }; \ static const struct spi_dw_config spi_dw_config_##inst = { \ - REG_ADDR(inst), \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \ .clock_frequency = COND_CODE_1( \ DT_NODE_HAS_PROP(DT_INST_PHANDLE(inst, clocks), clock_frequency), \ (DT_INST_PROP_BY_PHANDLE(inst, clocks, clock_frequency)), \ diff --git a/dts/bindings/mspi/snps,designware-ssi.yaml b/dts/bindings/mspi/snps,designware-ssi.yaml new file mode 100644 index 00000000000..fb516cb7835 --- /dev/null +++ b/dts/bindings/mspi/snps,designware-ssi.yaml @@ -0,0 +1,45 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Synopsys DesignWare Synchronous Serial Interface (SSI) node + +compatible: "snps,designware-ssi" + +include: [mspi-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + aux-reg-enable: + type: boolean + description: | + Activates auxiliary register access that is needed on some platforms. + + fifo-depth: + required: true + type: int + description: | + Number of items that can be stored in the TX FIFO. Range: 8-256. + If the RX FIFO depth is not specified separately in the rx-fifo-depth + property, this value specifies depth of both TX and RX FIFOs. + + rx-fifo-depth: + type: int + description: | + Number of items that can be stored in the RX FIFO. Range: 8-256. + + tx-fifo-threshold: + type: int + description: | + Number of entries in the TX FIFO above which the TX transfer is started. + Maximum value is the TX FIFO depth - 1. + + rx-fifo-threshold: + type: int + description: | + Number of entries in the RX FIFO above which the controller gets an RX + interrupt. Maximum value is the RX FIFO depth - 1. diff --git a/dts/bindings/mtd/jedec,mspi-nor.yaml b/dts/bindings/mtd/jedec,mspi-nor.yaml new file mode 100644 index 00000000000..9da68b7dd49 --- /dev/null +++ b/dts/bindings/mtd/jedec,mspi-nor.yaml @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +description: Generic NOR flash on MSPI bus + +compatible: "jedec,mspi-nor" + +include: [mspi-device.yaml, "jedec,spi-nor-common.yaml"] + +properties: + reset-gpios: + type: phandle-array + description: RESETn pin diff --git a/dts/bindings/spi/nordic,nrf-exmif.yaml b/dts/bindings/spi/nordic,nrf-exmif.yaml index d2b8815046b..294254aa60e 100644 --- a/dts/bindings/spi/nordic,nrf-exmif.yaml +++ b/dts/bindings/spi/nordic,nrf-exmif.yaml @@ -5,8 +5,4 @@ description: Nordic External Memory Interface (EXMIF) compatible: "nordic,nrf-exmif" -include: snps,designware-spi.yaml - -properties: - reg: - required: true +include: snps,designware-ssi.yaml diff --git a/dts/common/nordic/nrf54h20.dtsi b/dts/common/nordic/nrf54h20.dtsi index 790785ebaaa..701d60765d2 100644 --- a/dts/common/nordic/nrf54h20.dtsi +++ b/dts/common/nordic/nrf54h20.dtsi @@ -509,8 +509,8 @@ status = "disabled"; }; - exmif: spi@95000 { - compatible = "nordic,nrf-exmif", "snps,designware-spi"; + exmif: exmif@95000 { + compatible = "nordic,nrf-exmif", "snps,designware-ssi"; #address-cells = <1>; #size-cells = <0>; reg = <0x95000 0x500 0x95500 0xb00>; @@ -519,7 +519,6 @@ power-domains = <&gpd NRF_GPD_FAST_ACTIVE0>; clock-frequency = ; fifo-depth = <32>; - max-xfer-size = <16>; status = "disabled"; }; diff --git a/dts/common/nordic/nrf9280.dtsi b/dts/common/nordic/nrf9280.dtsi index 62b22b4fbc2..c9e1742e102 100644 --- a/dts/common/nordic/nrf9280.dtsi +++ b/dts/common/nordic/nrf9280.dtsi @@ -360,8 +360,8 @@ status = "disabled"; }; - exmif: spi@95000 { - compatible = "nordic,nrf-exmif"; + exmif: exmif@95000 { + compatible = "nordic,nrf-exmif", "snps,designware-ssi"; #address-cells = <1>; #size-cells = <0>; reg = <0x95000 0x500 0x95500 0xb00>; @@ -369,7 +369,6 @@ interrupts = <149 NRF_DEFAULT_IRQ_PRIORITY>; clock-frequency = ; fifo-depth = <32>; - max-xfer-size = <16>; status = "disabled"; }; diff --git a/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h index a73f59c48b7..49c06f3668c 100644 --- a/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/nrf-pinctrl.h @@ -162,6 +162,8 @@ #define NRF_FUN_CAN_TX 46U /** CAN RX */ #define NRF_FUN_CAN_RX 47U +/** EXMIF RWDS */ +#define NRF_FUN_EXMIF_RWDS 50U /** GRTC fast clock output */ #define NRF_FUN_GRTC_CLKOUT_FAST 55U /** GRTC slow clock output */ diff --git a/samples/application_development/code_relocation_nocopy/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/samples/application_development/code_relocation_nocopy/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 00000000000..83035081389 --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1 @@ +CONFIG_FLASH=y diff --git a/samples/application_development/code_relocation_nocopy/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/samples/application_development/code_relocation_nocopy/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..ab53f12725d --- /dev/null +++ b/samples/application_development/code_relocation_nocopy/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,17 @@ +&cpuapp_ram0x_region { + nordic,access = ; +}; + +&xip_region { + status = "okay"; + nordic,access = ; +}; + +&mx25uw63 { + read-command = <0xEC13>; + command-length = "INSTR_2_BYTE"; + address-length = "ADDR_4_BYTE"; + rx-dummy = <20>; + + xip-config = <1 0 0x20000000 0>; +}; diff --git a/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld b/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld index a1467f8e264..0a11783cca2 100644 --- a/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld +++ b/samples/application_development/code_relocation_nocopy/linker_arm_nocopy.ld @@ -47,6 +47,13 @@ #define EXTFLASH_ADDR DT_REG_ADDR(DT_INST(0, st_stm32_xspi_nor)) #define EXTFLASH_SIZE DT_REG_ADDR_BY_IDX(DT_INST(0, st_stm32_xspi_nor), 1) +#elif defined(CONFIG_FLASH_MSPI_NOR) && defined(CONFIG_SOC_NRF54H20_CPUAPP) + +#define EXTFLASH_NODE DT_INST(0, jedec_mspi_nor) +#define EXTFLASH_ADDR 0x60000000 +#define EXTFLASH_SIZE DT_PROP_OR(EXTFLASH_NODE, size_in_bytes, \ + DT_PROP(EXTFLASH_NODE, size) / 8) + #else /* diff --git a/samples/drivers/jesd216/boards/bmd_345_eval.conf b/samples/drivers/jesd216/boards/bmd_345_eval.conf deleted file mode 100644 index 8c262a3483e..00000000000 --- a/samples/drivers/jesd216/boards/bmd_345_eval.conf +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2021 Linumiz -# -# SPDX-License-Identifier: Apache-2.0 - -CONFIG_SPI=n -CONFIG_SPI_NOR=n -CONFIG_NORDIC_QSPI_NOR=y diff --git a/samples/drivers/jesd216/boards/mr_canhubk3.conf b/samples/drivers/jesd216/boards/mr_canhubk3.conf deleted file mode 100644 index b625f401a1c..00000000000 --- a/samples/drivers/jesd216/boards/mr_canhubk3.conf +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2023 NXP -# SPDX-License-Identifier: Apache-2.0 - -# Override defaults for SPI NOR flash driver -CONFIG_SPI_NOR=n diff --git a/samples/drivers/jesd216/boards/nrf52840dk_nrf52840.conf b/samples/drivers/jesd216/boards/nrf52840dk_nrf52840.conf deleted file mode 100644 index 976830569e3..00000000000 --- a/samples/drivers/jesd216/boards/nrf52840dk_nrf52840.conf +++ /dev/null @@ -1,10 +0,0 @@ -# -# Copyright (c) 2019 Peter Bigot Consulting, LLC -# Copyright (c) 2019 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 -# - -CONFIG_SPI=n -CONFIG_SPI_NOR=n -#CONFIG_NORDIC_QSPI_NOR=y diff --git a/samples/drivers/jesd216/boards/nrf52840dk_nrf52840_spi.conf b/samples/drivers/jesd216/boards/nrf52840dk_nrf52840_spi.conf deleted file mode 100644 index 15982f1c92e..00000000000 --- a/samples/drivers/jesd216/boards/nrf52840dk_nrf52840_spi.conf +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2022 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 -# - -CONFIG_SPI=y -CONFIG_SPI_NOR=y diff --git a/samples/drivers/jesd216/prj.conf b/samples/drivers/jesd216/prj.conf index c5c747a3bb3..b1b51a1e12f 100644 --- a/samples/drivers/jesd216/prj.conf +++ b/samples/drivers/jesd216/prj.conf @@ -1,8 +1,3 @@ CONFIG_STDOUT_CONSOLE=y CONFIG_FLASH=y CONFIG_FLASH_JESD216_API=y - -# Assume the standard SPI NOR flash driver. If the device uses -# another driver add an override configuration in boards/. -CONFIG_SPI=y -CONFIG_SPI_NOR=y diff --git a/samples/drivers/jesd216/sample.yaml b/samples/drivers/jesd216/sample.yaml index afc3b200554..a7ff46ffd9e 100644 --- a/samples/drivers/jesd216/sample.yaml +++ b/samples/drivers/jesd216/sample.yaml @@ -19,12 +19,11 @@ tests: - hifive_unmatched - mimxrt1170_evk/mimxrt1176/cm7 - mimxrt1170_evk/mimxrt1176/cm4 - filter: dt_compat_enabled("jedec,spi-nor") + filter: dt_compat_enabled("jedec,spi-nor") or dt_compat_enabled("jedec,mspi-nor") depends_on: spi sample.drivers.jesd216.nrf52840dk_spi: extra_args: - DTC_OVERLAY_FILE=boards/nrf52840dk_nrf52840_spi.overlay - - EXTRA_CONF_FILE=boards/nrf52840dk_nrf52840_spi.conf platform_allow: nrf52840dk/nrf52840 integration_platforms: - nrf52840dk/nrf52840 diff --git a/samples/drivers/jesd216/src/main.c b/samples/drivers/jesd216/src/main.c index 480649397b6..b8dad485997 100644 --- a/samples/drivers/jesd216/src/main.c +++ b/samples/drivers/jesd216/src/main.c @@ -14,6 +14,8 @@ #if DT_HAS_COMPAT_STATUS_OKAY(jedec_spi_nor) #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(jedec_spi_nor) +#elif DT_HAS_COMPAT_STATUS_OKAY(jedec_mspi_nor) +#define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(jedec_mspi_nor) #elif DT_HAS_COMPAT_STATUS_OKAY(nordic_qspi_nor) #define FLASH_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(nordic_qspi_nor) #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_qspi_nor) @@ -201,7 +203,7 @@ static void summarize_dw15(const struct jesd216_param_header *php, printf("0-4-4 Mode methods: entry 0x%01x ; exit 0x%02x\n", dw15.entry_044, dw15.exit_044); } else { - printf("0-4-4 Mode: not supported"); + printf("0-4-4 Mode: not supported\n"); } printf("4-4-4 Mode sequences: enable 0x%02x ; disable 0x%01x\n", dw15.enable_444, dw15.disable_444); diff --git a/samples/drivers/spi_flash/boards/adafruit_feather_nrf52840_sense.conf b/samples/drivers/spi_flash/boards/adafruit_feather_nrf52840_sense.conf deleted file mode 100644 index d9add33645a..00000000000 --- a/samples/drivers/spi_flash/boards/adafruit_feather_nrf52840_sense.conf +++ /dev/null @@ -1,7 +0,0 @@ -# -# Copyright (c) 2020 Teslabs Engineering S.L. -# -# SPDX-License-Identifier: Apache-2.0 -# - -CONFIG_NORDIC_QSPI_NOR=y diff --git a/samples/drivers/spi_flash/boards/em_starterkit_emsk_em9d.conf b/samples/drivers/spi_flash/boards/em_starterkit_emsk_em9d.conf deleted file mode 100644 index 4e3bfcd17d5..00000000000 --- a/samples/drivers/spi_flash/boards/em_starterkit_emsk_em9d.conf +++ /dev/null @@ -1,7 +0,0 @@ -# -# Copyright (c) 2023 Synopsys. -# -# SPDX-License-Identifier: Apache-2.0 -# - -CONFIG_SPI_NOR=y diff --git a/samples/drivers/spi_flash/boards/emsdp_emsdp_em11d.conf b/samples/drivers/spi_flash/boards/emsdp_emsdp_em11d.conf deleted file mode 100644 index 4e3bfcd17d5..00000000000 --- a/samples/drivers/spi_flash/boards/emsdp_emsdp_em11d.conf +++ /dev/null @@ -1,7 +0,0 @@ -# -# Copyright (c) 2023 Synopsys. -# -# SPDX-License-Identifier: Apache-2.0 -# - -CONFIG_SPI_NOR=y diff --git a/samples/drivers/spi_flash/boards/mec172xevb_assy6906.conf b/samples/drivers/spi_flash/boards/mec172xevb_assy6906.conf deleted file mode 100644 index 38f06a0c0f8..00000000000 --- a/samples/drivers/spi_flash/boards/mec172xevb_assy6906.conf +++ /dev/null @@ -1,7 +0,0 @@ -# -# Copyright (c) 2022 Microchip Technology Inc. -# -# SPDX-License-Identifier: Apache-2.0 -# - -CONFIG_SPI_NOR=y diff --git a/samples/drivers/spi_flash/boards/nrf52840_mdk.conf b/samples/drivers/spi_flash/boards/nrf52840_mdk.conf deleted file mode 100644 index c17e6e08b39..00000000000 --- a/samples/drivers/spi_flash/boards/nrf52840_mdk.conf +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2020 Stephane D'Alu -# -# SPDX-License-Identifier: Apache-2.0 -# - -CONFIG_SPI=n -CONFIG_NORDIC_QSPI_NOR=y diff --git a/samples/drivers/spi_flash/boards/nrf52840dk_nrf52840.conf b/samples/drivers/spi_flash/boards/nrf52840dk_nrf52840.conf deleted file mode 100644 index c483efdb826..00000000000 --- a/samples/drivers/spi_flash/boards/nrf52840dk_nrf52840.conf +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2019 Peter Bigot Consulting, LLC -# Copyright (c) 2019 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 -# - -CONFIG_NORDIC_QSPI_NOR=y diff --git a/samples/drivers/spi_flash/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/drivers/spi_flash/boards/nrf5340dk_nrf5340_cpuapp.conf deleted file mode 100644 index 10239a8fd1b..00000000000 --- a/samples/drivers/spi_flash/boards/nrf5340dk_nrf5340_cpuapp.conf +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) 2020 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 -# - -CONFIG_SPI=n -CONFIG_NORDIC_QSPI_NOR=y diff --git a/samples/drivers/spi_flash/boards/stm32h735g_disco.conf b/samples/drivers/spi_flash/boards/stm32h735g_disco.conf deleted file mode 100644 index d073f9492d8..00000000000 --- a/samples/drivers/spi_flash/boards/stm32h735g_disco.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_SPI=n diff --git a/samples/drivers/spi_flash/boards/stm32h7b3i_dk.conf b/samples/drivers/spi_flash/boards/stm32h7b3i_dk.conf deleted file mode 100644 index d073f9492d8..00000000000 --- a/samples/drivers/spi_flash/boards/stm32h7b3i_dk.conf +++ /dev/null @@ -1 +0,0 @@ -CONFIG_SPI=n diff --git a/samples/drivers/spi_flash/prj.conf b/samples/drivers/spi_flash/prj.conf index c5beb21553a..d78e334e0fb 100644 --- a/samples/drivers/spi_flash/prj.conf +++ b/samples/drivers/spi_flash/prj.conf @@ -1,3 +1,2 @@ CONFIG_STDOUT_CONSOLE=y CONFIG_FLASH=y -CONFIG_SPI=y diff --git a/samples/drivers/spi_flash/sample.yaml b/samples/drivers/spi_flash/sample.yaml index 377c5ccec6e..351e33997a0 100644 --- a/samples/drivers/spi_flash/sample.yaml +++ b/samples/drivers/spi_flash/sample.yaml @@ -7,8 +7,10 @@ tests: - flash filter: dt_compat_enabled("jedec,spi-nor") or dt_compat_enabled("st,stm32-qspi-nor") or dt_compat_enabled("st,stm32-ospi-nor") or dt_compat_enabled("st,stm32-xspi-nor") - or (dt_compat_enabled("nordic,qspi-nor") and CONFIG_NORDIC_QSPI_NOR) - platform_exclude: hifive_unmatched + or dt_compat_enabled("nordic,qspi-nor") or dt_compat_enabled("jedec,mspi-nor") + platform_exclude: + - hifive_unmatched/fu740/s7 + - hifive_unmatched/fu740/u74 harness: console harness_config: type: multi_line diff --git a/samples/drivers/spi_flash/src/main.c b/samples/drivers/spi_flash/src/main.c index b84359ae05b..52e8b6062b5 100644 --- a/samples/drivers/spi_flash/src/main.c +++ b/samples/drivers/spi_flash/src/main.c @@ -34,6 +34,8 @@ #if DT_HAS_COMPAT_STATUS_OKAY(jedec_spi_nor) #define SPI_FLASH_COMPAT jedec_spi_nor +#elif DT_HAS_COMPAT_STATUS_OKAY(jedec_mspi_nor) +#define SPI_FLASH_COMPAT jedec_mspi_nor #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_qspi_nor) #define SPI_FLASH_COMPAT st_stm32_qspi_nor #elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_ospi_nor) diff --git a/tests/drivers/flash/common/prj.conf b/tests/drivers/flash/common/prj.conf index 2496d765165..cb0a271262c 100644 --- a/tests/drivers/flash/common/prj.conf +++ b/tests/drivers/flash/common/prj.conf @@ -3,3 +3,4 @@ CONFIG_ZTEST=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_ZTEST_STACK_SIZE=4096 diff --git a/tests/drivers/flash/common/src/main.c b/tests/drivers/flash/common/src/main.c index 9ca767943d9..66a5eba0297 100644 --- a/tests/drivers/flash/common/src/main.c +++ b/tests/drivers/flash/common/src/main.c @@ -14,6 +14,8 @@ #define TEST_AREA_DEV_NODE DT_INST(0, nordic_qspi_nor) #elif defined(CONFIG_SPI_NOR) #define TEST_AREA_DEV_NODE DT_INST(0, jedec_spi_nor) +#elif defined(CONFIG_FLASH_MSPI_NOR) +#define TEST_AREA_DEV_NODE DT_INST(0, jedec_mspi_nor) #else #define TEST_AREA storage_partition #endif