-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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: initial support for stm32 FMC
This commit adds a new driver category for memory controller peripherals. There is no API involved for now, as it has not been found necessary for first implementation. STM32 Flexible Memory Controller (FMC) is the only controller supported for now. This peripheral allows to access multiple types of external memories, e.g. SDRAM, NAND, NOR Flash... The initial implementation adds support for the SDRAM controller only. The HAL API is used, so the implementation should be portable to other STM32 series. It has only been tested on H7 series, so for now it can only be enabled when working on H7. Linker facilities have also been added in order to allow applications to easily define a variable in SDRAM. Signed-off-by: Gerard Marull-Paretas <[email protected]>
- Loading branch information
1 parent
cb06f5e
commit e671d36
Showing
16 changed files
with
574 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -101,4 +101,6 @@ source "drivers/peci/Kconfig" | |
|
||
source "drivers/regulator/Kconfig" | ||
|
||
source "drivers/memc/Kconfig" | ||
|
||
endmenu |
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,3 @@ | ||
zephyr_sources_ifdef(CONFIG_MEMC_STM32 memc_stm32.c) | ||
zephyr_sources_ifdef(CONFIG_MEMC_STM32_SDRAM memc_stm32_sdram.c) | ||
zephyr_linker_sources_ifdef(CONFIG_MEMC_STM32_SDRAM SECTIONS memc_stm32_sdram.ld) |
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,25 @@ | ||
# Memory controller configuration options | ||
|
||
# Copyright (c) 2020 Teslabs Engineering S.L. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
menuconfig MEMC | ||
bool "Memory controllers [EXPERIMENTAL]" | ||
help | ||
Add support for memory controllers | ||
|
||
if MEMC | ||
|
||
module = MEMC | ||
module-str = memc | ||
source "subsys/logging/Kconfig.template.log_config" | ||
|
||
config MEMC_INIT_PRIORITY | ||
int "Initialization priority" | ||
default 0 | ||
help | ||
Memory controllers initialization priority. | ||
|
||
source "drivers/memc/Kconfig.stm32" | ||
|
||
endif |
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,19 @@ | ||
# Copyright (c) 2020 Teslabs Engineering S.L. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
config MEMC_STM32 | ||
bool "Enable STM32 Flexible Memory Controller (FMC)" | ||
depends on SOC_SERIES_STM32H7X | ||
help | ||
Enable STM32 Flexible Memory Controller. | ||
|
||
DT_COMPAT_ST_STM32_FMC_SDRAM := st,stm32-fmc-sdram | ||
|
||
config MEMC_STM32_SDRAM | ||
bool "Enable STM32 FMC SDRAM controller" | ||
depends on MEMC_STM32 | ||
default $(dt_compat_enabled,$(DT_COMPAT_ST_STM32_FMC_SDRAM)) | ||
select USE_STM32_LL_FMC | ||
select USE_STM32_HAL_SDRAM | ||
help | ||
Enable STM32 FMC SDRAM controller. |
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,63 @@ | ||
/* | ||
* Copyright (c) 2020 Teslabs Engineering S.L. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#define DT_DRV_COMPAT st_stm32_fmc | ||
|
||
#include <device.h> | ||
|
||
#include <drivers/clock_control/stm32_clock_control.h> | ||
#include <pinmux/stm32/pinmux_stm32.h> | ||
|
||
#include <logging/log.h> | ||
LOG_MODULE_REGISTER(memc_stm32, CONFIG_MEMC_LOG_LEVEL); | ||
|
||
struct memc_stm32_config { | ||
uint32_t fmc; | ||
struct stm32_pclken pclken; | ||
const struct soc_gpio_pinctrl *pinctrl; | ||
size_t pinctrl_len; | ||
}; | ||
|
||
static int memc_stm32_init(const struct device *dev) | ||
{ | ||
const struct memc_stm32_config *config = dev->config; | ||
|
||
int r; | ||
const struct device *clk; | ||
|
||
/* configure pinmux */ | ||
r = stm32_dt_pinctrl_configure(config->pinctrl, config->pinctrl_len, | ||
config->fmc); | ||
if (r < 0) { | ||
LOG_ERR("FMC pinctrl setup failed (%d)", r); | ||
return r; | ||
} | ||
|
||
/* enable FMC peripheral clock */ | ||
clk = device_get_binding(STM32_CLOCK_CONTROL_NAME); | ||
__ASSERT_NO_MSG(clk); | ||
|
||
r = clock_control_on(clk, (clock_control_subsys_t *)&config->pclken); | ||
if (r < 0) { | ||
LOG_ERR("Could not initialize FMC clock (%d)", r); | ||
return r; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static const struct soc_gpio_pinctrl pinctrl[] = ST_STM32_DT_INST_PINCTRL(0, 0); | ||
|
||
static const struct memc_stm32_config config = { | ||
.fmc = DT_INST_REG_ADDR(0), | ||
.pclken = { .bus = DT_INST_CLOCKS_CELL(0, bus), | ||
.enr = DT_INST_CLOCKS_CELL(0, bits) }, | ||
.pinctrl = pinctrl, | ||
.pinctrl_len = ARRAY_SIZE(pinctrl), | ||
}; | ||
|
||
DEVICE_DEFINE(memc_stm32, DT_INST_LABEL(0), memc_stm32_init, NULL, NULL, | ||
&config, POST_KERNEL, CONFIG_MEMC_INIT_PRIORITY, NULL); |
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,133 @@ | ||
/* | ||
* Copyright (c) 2020 Teslabs Engineering S.L. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#define DT_DRV_COMPAT st_stm32_fmc_sdram | ||
|
||
#include <device.h> | ||
#include <soc.h> | ||
|
||
#include <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_PARENT(DT_DRV_INST(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_DEFINE(memc_stm32_sdram, DT_INST_LABEL(0), memc_stm32_sdram_init, NULL, | ||
NULL, &config, POST_KERNEL, CONFIG_MEMC_INIT_PRIORITY, NULL); |
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,29 @@ | ||
/* | ||
* Copyright (c) 2020 Teslabs Engineering S.L. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#if DT_NODE_HAS_STATUS(DT_NODELABEL(sdram1), okay) | ||
GROUP_START(SDRAM1) | ||
|
||
SECTION_PROLOGUE(_STM32_SDRAM1_SECTION_NAME, (NOLOAD),) | ||
{ | ||
*(.stm32_sdram1) | ||
*(".stm32_sdram1.*") | ||
} GROUP_LINK_IN(SDRAM1) | ||
|
||
GROUP_END(SDRAM1) | ||
#endif | ||
|
||
#if DT_NODE_HAS_STATUS(DT_NODELABEL(sdram2), okay) | ||
GROUP_START(SDRAM2) | ||
|
||
SECTION_PROLOGUE(_STM32_SDRAM2_SECTION_NAME, (NOLOAD),) | ||
{ | ||
*(.stm32_sdram2) | ||
*(".stm32_sdram2.*") | ||
} GROUP_LINK_IN(SDRAM2) | ||
|
||
GROUP_END(SDRAM2) | ||
#endif |
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
Oops, something went wrong.