1 /*
2  * Copyright (c) 2020 Teslabs Engineering S.L.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT st_stm32_fmc_sdram
8 
9 #include <zephyr/device.h>
10 #include <zephyr/kernel.h>
11 #include <soc.h>
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(memc_stm32_sdram, CONFIG_MEMC_LOG_LEVEL);
15 
16 /** SDRAM controller register offset. */
17 #define SDRAM_OFFSET 0x140U
18 
19 /** FMC SDRAM controller bank configuration fields. */
20 struct memc_stm32_sdram_bank_config {
21 	FMC_SDRAM_InitTypeDef init;
22 	FMC_SDRAM_TimingTypeDef timing;
23 };
24 
25 /** FMC SDRAM controller configuration fields. */
26 struct memc_stm32_sdram_config {
27 	FMC_SDRAM_TypeDef *sdram;
28 	uint32_t power_up_delay;
29 	uint8_t num_auto_refresh;
30 	uint16_t mode_register;
31 	uint16_t refresh_rate;
32 	const struct memc_stm32_sdram_bank_config *banks;
33 	size_t banks_len;
34 };
35 
memc_stm32_sdram_init(const struct device * dev)36 static int memc_stm32_sdram_init(const struct device *dev)
37 {
38 	const struct memc_stm32_sdram_config *config = dev->config;
39 
40 	SDRAM_HandleTypeDef sdram = { 0 };
41 	FMC_SDRAM_CommandTypeDef sdram_cmd = { 0 };
42 
43 	sdram.Instance = config->sdram;
44 
45 	for (size_t i = 0U; i < config->banks_len; i++) {
46 		sdram.State = HAL_SDRAM_STATE_RESET;
47 		memcpy(&sdram.Init, &config->banks[i].init, sizeof(sdram.Init));
48 
49 		(void)HAL_SDRAM_Init(
50 			&sdram,
51 			(FMC_SDRAM_TimingTypeDef *)&config->banks[i].timing);
52 	}
53 
54 	/* SDRAM initialization sequence */
55 	if (config->banks_len == 2U) {
56 		sdram_cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;
57 	} else if (config->banks[0].init.SDBank == FMC_SDRAM_BANK1) {
58 		sdram_cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
59 	} else {
60 		sdram_cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
61 	}
62 
63 	sdram_cmd.AutoRefreshNumber = config->num_auto_refresh;
64 	sdram_cmd.ModeRegisterDefinition = config->mode_register;
65 
66 	/* enable clock */
67 	sdram_cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
68 	(void)HAL_SDRAM_SendCommand(&sdram, &sdram_cmd, 0U);
69 
70 	k_usleep(config->power_up_delay);
71 
72 	/* pre-charge all */
73 	sdram_cmd.CommandMode = FMC_SDRAM_CMD_PALL;
74 	(void)HAL_SDRAM_SendCommand(&sdram, &sdram_cmd, 0U);
75 
76 	/* auto-refresh */
77 	sdram_cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
78 	(void)HAL_SDRAM_SendCommand(&sdram, &sdram_cmd, 0U);
79 
80 	/* load mode */
81 	sdram_cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
82 	(void)HAL_SDRAM_SendCommand(&sdram, &sdram_cmd, 0U);
83 
84 	/* program refresh count */
85 	(void)HAL_SDRAM_ProgramRefreshRate(&sdram, config->refresh_rate);
86 
87 	return 0;
88 }
89 
90 /** SDRAM bank/s configuration initialization macro. */
91 #define BANK_CONFIG(node_id)                                                   \
92 	{ .init = {                                                            \
93 	    .SDBank = DT_REG_ADDR(node_id),                                    \
94 	    .ColumnBitsNumber = DT_PROP_BY_IDX(node_id, st_sdram_control, 0),  \
95 	    .RowBitsNumber = DT_PROP_BY_IDX(node_id, st_sdram_control, 1),     \
96 	    .MemoryDataWidth = DT_PROP_BY_IDX(node_id, st_sdram_control, 2),   \
97 	    .InternalBankNumber = DT_PROP_BY_IDX(node_id, st_sdram_control, 3),\
98 	    .CASLatency = DT_PROP_BY_IDX(node_id, st_sdram_control, 4),        \
99 	    .WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE,             \
100 	    .SDClockPeriod = DT_PROP_BY_IDX(node_id, st_sdram_control, 5),     \
101 	    .ReadBurst = DT_PROP_BY_IDX(node_id, st_sdram_control, 6),         \
102 	    .ReadPipeDelay = DT_PROP_BY_IDX(node_id, st_sdram_control, 7),     \
103 	  },                                                                   \
104 	  .timing = {                                                          \
105 	    .LoadToActiveDelay = DT_PROP_BY_IDX(node_id, st_sdram_timing, 0),  \
106 	    .ExitSelfRefreshDelay =                                            \
107 		DT_PROP_BY_IDX(node_id, st_sdram_timing, 1),                   \
108 	    .SelfRefreshTime = DT_PROP_BY_IDX(node_id, st_sdram_timing, 2),    \
109 	    .RowCycleDelay = DT_PROP_BY_IDX(node_id, st_sdram_timing, 3),      \
110 	    .WriteRecoveryTime = DT_PROP_BY_IDX(node_id, st_sdram_timing, 4),  \
111 	    .RPDelay = DT_PROP_BY_IDX(node_id, st_sdram_timing, 5),            \
112 	    .RCDDelay = DT_PROP_BY_IDX(node_id, st_sdram_timing, 6),           \
113 	  }                                                                    \
114 	},
115 
116 /** SDRAM bank/s configuration. */
117 static const struct memc_stm32_sdram_bank_config bank_config[] = {
118 	DT_INST_FOREACH_CHILD(0, BANK_CONFIG)
119 };
120 
121 /** SDRAM configuration. */
122 static const struct memc_stm32_sdram_config config = {
123 	.sdram = (FMC_SDRAM_TypeDef *)(DT_REG_ADDR(DT_INST_PARENT(0)) +
124 				       SDRAM_OFFSET),
125 	.power_up_delay = DT_INST_PROP(0, power_up_delay),
126 	.num_auto_refresh = DT_INST_PROP(0, num_auto_refresh),
127 	.mode_register = DT_INST_PROP(0, mode_register),
128 	.refresh_rate = DT_INST_PROP(0, refresh_rate),
129 	.banks = bank_config,
130 	.banks_len = ARRAY_SIZE(bank_config),
131 };
132 
133 DEVICE_DT_INST_DEFINE(0, memc_stm32_sdram_init, NULL,
134 	      NULL, &config, POST_KERNEL, CONFIG_MEMC_INIT_PRIORITY, NULL);
135