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