blob: d6b7891fe13d03de23df61192682adc81c83f663 [file] [log] [blame]
/*
* Copyright (c) 2020 Teslabs Engineering S.L.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT st_stm32_fmc_sdram
#include <zephyr/device.h>
#include <zephyr/kernel.h>
#include <soc.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(memc_stm32_sdram, CONFIG_MEMC_LOG_LEVEL);
/** SDRAM controller register offset. */
#define SDRAM_OFFSET 0x140U
/** FMC SDRAM controller bank configuration fields. */
struct memc_stm32_sdram_bank_config {
FMC_SDRAM_InitTypeDef init;
FMC_SDRAM_TimingTypeDef timing;
};
/** FMC SDRAM controller configuration fields. */
struct memc_stm32_sdram_config {
FMC_SDRAM_TypeDef *sdram;
uint32_t power_up_delay;
uint8_t num_auto_refresh;
uint16_t mode_register;
uint16_t refresh_rate;
const struct memc_stm32_sdram_bank_config *banks;
size_t banks_len;
};
static int memc_stm32_sdram_init(const struct device *dev)
{
const struct memc_stm32_sdram_config *config = dev->config;
SDRAM_HandleTypeDef sdram = { 0 };
FMC_SDRAM_CommandTypeDef sdram_cmd = { 0 };
sdram.Instance = config->sdram;
for (size_t i = 0U; i < config->banks_len; i++) {
sdram.State = HAL_SDRAM_STATE_RESET;
memcpy(&sdram.Init, &config->banks[i].init, sizeof(sdram.Init));
(void)HAL_SDRAM_Init(
&sdram,
(FMC_SDRAM_TimingTypeDef *)&config->banks[i].timing);
}
/* SDRAM initialization sequence */
if (config->banks_len == 2U) {
sdram_cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;
} else if (config->banks[0].init.SDBank == FMC_SDRAM_BANK1) {
sdram_cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
} else {
sdram_cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
}
sdram_cmd.AutoRefreshNumber = config->num_auto_refresh;
sdram_cmd.ModeRegisterDefinition = config->mode_register;
/* enable clock */
sdram_cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
(void)HAL_SDRAM_SendCommand(&sdram, &sdram_cmd, 0U);
k_usleep(config->power_up_delay);
/* pre-charge all */
sdram_cmd.CommandMode = FMC_SDRAM_CMD_PALL;
(void)HAL_SDRAM_SendCommand(&sdram, &sdram_cmd, 0U);
/* auto-refresh */
sdram_cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
(void)HAL_SDRAM_SendCommand(&sdram, &sdram_cmd, 0U);
/* load mode */
sdram_cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
(void)HAL_SDRAM_SendCommand(&sdram, &sdram_cmd, 0U);
/* program refresh count */
(void)HAL_SDRAM_ProgramRefreshRate(&sdram, config->refresh_rate);
return 0;
}
/** SDRAM bank/s configuration initialization macro. */
#define BANK_CONFIG(node_id) \
{ .init = { \
.SDBank = DT_REG_ADDR(node_id), \
.ColumnBitsNumber = DT_PROP_BY_IDX(node_id, st_sdram_control, 0), \
.RowBitsNumber = DT_PROP_BY_IDX(node_id, st_sdram_control, 1), \
.MemoryDataWidth = DT_PROP_BY_IDX(node_id, st_sdram_control, 2), \
.InternalBankNumber = DT_PROP_BY_IDX(node_id, st_sdram_control, 3),\
.CASLatency = DT_PROP_BY_IDX(node_id, st_sdram_control, 4), \
.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE, \
.SDClockPeriod = DT_PROP_BY_IDX(node_id, st_sdram_control, 5), \
.ReadBurst = DT_PROP_BY_IDX(node_id, st_sdram_control, 6), \
.ReadPipeDelay = DT_PROP_BY_IDX(node_id, st_sdram_control, 7), \
}, \
.timing = { \
.LoadToActiveDelay = DT_PROP_BY_IDX(node_id, st_sdram_timing, 0), \
.ExitSelfRefreshDelay = \
DT_PROP_BY_IDX(node_id, st_sdram_timing, 1), \
.SelfRefreshTime = DT_PROP_BY_IDX(node_id, st_sdram_timing, 2), \
.RowCycleDelay = DT_PROP_BY_IDX(node_id, st_sdram_timing, 3), \
.WriteRecoveryTime = DT_PROP_BY_IDX(node_id, st_sdram_timing, 4), \
.RPDelay = DT_PROP_BY_IDX(node_id, st_sdram_timing, 5), \
.RCDDelay = DT_PROP_BY_IDX(node_id, st_sdram_timing, 6), \
} \
},
/** SDRAM bank/s configuration. */
static const struct memc_stm32_sdram_bank_config bank_config[] = {
DT_INST_FOREACH_CHILD(0, BANK_CONFIG)
};
/** SDRAM configuration. */
static const struct memc_stm32_sdram_config config = {
.sdram = (FMC_SDRAM_TypeDef *)(DT_REG_ADDR(DT_INST_PARENT(0)) +
SDRAM_OFFSET),
.power_up_delay = DT_INST_PROP(0, power_up_delay),
.num_auto_refresh = DT_INST_PROP(0, num_auto_refresh),
.mode_register = DT_INST_PROP(0, mode_register),
.refresh_rate = DT_INST_PROP(0, refresh_rate),
.banks = bank_config,
.banks_len = ARRAY_SIZE(bank_config),
};
DEVICE_DT_INST_DEFINE(0, memc_stm32_sdram_init, NULL,
NULL, &config, POST_KERNEL, CONFIG_MEMC_INIT_PRIORITY, NULL);