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