-
Notifications
You must be signed in to change notification settings - Fork 6.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
drivers: memc: stm32: add FMC NOR/PSRAM driver
Adds STM32 FMC NOR/PSRAM controller driver. The implementation follows FMC SDRAM driver approach and uses HAL API. Tested on H7 series. Signed-off-by: Georgij Cernysiov <[email protected]>
- Loading branch information
1 parent
778f1d7
commit cf9df29
Showing
3 changed files
with
191 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <device.h> | ||
#include <soc.h> | ||
#include <errno.h> | ||
|
||
#include <logging/log.h> | ||
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); |