/* * 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);