1 /*
2  * Copyright (c) 2022 Georgij Cernysiov
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT st_stm32_fmc_nor_psram
8 
9 #include <zephyr/device.h>
10 #include <soc.h>
11 #include <errno.h>
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(memc_stm32_nor_psram, CONFIG_MEMC_LOG_LEVEL);
15 
16 /** SRAM base register offset, see FMC_Bank1_R_BASE */
17 #define SRAM_OFFSET 0x0000UL
18 /** SRAM extended mode register offset, see FMC_Bank1E_R_BASE */
19 #define SRAM_EXT_OFFSET 0x0104UL
20 
21 /** FMC NOR/PSRAM controller bank configuration fields. */
22 struct memc_stm32_nor_psram_bank_config {
23 	FMC_NORSRAM_InitTypeDef init;
24 	FMC_NORSRAM_TimingTypeDef timing;
25 	FMC_NORSRAM_TimingTypeDef timing_ext;
26 };
27 
28 /** FMC NOR/PSRAM controller configuration fields. */
29 struct memc_stm32_nor_psram_config {
30 	FMC_NORSRAM_TypeDef *nor_psram;
31 	FMC_NORSRAM_EXTENDED_TypeDef *extended;
32 	const struct memc_stm32_nor_psram_bank_config *banks;
33 	size_t banks_len;
34 };
35 
memc_stm32_nor_init(const struct memc_stm32_nor_psram_config * config,const struct memc_stm32_nor_psram_bank_config * bank_config)36 static int memc_stm32_nor_init(const struct memc_stm32_nor_psram_config *config,
37 			       const struct memc_stm32_nor_psram_bank_config *bank_config)
38 {
39 	FMC_NORSRAM_TimingTypeDef *ext_timing;
40 	NOR_HandleTypeDef hnor = { 0 };
41 
42 	hnor.Instance = config->nor_psram;
43 	hnor.Extended = config->extended;
44 
45 	memcpy(&hnor.Init, &bank_config->init, sizeof(hnor.Init));
46 
47 	if (bank_config->init.ExtendedMode == FMC_EXTENDED_MODE_ENABLE) {
48 		ext_timing = (FMC_NORSRAM_TimingTypeDef *)&bank_config->timing_ext;
49 	} else {
50 		ext_timing = NULL;
51 	}
52 
53 	if (HAL_NOR_Init(&hnor,
54 			 (FMC_NORSRAM_TimingTypeDef *)&bank_config->timing,
55 			 ext_timing) != HAL_OK) {
56 		return -ENODEV;
57 	}
58 
59 	return 0;
60 }
61 
memc_stm32_psram_init(const struct memc_stm32_nor_psram_config * config,const struct memc_stm32_nor_psram_bank_config * bank_config)62 static int memc_stm32_psram_init(const struct memc_stm32_nor_psram_config *config,
63 				 const struct memc_stm32_nor_psram_bank_config *bank_config)
64 {
65 	FMC_NORSRAM_TimingTypeDef *ext_timing;
66 	SRAM_HandleTypeDef hsram = { 0 };
67 
68 	hsram.Instance = config->nor_psram;
69 	hsram.Extended = config->extended;
70 
71 	memcpy(&hsram.Init, &bank_config->init, sizeof(hsram.Init));
72 
73 	if (bank_config->init.ExtendedMode == FMC_EXTENDED_MODE_ENABLE) {
74 		ext_timing = (FMC_NORSRAM_TimingTypeDef *)&bank_config->timing_ext;
75 	} else {
76 		ext_timing = NULL;
77 	}
78 
79 	if (HAL_SRAM_Init(&hsram,
80 			  (FMC_NORSRAM_TimingTypeDef *)&bank_config->timing,
81 			  ext_timing) != HAL_OK) {
82 		return -ENODEV;
83 	}
84 
85 	return 0;
86 }
87 
memc_stm32_nor_psram_init(const struct device * dev)88 static int memc_stm32_nor_psram_init(const struct device *dev)
89 {
90 	const struct memc_stm32_nor_psram_config *config = dev->config;
91 	uint32_t memory_type;
92 	size_t bank_idx;
93 	int ret = 0;
94 
95 	for (bank_idx = 0U; bank_idx < config->banks_len; ++bank_idx) {
96 		memory_type = config->banks[bank_idx].init.MemoryType;
97 
98 		switch (memory_type) {
99 		case FMC_MEMORY_TYPE_NOR:
100 			ret = memc_stm32_nor_init(config, &config->banks[bank_idx]);
101 			break;
102 		case FMC_MEMORY_TYPE_PSRAM:
103 			__fallthrough;
104 		case FMC_MEMORY_TYPE_SRAM:
105 			ret = memc_stm32_psram_init(config, &config->banks[bank_idx]);
106 			break;
107 		default:
108 			ret = -ENOTSUP;
109 			break;
110 		}
111 
112 		if (ret < 0) {
113 			LOG_ERR("Unable to initialize memory type: "
114 				"0x%08X, NSBank: %d, err: %d",
115 				memory_type, config->banks[bank_idx].init.NSBank, ret);
116 			goto end;
117 		}
118 	}
119 
120 end:
121 	return ret;
122 }
123 
124 /** SDRAM bank/s configuration initialization macro. */
125 #define BANK_CONFIG(node_id)                                                    \
126 	{ .init = {                                                             \
127 	    .NSBank = DT_REG_ADDR(node_id),                                     \
128 	    .DataAddressMux = DT_PROP_BY_IDX(node_id, st_control, 0),           \
129 	    .MemoryType = DT_PROP_BY_IDX(node_id, st_control, 1),               \
130 	    .MemoryDataWidth = DT_PROP_BY_IDX(node_id, st_control, 2),          \
131 	    .BurstAccessMode = DT_PROP_BY_IDX(node_id, st_control, 3),          \
132 	    .WaitSignalPolarity = DT_PROP_BY_IDX(node_id, st_control, 4),       \
133 	    .WaitSignalActive = DT_PROP_BY_IDX(node_id, st_control, 5),         \
134 	    .WriteOperation = DT_PROP_BY_IDX(node_id, st_control, 6),           \
135 	    .WaitSignal = DT_PROP_BY_IDX(node_id, st_control, 7),               \
136 	    .ExtendedMode = DT_PROP_BY_IDX(node_id, st_control, 8),             \
137 	    .AsynchronousWait = DT_PROP_BY_IDX(node_id, st_control, 9),         \
138 	    .WriteBurst = DT_PROP_BY_IDX(node_id, st_control, 10),              \
139 	    .ContinuousClock = DT_PROP_BY_IDX(node_id, st_control, 11),         \
140 	    .WriteFifo = DT_PROP_BY_IDX(node_id, st_control, 12),               \
141 	    .PageSize = DT_PROP_BY_IDX(node_id, st_control, 13)                 \
142 	  },                                                                    \
143 	  .timing = {                                                           \
144 	    .AddressSetupTime = DT_PROP_BY_IDX(node_id, st_timing, 0),          \
145 	    .AddressHoldTime =  DT_PROP_BY_IDX(node_id, st_timing, 1),          \
146 	    .DataSetupTime = DT_PROP_BY_IDX(node_id, st_timing, 2),             \
147 	    .BusTurnAroundDuration = DT_PROP_BY_IDX(node_id, st_timing, 3),     \
148 	    .CLKDivision = DT_PROP_BY_IDX(node_id, st_timing, 4),               \
149 	    .DataLatency = DT_PROP_BY_IDX(node_id, st_timing, 5),               \
150 	    .AccessMode = DT_PROP_BY_IDX(node_id, st_timing, 6),                \
151 	  },                                                                    \
152 	  .timing_ext = {                                                       \
153 	    .AddressSetupTime = DT_PROP_BY_IDX(node_id, st_timing_ext, 0),      \
154 	    .AddressHoldTime =  DT_PROP_BY_IDX(node_id, st_timing_ext, 1),      \
155 	    .DataSetupTime = DT_PROP_BY_IDX(node_id, st_timing_ext, 2),         \
156 	    .BusTurnAroundDuration = DT_PROP_BY_IDX(node_id, st_timing_ext, 3), \
157 	    .AccessMode = DT_PROP_BY_IDX(node_id, st_timing_ext, 4),            \
158 	  }                                                                     \
159 	},
160 
161 /** SRAM bank/s configuration. */
162 static const struct memc_stm32_nor_psram_bank_config bank_config[] = {
163 	DT_INST_FOREACH_CHILD(0, BANK_CONFIG)
164 };
165 
166 /** SRAM configuration. */
167 static const struct memc_stm32_nor_psram_config config = {
168 	.nor_psram = (FMC_NORSRAM_TypeDef *)(DT_REG_ADDR(DT_INST_PARENT(0)) + SRAM_OFFSET),
169 	.extended = (FMC_NORSRAM_EXTENDED_TypeDef *)(DT_REG_ADDR(DT_INST_PARENT(0))
170 								 + SRAM_EXT_OFFSET),
171 	.banks = bank_config,
172 	.banks_len = ARRAY_SIZE(bank_config),
173 };
174 
175 DEVICE_DT_INST_DEFINE(0, memc_stm32_nor_psram_init, NULL,
176 		      NULL, &config,
177 		      POST_KERNEL, CONFIG_MEMC_INIT_PRIORITY,
178 		      NULL);
179