diff --git a/drivers/memc/CMakeLists.txt b/drivers/memc/CMakeLists.txt index a5f7266c9e2..af9400facca 100644 --- a/drivers/memc/CMakeLists.txt +++ b/drivers/memc/CMakeLists.txt @@ -5,6 +5,7 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_MEMC_STM32 memc_stm32.c) zephyr_library_sources_ifdef(CONFIG_MEMC_STM32_SDRAM memc_stm32_sdram.c) zephyr_linker_sources_ifdef(CONFIG_MEMC_STM32_SDRAM SECTIONS memc_stm32_sdram.ld) +zephyr_library_sources_ifdef(CONFIG_MEMC_STM32_NOR_PSRAM memc_stm32_nor_psram.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI memc_mcux_flexspi.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_HYPERRAM memc_mcux_flexspi_hyperram.c) diff --git a/drivers/memc/Kconfig.stm32 b/drivers/memc/Kconfig.stm32 index 83f2a2ae25c..1731859f1fe 100644 --- a/drivers/memc/Kconfig.stm32 +++ b/drivers/memc/Kconfig.stm32 @@ -19,3 +19,15 @@ config MEMC_STM32_SDRAM select USE_STM32_HAL_SDRAM help Enable STM32 FMC SDRAM controller. + +DT_COMPAT_ST_STM32_FMC_NOR_PSRAM := st,stm32-fmc-nor-psram + +config MEMC_STM32_NOR_PSRAM + bool "STM32 FMC NOR/PSRAM controller" + depends on MEMC_STM32 + default $(dt_compat_enabled,$(DT_COMPAT_ST_STM32_FMC_NOR_PSRAM)) + select USE_STM32_LL_FMC + select USE_STM32_HAL_NOR + select USE_STM32_HAL_SRAM + help + Enable STM32 FMC NOR/PSRAM controller. diff --git a/drivers/memc/memc_stm32_nor_psram.c b/drivers/memc/memc_stm32_nor_psram.c new file mode 100644 index 00000000000..06d7065cb9e --- /dev/null +++ b/drivers/memc/memc_stm32_nor_psram.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2022 Georgij Cernysiov + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT st_stm32_fmc_nor_psram + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(memc_stm32_nor_psram, CONFIG_MEMC_LOG_LEVEL); + +/** SRAM base register offset, see FMC_Bank1_R_BASE */ +#define SRAM_OFFSET 0x0000UL +/** SRAM extended mode register offset, see FMC_Bank1E_R_BASE */ +#define SRAM_EXT_OFFSET 0x0104UL + +/** FMC NOR/PSRAM controller bank configuration fields. */ +struct memc_stm32_nor_psram_bank_config { + FMC_NORSRAM_InitTypeDef init; + FMC_NORSRAM_TimingTypeDef timing; + FMC_NORSRAM_TimingTypeDef timing_ext; +}; + +/** FMC NOR/PSRAM controller configuration fields. */ +struct memc_stm32_nor_psram_config { + FMC_NORSRAM_TypeDef *nor_psram; + FMC_NORSRAM_EXTENDED_TypeDef *extended; + const struct memc_stm32_nor_psram_bank_config *banks; + size_t banks_len; +}; + +static int memc_stm32_nor_init(const struct memc_stm32_nor_psram_config *config, + const struct memc_stm32_nor_psram_bank_config *bank_config) +{ + FMC_NORSRAM_TimingTypeDef *ext_timing; + NOR_HandleTypeDef hnor = { 0 }; + + hnor.Instance = config->nor_psram; + hnor.Extended = config->extended; + + memcpy(&hnor.Init, &bank_config->init, sizeof(hnor.Init)); + + if (bank_config->init.ExtendedMode == FMC_EXTENDED_MODE_ENABLE) { + ext_timing = (FMC_NORSRAM_TimingTypeDef *)&bank_config->timing_ext; + } else { + ext_timing = NULL; + } + + if (HAL_NOR_Init(&hnor, + (FMC_NORSRAM_TimingTypeDef *)&bank_config->timing, + ext_timing) != HAL_OK) { + return -ENODEV; + } + + return 0; +} + +static int memc_stm32_psram_init(const struct memc_stm32_nor_psram_config *config, + const struct memc_stm32_nor_psram_bank_config *bank_config) +{ + FMC_NORSRAM_TimingTypeDef *ext_timing; + SRAM_HandleTypeDef hsram = { 0 }; + + hsram.Instance = config->nor_psram; + hsram.Extended = config->extended; + + memcpy(&hsram.Init, &bank_config->init, sizeof(hsram.Init)); + + if (bank_config->init.ExtendedMode == FMC_EXTENDED_MODE_ENABLE) { + ext_timing = (FMC_NORSRAM_TimingTypeDef *)&bank_config->timing_ext; + } else { + ext_timing = NULL; + } + + if (HAL_SRAM_Init(&hsram, + (FMC_NORSRAM_TimingTypeDef *)&bank_config->timing, + ext_timing) != HAL_OK) { + return -ENODEV; + } + + return 0; +} + +static int memc_stm32_nor_psram_init(const struct device *dev) +{ + const struct memc_stm32_nor_psram_config *config = dev->config; + uint32_t memory_type; + size_t bank_idx; + int ret = 0; + + for (bank_idx = 0U; bank_idx < config->banks_len; ++bank_idx) { + memory_type = config->banks[bank_idx].init.MemoryType; + + switch (memory_type) { + case FMC_MEMORY_TYPE_NOR: + ret = memc_stm32_nor_init(config, &config->banks[bank_idx]); + break; + case FMC_MEMORY_TYPE_PSRAM: + __fallthrough; + case FMC_MEMORY_TYPE_SRAM: + ret = memc_stm32_psram_init(config, &config->banks[bank_idx]); + break; + default: + ret = -ENOTSUP; + break; + } + + if (ret < 0) { + LOG_ERR("Unable to initialize memory type: " + "0x%08X, NSBank: %d, err: %d", + memory_type, config->banks[bank_idx].init.NSBank, ret); + goto end; + } + } + +end: + return ret; +} + +/** SDRAM bank/s configuration initialization macro. */ +#define BANK_CONFIG(node_id) \ + { .init = { \ + .NSBank = DT_REG_ADDR(node_id), \ + .DataAddressMux = DT_PROP_BY_IDX(node_id, st_control, 0), \ + .MemoryType = DT_PROP_BY_IDX(node_id, st_control, 1), \ + .MemoryDataWidth = DT_PROP_BY_IDX(node_id, st_control, 2), \ + .BurstAccessMode = DT_PROP_BY_IDX(node_id, st_control, 3), \ + .WaitSignalPolarity = DT_PROP_BY_IDX(node_id, st_control, 4), \ + .WaitSignalActive = DT_PROP_BY_IDX(node_id, st_control, 5), \ + .WriteOperation = DT_PROP_BY_IDX(node_id, st_control, 6), \ + .WaitSignal = DT_PROP_BY_IDX(node_id, st_control, 7), \ + .ExtendedMode = DT_PROP_BY_IDX(node_id, st_control, 8), \ + .AsynchronousWait = DT_PROP_BY_IDX(node_id, st_control, 9), \ + .WriteBurst = DT_PROP_BY_IDX(node_id, st_control, 10), \ + .ContinuousClock = DT_PROP_BY_IDX(node_id, st_control, 11), \ + .WriteFifo = DT_PROP_BY_IDX(node_id, st_control, 12), \ + .PageSize = DT_PROP_BY_IDX(node_id, st_control, 13) \ + }, \ + .timing = { \ + .AddressSetupTime = DT_PROP_BY_IDX(node_id, st_timing, 0), \ + .AddressHoldTime = DT_PROP_BY_IDX(node_id, st_timing, 1), \ + .DataSetupTime = DT_PROP_BY_IDX(node_id, st_timing, 2), \ + .BusTurnAroundDuration = DT_PROP_BY_IDX(node_id, st_timing, 3), \ + .CLKDivision = DT_PROP_BY_IDX(node_id, st_timing, 4), \ + .DataLatency = DT_PROP_BY_IDX(node_id, st_timing, 5), \ + .AccessMode = DT_PROP_BY_IDX(node_id, st_timing, 6), \ + }, \ + .timing_ext = { \ + .AddressSetupTime = DT_PROP_BY_IDX(node_id, st_timing_ext, 0), \ + .AddressHoldTime = DT_PROP_BY_IDX(node_id, st_timing_ext, 1), \ + .DataSetupTime = DT_PROP_BY_IDX(node_id, st_timing_ext, 2), \ + .BusTurnAroundDuration = DT_PROP_BY_IDX(node_id, st_timing_ext, 3), \ + .AccessMode = DT_PROP_BY_IDX(node_id, st_timing_ext, 4), \ + } \ + }, + +/** SRAM bank/s configuration. */ +static const struct memc_stm32_nor_psram_bank_config bank_config[] = { + DT_INST_FOREACH_CHILD(0, BANK_CONFIG) +}; + +/** SRAM configuration. */ +static const struct memc_stm32_nor_psram_config config = { + .nor_psram = (FMC_NORSRAM_TypeDef *)(DT_REG_ADDR(DT_INST_PARENT(0)) + SRAM_OFFSET), + .extended = (FMC_NORSRAM_EXTENDED_TypeDef *)(DT_REG_ADDR(DT_INST_PARENT(0)) + + SRAM_EXT_OFFSET), + .banks = bank_config, + .banks_len = ARRAY_SIZE(bank_config), +}; + +DEVICE_DT_INST_DEFINE(0, memc_stm32_nor_psram_init, NULL, + NULL, &config, + POST_KERNEL, CONFIG_MEMC_INIT_PRIORITY, + NULL);