1 /*
2 * Copyright 2020-2023 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_imx_flexspi
8
9 #include <zephyr/logging/log.h>
10 #include <zephyr/sys/util.h>
11 #include <zephyr/drivers/pinctrl.h>
12 #include <zephyr/pm/device.h>
13 #include <soc.h>
14
15 #include "memc_mcux_flexspi.h"
16
17
18 /*
19 * NOTE: If CONFIG_FLASH_MCUX_FLEXSPI_XIP is selected, Any external functions
20 * called while interacting with the flexspi MUST be relocated to SRAM or ITCM
21 * at runtime, so that the chip does not access the flexspi to read program
22 * instructions while it is being written to
23 */
24 #if defined(CONFIG_FLASH_MCUX_FLEXSPI_XIP) && (CONFIG_MEMC_LOG_LEVEL > 0)
25 #warning "Enabling memc driver logging and XIP mode simultaneously can cause \
26 read-while-write hazards. This configuration is not recommended."
27 #endif
28
29 LOG_MODULE_REGISTER(memc_flexspi, CONFIG_MEMC_LOG_LEVEL);
30
31 struct memc_flexspi_buf_cfg {
32 uint16_t prefetch;
33 uint16_t priority;
34 uint16_t master_id;
35 uint16_t buf_size;
36 } __packed;
37
38 /* flexspi device data should be stored in RAM to avoid read-while-write hazards */
39 struct memc_flexspi_data {
40 FLEXSPI_Type *base;
41 uint8_t *ahb_base;
42 bool xip;
43 bool ahb_bufferable;
44 bool ahb_cacheable;
45 bool ahb_prefetch;
46 bool ahb_read_addr_opt;
47 bool combination_mode;
48 bool sck_differential_clock;
49 flexspi_read_sample_clock_t rx_sample_clock;
50 const struct pinctrl_dev_config *pincfg;
51 size_t size[kFLEXSPI_PortCount];
52 struct memc_flexspi_buf_cfg *buf_cfg;
53 uint8_t buf_cfg_cnt;
54 };
55
memc_flexspi_wait_bus_idle(const struct device * dev)56 void memc_flexspi_wait_bus_idle(const struct device *dev)
57 {
58 struct memc_flexspi_data *data = dev->data;
59
60 while (false == FLEXSPI_GetBusIdleStatus(data->base)) {
61 }
62 }
63
memc_flexspi_is_running_xip(const struct device * dev)64 bool memc_flexspi_is_running_xip(const struct device *dev)
65 {
66 struct memc_flexspi_data *data = dev->data;
67
68 return data->xip;
69 }
70
memc_flexspi_update_lut(const struct device * dev,uint32_t index,const uint32_t * cmd,uint32_t count)71 int memc_flexspi_update_lut(const struct device *dev, uint32_t index,
72 const uint32_t *cmd, uint32_t count)
73 {
74 struct memc_flexspi_data *data = dev->data;
75
76 FLEXSPI_UpdateLUT(data->base, index, cmd, count);
77
78 return 0;
79 }
80
memc_flexspi_update_clock(const struct device * dev,flexspi_device_config_t * device_config,flexspi_port_t port,enum memc_flexspi_clock_t clock)81 int memc_flexspi_update_clock(const struct device *dev,
82 flexspi_device_config_t *device_config,
83 flexspi_port_t port, enum memc_flexspi_clock_t clock)
84 {
85 #if CONFIG_SOC_SERIES_IMX_RT10XX
86 struct memc_flexspi_data *data = dev->data;
87
88 memc_flexspi_wait_bus_idle(dev);
89
90 FLEXSPI_Enable(data->base, false);
91
92 flexspi_clock_set_div(clock == MEMC_FLEXSPI_CLOCK_166M ? 0 : 3);
93
94 FLEXSPI_Enable(data->base, true);
95
96 memc_flexspi_reset(dev);
97
98 device_config->flexspiRootClk = flexspi_clock_get_freq();
99 FLEXSPI_UpdateDllValue(data->base, device_config, port);
100
101 memc_flexspi_reset(dev);
102
103 return 0;
104 #else
105 return -ENOTSUP;
106 #endif
107 }
108
memc_flexspi_set_device_config(const struct device * dev,const flexspi_device_config_t * device_config,flexspi_port_t port)109 int memc_flexspi_set_device_config(const struct device *dev,
110 const flexspi_device_config_t *device_config,
111 flexspi_port_t port)
112 {
113 struct memc_flexspi_data *data = dev->data;
114
115 if (port >= kFLEXSPI_PortCount) {
116 LOG_ERR("Invalid port number");
117 return -EINVAL;
118 }
119
120 data->size[port] = device_config->flashSize * KB(1);
121
122 FLEXSPI_SetFlashConfig(data->base,
123 (flexspi_device_config_t *) device_config,
124 port);
125
126 return 0;
127 }
128
memc_flexspi_reset(const struct device * dev)129 int memc_flexspi_reset(const struct device *dev)
130 {
131 struct memc_flexspi_data *data = dev->data;
132
133 FLEXSPI_SoftwareReset(data->base);
134
135 return 0;
136 }
137
memc_flexspi_transfer(const struct device * dev,flexspi_transfer_t * transfer)138 int memc_flexspi_transfer(const struct device *dev,
139 flexspi_transfer_t *transfer)
140 {
141 struct memc_flexspi_data *data = dev->data;
142 status_t status = FLEXSPI_TransferBlocking(data->base, transfer);
143
144 if (status != kStatus_Success) {
145 LOG_ERR("Transfer error: %d", status);
146 return -EIO;
147 }
148
149 return 0;
150 }
151
memc_flexspi_get_ahb_address(const struct device * dev,flexspi_port_t port,off_t offset)152 void *memc_flexspi_get_ahb_address(const struct device *dev,
153 flexspi_port_t port, off_t offset)
154 {
155 struct memc_flexspi_data *data = dev->data;
156 int i;
157
158 if (port >= kFLEXSPI_PortCount) {
159 LOG_ERR("Invalid port number: %u", port);
160 return NULL;
161 }
162
163 for (i = 0; i < port; i++) {
164 offset += data->size[port];
165 }
166
167 return data->ahb_base + offset;
168 }
169
memc_flexspi_init(const struct device * dev)170 static int memc_flexspi_init(const struct device *dev)
171 {
172 struct memc_flexspi_data *data = dev->data;
173 flexspi_config_t flexspi_config;
174
175 /* we should not configure the device we are running on */
176 if (memc_flexspi_is_running_xip(dev)) {
177 LOG_DBG("XIP active on %s, skipping init", dev->name);
178 return 0;
179 }
180
181 /*
182 * SOCs such as the RT1064 and RT1024 have internal flash, and no pinmux
183 * settings, continue if no pinctrl state found.
184 */
185 int ret;
186
187 ret = pinctrl_apply_state(data->pincfg, PINCTRL_STATE_DEFAULT);
188 if (ret < 0 && ret != -ENOENT) {
189 return ret;
190 }
191
192 FLEXSPI_GetDefaultConfig(&flexspi_config);
193
194 flexspi_config.ahbConfig.enableAHBBufferable = data->ahb_bufferable;
195 flexspi_config.ahbConfig.enableAHBCachable = data->ahb_cacheable;
196 flexspi_config.ahbConfig.enableAHBPrefetch = data->ahb_prefetch;
197 flexspi_config.ahbConfig.enableReadAddressOpt = data->ahb_read_addr_opt;
198 #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN) && \
199 FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN)
200 flexspi_config.enableCombination = data->combination_mode;
201 #endif
202
203 #if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT) && \
204 FSL_FEATURE_FLEXSPI_HAS_NO_MCR2_SCKBDIFFOPT)
205 flexspi_config.enableSckBDiffOpt = data->sck_differential_clock;
206 #endif
207 flexspi_config.rxSampleClock = data->rx_sample_clock;
208
209 /* Configure AHB RX buffers, if any configuration settings are present */
210 __ASSERT(data->buf_cfg_cnt < FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT,
211 "Maximum RX buffer configuration count exceeded");
212 for (uint8_t i = 0; i < data->buf_cfg_cnt; i++) {
213 /* Should AHB prefetch up to buffer size? */
214 flexspi_config.ahbConfig.buffer[i].enablePrefetch = data->buf_cfg[i].prefetch;
215 /* AHB access priority (used for suspending control of AHB prefetching )*/
216 flexspi_config.ahbConfig.buffer[i].priority = data->buf_cfg[i].priority;
217 /* AHB master index, SOC specific */
218 flexspi_config.ahbConfig.buffer[i].masterIndex = data->buf_cfg[i].master_id;
219 /* RX buffer allocation (total available buffer space is instance/SOC specific) */
220 flexspi_config.ahbConfig.buffer[i].bufferSize = data->buf_cfg[i].buf_size;
221 }
222
223 FLEXSPI_Init(data->base, &flexspi_config);
224
225 return 0;
226 }
227
228 #ifdef CONFIG_PM_DEVICE
memc_flexspi_pm_action(const struct device * dev,enum pm_device_action action)229 static int memc_flexspi_pm_action(const struct device *dev, enum pm_device_action action)
230 {
231 struct memc_flexspi_data *data = dev->data;
232 int ret;
233
234 switch (action) {
235 case PM_DEVICE_ACTION_RESUME:
236 ret = pinctrl_apply_state(data->pincfg, PINCTRL_STATE_DEFAULT);
237 if (ret < 0 && ret != -ENOENT) {
238 return ret;
239 }
240 break;
241 case PM_DEVICE_ACTION_SUSPEND:
242 ret = pinctrl_apply_state(data->pincfg, PINCTRL_STATE_SLEEP);
243 if (ret < 0 && ret != -ENOENT) {
244 return ret;
245 }
246 break;
247 default:
248 return -ENOTSUP;
249 }
250
251 return 0;
252 }
253 #endif
254
255 #if defined(CONFIG_XIP) && defined(CONFIG_CODE_FLEXSPI)
256 #define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi))
257 #elif defined(CONFIG_XIP) && defined(CONFIG_CODE_FLEXSPI2)
258 #define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi2))
259 #elif defined(CONFIG_SOC_SERIES_IMX_RT6XX) || defined(CONFIG_SOC_SERIES_IMX_RT5XX)
260 #define MEMC_FLEXSPI_CFG_XIP(node_id) DT_SAME_NODE(node_id, DT_NODELABEL(flexspi))
261 #else
262 #define MEMC_FLEXSPI_CFG_XIP(node_id) false
263 #endif
264
265 #define MEMC_FLEXSPI(n) \
266 PINCTRL_DT_INST_DEFINE(n); \
267 static uint16_t buf_cfg_##n[] = \
268 DT_INST_PROP_OR(n, rx_buffer_config, {0}); \
269 \
270 static struct memc_flexspi_data \
271 memc_flexspi_data_##n = { \
272 .base = (FLEXSPI_Type *) DT_INST_REG_ADDR(n), \
273 .xip = MEMC_FLEXSPI_CFG_XIP(DT_DRV_INST(n)), \
274 .ahb_base = (uint8_t *) DT_INST_REG_ADDR_BY_IDX(n, 1), \
275 .ahb_bufferable = DT_INST_PROP(n, ahb_bufferable), \
276 .ahb_cacheable = DT_INST_PROP(n, ahb_cacheable), \
277 .ahb_prefetch = DT_INST_PROP(n, ahb_prefetch), \
278 .ahb_read_addr_opt = DT_INST_PROP(n, ahb_read_addr_opt),\
279 .combination_mode = DT_INST_PROP(n, combination_mode), \
280 .sck_differential_clock = DT_INST_PROP(n, sck_differential_clock), \
281 .rx_sample_clock = DT_INST_PROP(n, rx_clock_source), \
282 .buf_cfg = (struct memc_flexspi_buf_cfg *)buf_cfg_##n, \
283 .buf_cfg_cnt = sizeof(buf_cfg_##n) / \
284 sizeof(struct memc_flexspi_buf_cfg), \
285 .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
286 }; \
287 \
288 PM_DEVICE_DT_INST_DEFINE(n, memc_flexspi_pm_action); \
289 \
290 DEVICE_DT_INST_DEFINE(n, \
291 memc_flexspi_init, \
292 PM_DEVICE_DT_INST_GET(n), \
293 &memc_flexspi_data_##n, \
294 NULL, \
295 POST_KERNEL, \
296 CONFIG_MEMC_INIT_PRIORITY, \
297 NULL);
298
299 DT_INST_FOREACH_STATUS_OKAY(MEMC_FLEXSPI)
300