179 lines
6.2 KiB
C
179 lines
6.2 KiB
C
/*
|
|
* Copyright (c) 2022 Georgij Cernysiov
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT st_stm32_fmc_nor_psram
|
|
|
|
#include <zephyr/device.h>
|
|
#include <soc.h>
|
|
#include <errno.h>
|
|
|
|
#include <zephyr/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);
|