You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
4.8 KiB
134 lines
4.8 KiB
/* |
|
* 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);
|
|
|