1 /*
2  * Copyright (c) 2024, Ambiq Micro Inc. <www.ambiq.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT mspi_aps6404l
8 #include <zephyr/kernel.h>
9 #include <zephyr/pm/device.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/sys/util.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/drivers/mspi.h>
14 #if CONFIG_SOC_FAMILY_AMBIQ
15 #include "mspi_ambiq.h"
16 typedef struct mspi_ambiq_timing_cfg mspi_timing_cfg;
17 typedef enum mspi_ambiq_timing_param mspi_timing_param;
18 #else
19 typedef struct mspi_timing_cfg mspi_timing_cfg;
20 typedef enum mspi_timing_param mspi_timing_param;
21 #endif
22 
23 LOG_MODULE_REGISTER(memc_mspi_aps6404l, CONFIG_MEMC_LOG_LEVEL);
24 
25 #define APM_VENDOR_ID                  0xD
26 
27 #define APS6404L_WRITE                 0x02
28 #define APS6404L_READ                  0x03
29 #define APS6404L_FAST_READ             0x0B
30 #define APS6404L_QUAD_MODE_ENTER       0x35
31 #define APS6404L_QUAD_WRITE            0x38
32 #define APS6404L_RESET_ENABLE          0x66
33 #define APS6404L_RESET_MEMORY          0x99
34 #define APS6404L_READ_ID               0x9F
35 #define APS6404L_HALF_SLEEP_ENTER      0xC0
36 #define APS6404L_QUAD_READ             0xEB
37 #define APS6404L_QUAD_MODE_EXIT        0xF5
38 
39 struct memc_mspi_aps6404l_config {
40 	uint32_t                       port;
41 	uint32_t                       mem_size;
42 
43 	const struct device            *bus;
44 	struct mspi_dev_id             dev_id;
45 	struct mspi_dev_cfg            serial_cfg;
46 	struct mspi_dev_cfg            quad_cfg;
47 	struct mspi_dev_cfg            tar_dev_cfg;
48 	struct mspi_xip_cfg            tar_xip_cfg;
49 	struct mspi_scramble_cfg       tar_scramble_cfg;
50 
51 	mspi_timing_cfg                tar_timing_cfg;
52 	mspi_timing_param              timing_cfg_mask;
53 
54 	bool                           sw_multi_periph;
55 };
56 
57 struct memc_mspi_aps6404l_data {
58 	struct mspi_dev_cfg            dev_cfg;
59 	struct mspi_xip_cfg            xip_cfg;
60 	struct mspi_scramble_cfg       scramble_cfg;
61 	mspi_timing_cfg                timing_cfg;
62 	struct mspi_xfer               trans;
63 	struct mspi_xfer_packet        packet;
64 
65 	struct k_sem                   lock;
66 };
67 
memc_mspi_aps6404l_command_write(const struct device * psram,uint8_t cmd,uint32_t addr,uint8_t * wdata,uint32_t length)68 static int memc_mspi_aps6404l_command_write(const struct device *psram, uint8_t cmd, uint32_t addr,
69 					    uint8_t *wdata, uint32_t length)
70 {
71 	const struct memc_mspi_aps6404l_config *cfg = psram->config;
72 	struct memc_mspi_aps6404l_data *data = psram->data;
73 	int ret;
74 	uint8_t buffer[16];
75 
76 	data->packet.dir              = MSPI_TX;
77 	data->packet.cmd              = cmd;
78 	data->packet.address          = addr;
79 	data->packet.data_buf         = buffer;
80 	data->packet.num_bytes        = length;
81 
82 	data->trans.async             = false;
83 	data->trans.xfer_mode         = MSPI_PIO;
84 	data->trans.tx_dummy          = 0;
85 	data->trans.cmd_length        = 1;
86 	data->trans.addr_length       = 0;
87 	data->trans.hold_ce           = false;
88 	data->trans.packets           = &data->packet;
89 	data->trans.num_packet        = 1;
90 	data->trans.timeout           = 10;
91 
92 	if (wdata != NULL) {
93 		memcpy(buffer, wdata, length);
94 	}
95 
96 	ret = mspi_transceive(cfg->bus, &cfg->dev_id, (const struct mspi_xfer *)&data->trans);
97 	if (ret) {
98 		LOG_ERR("MSPI write transaction failed with code: %d/%u", ret, __LINE__);
99 		return -EIO;
100 	}
101 	return ret;
102 }
103 
memc_mspi_aps6404l_command_read(const struct device * psram,uint8_t cmd,uint32_t addr,uint8_t * rdata,uint32_t length)104 static int memc_mspi_aps6404l_command_read(const struct device *psram, uint8_t cmd, uint32_t addr,
105 					   uint8_t *rdata, uint32_t length)
106 {
107 	const struct memc_mspi_aps6404l_config *cfg = psram->config;
108 	struct memc_mspi_aps6404l_data *data = psram->data;
109 
110 	int ret;
111 	uint8_t buffer[16];
112 
113 	data->packet.dir              = MSPI_RX;
114 	data->packet.cmd              = cmd;
115 	data->packet.address          = addr;
116 	data->packet.data_buf         = buffer;
117 	data->packet.num_bytes        = length;
118 
119 	data->trans.async             = false;
120 	data->trans.xfer_mode         = MSPI_PIO;
121 	data->trans.rx_dummy          = 0;
122 	data->trans.cmd_length        = 1;
123 	data->trans.addr_length       = 3;
124 	data->trans.hold_ce           = false;
125 	data->trans.packets           = &data->packet;
126 	data->trans.num_packet        = 1;
127 	data->trans.timeout           = 10;
128 
129 	ret = mspi_transceive(cfg->bus, &cfg->dev_id, (const struct mspi_xfer *)&data->trans);
130 	if (ret) {
131 		LOG_ERR("MSPI read transaction failed with code: %d/%u", ret, __LINE__);
132 		return -EIO;
133 	}
134 	memcpy(rdata, buffer, length);
135 	return ret;
136 }
137 
138 #if CONFIG_PM_DEVICE
acquire(const struct device * psram)139 static void acquire(const struct device *psram)
140 {
141 	const struct memc_mspi_aps6404l_config *cfg = psram->config;
142 	struct memc_mspi_aps6404l_data *data = psram->data;
143 
144 	k_sem_take(&data->lock, K_FOREVER);
145 
146 	if (cfg->sw_multi_periph) {
147 		while (mspi_dev_config(cfg->bus, &cfg->dev_id,
148 				       MSPI_DEVICE_CONFIG_ALL, &data->dev_cfg)) {
149 			;
150 		}
151 	} else {
152 		while (mspi_dev_config(cfg->bus, &cfg->dev_id,
153 				       MSPI_DEVICE_CONFIG_NONE, NULL)) {
154 			;
155 		}
156 	}
157 }
158 #endif /* CONFIG_PM_DEVICE */
159 
release(const struct device * psram)160 static void release(const struct device *psram)
161 {
162 	const struct memc_mspi_aps6404l_config *cfg = psram->config;
163 	struct memc_mspi_aps6404l_data *data = psram->data;
164 
165 	while (mspi_get_channel_status(cfg->bus, cfg->port)) {
166 		;
167 	}
168 
169 	k_sem_give(&data->lock);
170 }
171 
memc_mspi_aps6404l_reset(const struct device * psram)172 static int memc_mspi_aps6404l_reset(const struct device *psram)
173 {
174 	int ret;
175 
176 	LOG_DBG("Resetting aps6404l/%u", __LINE__);
177 
178 	ret = memc_mspi_aps6404l_command_write(psram, APS6404L_RESET_ENABLE, 0, NULL, 0);
179 	if (ret) {
180 		return ret;
181 	}
182 	ret = memc_mspi_aps6404l_command_write(psram, APS6404L_RESET_MEMORY, 0, NULL, 0);
183 	if (ret) {
184 		return ret;
185 	}
186 	/** We need to delay 5 ms to allow aps6404L pSRAM to reinitialize */
187 	k_busy_wait(5000);
188 	return ret;
189 }
190 
memc_mspi_aps6404l_get_vendor_id(const struct device * psram,uint8_t * vendor_id)191 static int memc_mspi_aps6404l_get_vendor_id(const struct device *psram, uint8_t *vendor_id)
192 {
193 	uint16_t buffer = 0;
194 	int ret;
195 
196 	ret = memc_mspi_aps6404l_command_read(psram, APS6404L_READ_ID, 0, (uint8_t *)&buffer, 2);
197 	LOG_DBG("Read ID buff: %x/%u", buffer, __LINE__);
198 	*vendor_id = buffer & 0xff;
199 
200 	return ret;
201 }
202 
203 #if CONFIG_PM_DEVICE
memc_mspi_aps6404l_half_sleep_enter(const struct device * psram)204 static int memc_mspi_aps6404l_half_sleep_enter(const struct device *psram)
205 {
206 	int ret;
207 
208 	LOG_DBG("Putting aps6404l to half sleep/%u", __LINE__);
209 	ret = memc_mspi_aps6404l_command_write(psram, APS6404L_HALF_SLEEP_ENTER, 0, NULL, 0);
210 	if (ret) {
211 		LOG_ERR("Failed to enter half sleep/%u", __LINE__);
212 		return ret;
213 	}
214 	/** Minimum half sleep duration tHS time */
215 	k_busy_wait(4);
216 
217 	return ret;
218 }
219 
memc_mspi_aps6404l_half_sleep_exit(const struct device * psram)220 static int memc_mspi_aps6404l_half_sleep_exit(const struct device *psram)
221 {
222 	const struct memc_mspi_aps6404l_config *cfg = psram->config;
223 	struct memc_mspi_aps6404l_data *data = psram->data;
224 	struct mspi_dev_cfg bkp = data->dev_cfg;
225 	int ret = 0;
226 
227 	data->dev_cfg.freq = 48000000;
228 
229 	mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_FREQUENCY,
230 			(const struct mspi_dev_cfg *)&data->dev_cfg);
231 
232 	LOG_DBG("Waking up aps6404l from half sleep/%u", __LINE__);
233 	ret = memc_mspi_aps6404l_command_write(psram, 0, 0, NULL, 0);
234 	if (ret) {
235 		LOG_ERR("Failed to exit from half sleep/%u", __LINE__);
236 		return ret;
237 	}
238 	/** Minimum half sleep exit CE to CLK setup time  */
239 	k_busy_wait(100);
240 
241 	data->dev_cfg = bkp;
242 
243 	ret = mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_FREQUENCY,
244 			      (const struct mspi_dev_cfg *)&data->dev_cfg);
245 	if (ret) {
246 		LOG_ERR("Failed to reconfigure MSPI after exiting half sleep/%u", __LINE__);
247 		return ret;
248 	}
249 
250 	return ret;
251 }
252 
memc_mspi_aps6404l_pm_action(const struct device * psram,enum pm_device_action action)253 static int memc_mspi_aps6404l_pm_action(const struct device *psram, enum pm_device_action action)
254 {
255 	switch (action) {
256 	case PM_DEVICE_ACTION_RESUME:
257 		acquire(psram);
258 		memc_mspi_aps6404l_half_sleep_exit(psram);
259 		release(psram);
260 		break;
261 
262 	case PM_DEVICE_ACTION_SUSPEND:
263 		acquire(psram);
264 		memc_mspi_aps6404l_half_sleep_enter(psram);
265 		release(psram);
266 		break;
267 
268 	default:
269 		return -ENOTSUP;
270 	}
271 
272 	return 0;
273 }
274 #endif /** IS_ENABLED(CONFIG_PM_DEVICE) */
275 
memc_mspi_aps6404l_init(const struct device * psram)276 static int memc_mspi_aps6404l_init(const struct device *psram)
277 {
278 	const struct memc_mspi_aps6404l_config *cfg = psram->config;
279 	struct memc_mspi_aps6404l_data *data = psram->data;
280 	uint8_t vendor_id;
281 
282 	if (!device_is_ready(cfg->bus)) {
283 		LOG_ERR("Controller device not ready/%u", __LINE__);
284 		return -ENODEV;
285 	}
286 
287 	switch (cfg->tar_dev_cfg.io_mode) {
288 	case MSPI_IO_MODE_SINGLE:
289 	case MSPI_IO_MODE_QUAD:
290 		break;
291 	default:
292 		LOG_ERR("Bus mode %d not supported/%u", cfg->tar_dev_cfg.io_mode, __LINE__);
293 		return -EIO;
294 	}
295 
296 	if (data->dev_cfg.io_mode == MSPI_IO_MODE_QUAD) {
297 		if (mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_ALL,
298 				    &cfg->quad_cfg)) {
299 			LOG_ERR("Failed to config mspi controller/%u", __LINE__);
300 			return -EIO;
301 		}
302 		data->dev_cfg = cfg->quad_cfg;
303 		if (memc_mspi_aps6404l_reset(psram)) {
304 			LOG_ERR("Could not reset pSRAM/%u", __LINE__);
305 			return -EIO;
306 		}
307 		if (memc_mspi_aps6404l_command_write(psram, APS6404L_QUAD_MODE_EXIT, 0, NULL, 0)) {
308 			LOG_ERR("Could not exit quad mode/%u", __LINE__);
309 			return -EIO;
310 		}
311 	}
312 
313 	if (mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_ALL, &cfg->serial_cfg)) {
314 		LOG_ERR("Failed to config mspi controller/%u", __LINE__);
315 		return -EIO;
316 	}
317 	data->dev_cfg = cfg->serial_cfg;
318 
319 	if (memc_mspi_aps6404l_reset(psram)) {
320 		LOG_ERR("Could not reset pSRAM/%u", __LINE__);
321 		return -EIO;
322 	}
323 
324 	if (memc_mspi_aps6404l_get_vendor_id(psram, &vendor_id)) {
325 		LOG_ERR("Could not read vendor id/%u", __LINE__);
326 		return -EIO;
327 	}
328 	LOG_DBG("Vendor id: 0x%0x", vendor_id);
329 	if (vendor_id != APM_VENDOR_ID) {
330 		LOG_WRN("Vendor ID does not match expected value of 0x%0x/%u", APM_VENDOR_ID,
331 			__LINE__);
332 	}
333 
334 	if (cfg->tar_dev_cfg.io_mode == MSPI_IO_MODE_QUAD) {
335 		if (memc_mspi_aps6404l_command_write(psram, APS6404L_QUAD_MODE_ENTER, 0, NULL, 0)) {
336 			return -EIO;
337 		}
338 	}
339 
340 	if (mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_ALL, &cfg->tar_dev_cfg)) {
341 		LOG_ERR("Failed to config mspi controller/%u", __LINE__);
342 		return -EIO;
343 	}
344 	data->dev_cfg = cfg->tar_dev_cfg;
345 
346 #if CONFIG_MSPI_TIMING
347 	if (mspi_timing_config(cfg->bus, &cfg->dev_id, cfg->timing_cfg_mask,
348 			       (void *)&cfg->tar_timing_cfg)) {
349 		LOG_ERR("Failed to config mspi timing/%u", __LINE__);
350 		return -EIO;
351 	}
352 	data->timing_cfg = cfg->tar_timing_cfg;
353 #endif /* CONFIG_MSPI_TIMING */
354 
355 #if CONFIG_MSPI_XIP
356 	if (cfg->tar_xip_cfg.enable) {
357 		if (mspi_xip_config(cfg->bus, &cfg->dev_id, &cfg->tar_xip_cfg)) {
358 			LOG_ERR("Failed to enable XIP/%u", __LINE__);
359 			return -EIO;
360 		}
361 		data->xip_cfg = cfg->tar_xip_cfg;
362 	}
363 #endif /* CONFIG_MSPI_XIP */
364 
365 #if CONFIG_MSPI_SCRAMBLE
366 	if (cfg->tar_scramble_cfg.enable) {
367 		if (mspi_scramble_config(cfg->bus, &cfg->dev_id, &cfg->tar_scramble_cfg)) {
368 			LOG_ERR("Failed to enable scrambling/%u", __LINE__);
369 			return -EIO;
370 		}
371 		data->scramble_cfg = cfg->tar_scramble_cfg;
372 	}
373 #endif /* MSPI_SCRAMBLE */
374 
375 	release(psram);
376 
377 	return 0;
378 }
379 
380 #define MSPI_DEVICE_CONFIG_SERIAL(n)                                                              \
381 	{                                                                                         \
382 		.ce_num             = DT_INST_PROP(n, mspi_hardware_ce_num),                      \
383 		.freq               = 12000000,                                                   \
384 		.io_mode            = MSPI_IO_MODE_SINGLE,                                        \
385 		.data_rate          = MSPI_DATA_RATE_SINGLE,                                      \
386 		.cpp                = MSPI_CPP_MODE_0,                                            \
387 		.endian             = MSPI_XFER_LITTLE_ENDIAN,                                    \
388 		.ce_polarity        = MSPI_CE_ACTIVE_LOW,                                         \
389 		.dqs_enable         = false,                                                      \
390 		.rx_dummy           = 8,                                                          \
391 		.tx_dummy           = 0,                                                          \
392 		.read_cmd           = APS6404L_FAST_READ,                                         \
393 		.write_cmd          = APS6404L_WRITE,                                             \
394 		.cmd_length         = 1,                                                          \
395 		.addr_length        = 3,                                                          \
396 		.mem_boundary       = 1024,                                                        \
397 		.time_to_break      = 8,                                                         \
398 	}
399 
400 #define MSPI_DEVICE_CONFIG_QUAD(n)                                                                \
401 	{                                                                                         \
402 		.ce_num             = DT_INST_PROP(n, mspi_hardware_ce_num),                      \
403 		.freq               = 24000000,                                                   \
404 		.io_mode            = MSPI_IO_MODE_SINGLE,                                        \
405 		.data_rate          = MSPI_DATA_RATE_SINGLE,                                      \
406 		.cpp                = MSPI_CPP_MODE_0,                                            \
407 		.endian             = MSPI_XFER_LITTLE_ENDIAN,                                    \
408 		.ce_polarity        = MSPI_CE_ACTIVE_LOW,                                         \
409 		.dqs_enable         = false,                                                      \
410 		.rx_dummy           = 6,                                                          \
411 		.tx_dummy           = 0,                                                          \
412 		.read_cmd           = APS6404L_QUAD_READ,                                         \
413 		.write_cmd          = APS6404L_QUAD_WRITE,                                        \
414 		.cmd_length         = 1,                                                          \
415 		.addr_length        = 3,                                                          \
416 		.mem_boundary       = 1024,                                                        \
417 		.time_to_break      = 4,                                                         \
418 	}
419 
420 #if CONFIG_SOC_FAMILY_AMBIQ
421 #define MSPI_TIMING_CONFIG(n)                                                                     \
422 	{                                                                                         \
423 		.ui8WriteLatency    = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 0),             \
424 		.ui8TurnAround      = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 1),             \
425 		.bTxNeg             = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 2),             \
426 		.bRxNeg             = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 3),             \
427 		.bRxCap             = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 4),             \
428 		.ui32TxDQSDelay     = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 5),             \
429 		.ui32RxDQSDelay     = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 6),             \
430 		.ui32RXDQSDelayEXT  = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 7),             \
431 	}
432 #define MSPI_TIMING_CONFIG_MASK(n) DT_INST_PROP(n, ambiq_timing_config_mask)
433 #else
434 #define MSPI_TIMING_CONFIG(n) {}
435 #define MSPI_TIMING_CONFIG_MASK(n) MSPI_TIMING_PARAM_DUMMY
436 #define MSPI_PORT(n) 0
437 #endif
438 
439 #define MEMC_MSPI_APS6404L(n)                                                                     \
440 	static const struct memc_mspi_aps6404l_config                                             \
441 	memc_mspi_aps6404l_config_##n = {                                                         \
442 		.port               = MSPI_PORT(n),                                               \
443 		.mem_size           = DT_INST_PROP(n, size) / 8,                                  \
444 		.bus                = DEVICE_DT_GET(DT_INST_BUS(n)),                              \
445 		.dev_id             = MSPI_DEVICE_ID_DT_INST(n),                                  \
446 		.serial_cfg         = MSPI_DEVICE_CONFIG_SERIAL(n),                               \
447 		.quad_cfg           = MSPI_DEVICE_CONFIG_QUAD(n),                                 \
448 		.tar_dev_cfg        = MSPI_DEVICE_CONFIG_DT_INST(n),                              \
449 		.tar_xip_cfg        = MSPI_XIP_CONFIG_DT_INST(n),                                 \
450 		.tar_scramble_cfg   = MSPI_SCRAMBLE_CONFIG_DT_INST(n),                            \
451 		.tar_timing_cfg     = MSPI_TIMING_CONFIG(n),                                      \
452 		.timing_cfg_mask    = MSPI_TIMING_CONFIG_MASK(n),                                 \
453 		.sw_multi_periph    = DT_PROP(DT_INST_BUS(n), software_multiperipheral)           \
454 	};                                                                                        \
455 	static struct memc_mspi_aps6404l_data                                                     \
456 		memc_mspi_aps6404l_data_##n = {                                                   \
457 		.lock = Z_SEM_INITIALIZER(memc_mspi_aps6404l_data_##n.lock, 0, 1),                \
458 	};                                                                                        \
459 	PM_DEVICE_DT_INST_DEFINE(n, memc_mspi_aps6404l_pm_action);                                \
460 	DEVICE_DT_INST_DEFINE(n,                                                                  \
461 			      memc_mspi_aps6404l_init,                                            \
462 			      PM_DEVICE_DT_INST_GET(n),                                           \
463 			      &memc_mspi_aps6404l_data_##n,                                       \
464 			      &memc_mspi_aps6404l_config_##n,                                     \
465 			      POST_KERNEL,                                                        \
466 			      CONFIG_MEMC_INIT_PRIORITY,                                          \
467 			      NULL);
468 
469 DT_INST_FOREACH_STATUS_OKAY(MEMC_MSPI_APS6404L)
470