zephyr/drivers/memc/memc_stm32_nor_psram.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);