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 
acquire(const struct device * psram)138 static void acquire(const struct device *psram)
139 {
140 	const struct memc_mspi_aps6404l_config *cfg = psram->config;
141 	struct memc_mspi_aps6404l_data *data = psram->data;
142 
143 	k_sem_take(&data->lock, K_FOREVER);
144 
145 	if (cfg->sw_multi_periph) {
146 		while (mspi_dev_config(cfg->bus, &cfg->dev_id,
147 				       MSPI_DEVICE_CONFIG_ALL, &data->dev_cfg))
148 			;
149 	} else {
150 		while (mspi_dev_config(cfg->bus, &cfg->dev_id,
151 				       MSPI_DEVICE_CONFIG_NONE, NULL))
152 			;
153 
154 	}
155 }
156 
release(const struct device * psram)157 static void release(const struct device *psram)
158 {
159 	const struct memc_mspi_aps6404l_config *cfg = psram->config;
160 	struct memc_mspi_aps6404l_data *data = psram->data;
161 
162 	while (mspi_get_channel_status(cfg->bus, cfg->port))
163 		;
164 
165 	k_sem_give(&data->lock);
166 }
167 
memc_mspi_aps6404l_reset(const struct device * psram)168 static int memc_mspi_aps6404l_reset(const struct device *psram)
169 {
170 	int ret;
171 
172 	LOG_DBG("Resetting aps6404l/%u", __LINE__);
173 
174 	ret = memc_mspi_aps6404l_command_write(psram, APS6404L_RESET_ENABLE, 0, NULL, 0);
175 	if (ret) {
176 		return ret;
177 	}
178 	ret = memc_mspi_aps6404l_command_write(psram, APS6404L_RESET_MEMORY, 0, NULL, 0);
179 	if (ret) {
180 		return ret;
181 	}
182 	/** We need to delay 5 ms to allow aps6404L pSRAM to reinitialize */
183 	k_busy_wait(5000);
184 	return ret;
185 }
186 
memc_mspi_aps6404l_get_vendor_id(const struct device * psram,uint8_t * vendor_id)187 static int memc_mspi_aps6404l_get_vendor_id(const struct device *psram, uint8_t *vendor_id)
188 {
189 	uint16_t buffer = 0;
190 	int ret;
191 
192 	ret = memc_mspi_aps6404l_command_read(psram, APS6404L_READ_ID, 0, (uint8_t *)&buffer, 2);
193 	LOG_DBG("Read ID buff: %x/%u", buffer, __LINE__);
194 	*vendor_id = buffer & 0xff;
195 
196 	return ret;
197 }
198 
199 #if CONFIG_PM_DEVICE
memc_mspi_aps6404l_half_sleep_enter(const struct device * psram)200 static int memc_mspi_aps6404l_half_sleep_enter(const struct device *psram)
201 {
202 	int ret;
203 
204 	LOG_DBG("Putting aps6404l to half sleep/%u", __LINE__);
205 	ret = memc_mspi_aps6404l_command_write(psram, APS6404L_HALF_SLEEP_ENTER, 0, NULL, 0);
206 	if (ret) {
207 		LOG_ERR("Failed to enter half sleep/%u", __LINE__);
208 		return ret;
209 	}
210 	/** Minimum half sleep duration tHS time */
211 	k_busy_wait(4);
212 
213 	return ret;
214 }
215 
memc_mspi_aps6404l_half_sleep_exit(const struct device * psram)216 static int memc_mspi_aps6404l_half_sleep_exit(const struct device *psram)
217 {
218 	const struct memc_mspi_aps6404l_config *cfg = psram->config;
219 	struct memc_mspi_aps6404l_data *data = psram->data;
220 	struct mspi_dev_cfg bkp = data->dev_cfg;
221 	int ret = 0;
222 
223 	data->dev_cfg.freq = 48000000;
224 
225 	mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_FREQUENCY,
226 			(const struct mspi_dev_cfg *)&data->dev_cfg);
227 
228 	LOG_DBG("Waking up aps6404l from half sleep/%u", __LINE__);
229 	ret = memc_mspi_aps6404l_command_write(psram, 0, 0, NULL, 0);
230 	if (ret) {
231 		LOG_ERR("Failed to exit from half sleep/%u", __LINE__);
232 		return ret;
233 	}
234 	/** Minimum half sleep exit CE to CLK setup time  */
235 	k_busy_wait(100);
236 
237 	data->dev_cfg = bkp;
238 
239 	ret = mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_FREQUENCY,
240 			      (const struct mspi_dev_cfg *)&data->dev_cfg);
241 	if (ret) {
242 		LOG_ERR("Failed to reconfigure MSPI after exiting half sleep/%u", __LINE__);
243 		return ret;
244 	}
245 
246 	return ret;
247 }
248 
memc_mspi_aps6404l_pm_action(const struct device * psram,enum pm_device_action action)249 static int memc_mspi_aps6404l_pm_action(const struct device *psram, enum pm_device_action action)
250 {
251 	switch (action) {
252 	case PM_DEVICE_ACTION_RESUME:
253 		acquire(psram);
254 		memc_mspi_aps6404l_half_sleep_exit(psram);
255 		release(psram);
256 		break;
257 
258 	case PM_DEVICE_ACTION_SUSPEND:
259 		acquire(psram);
260 		memc_mspi_aps6404l_half_sleep_enter(psram);
261 		release(psram);
262 		break;
263 
264 	default:
265 		return -ENOTSUP;
266 	}
267 
268 	return 0;
269 }
270 #endif /** IS_ENABLED(CONFIG_PM_DEVICE) */
271 
memc_mspi_aps6404l_init(const struct device * psram)272 static int memc_mspi_aps6404l_init(const struct device *psram)
273 {
274 	const struct memc_mspi_aps6404l_config *cfg = psram->config;
275 	struct memc_mspi_aps6404l_data *data = psram->data;
276 	uint8_t vendor_id;
277 
278 	if (!device_is_ready(cfg->bus)) {
279 		LOG_ERR("Controller device not ready/%u", __LINE__);
280 		return -ENODEV;
281 	}
282 
283 	switch (cfg->tar_dev_cfg.io_mode) {
284 	case MSPI_IO_MODE_SINGLE:
285 	case MSPI_IO_MODE_QUAD:
286 		break;
287 	default:
288 		LOG_ERR("Bus mode %d not supported/%u", cfg->tar_dev_cfg.io_mode, __LINE__);
289 		return -EIO;
290 	}
291 
292 	if (data->dev_cfg.io_mode == MSPI_IO_MODE_QUAD) {
293 		if (mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_ALL,
294 				    &cfg->quad_cfg)) {
295 			LOG_ERR("Failed to config mspi controller/%u", __LINE__);
296 			return -EIO;
297 		}
298 		data->dev_cfg = cfg->quad_cfg;
299 		if (memc_mspi_aps6404l_reset(psram)) {
300 			LOG_ERR("Could not reset pSRAM/%u", __LINE__);
301 			return -EIO;
302 		}
303 		if (memc_mspi_aps6404l_command_write(psram, APS6404L_QUAD_MODE_EXIT, 0, NULL, 0)) {
304 			LOG_ERR("Could not exit quad mode/%u", __LINE__);
305 			return -EIO;
306 		}
307 	}
308 
309 	if (mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_ALL, &cfg->serial_cfg)) {
310 		LOG_ERR("Failed to config mspi controller/%u", __LINE__);
311 		return -EIO;
312 	}
313 	data->dev_cfg = cfg->serial_cfg;
314 
315 	if (memc_mspi_aps6404l_reset(psram)) {
316 		LOG_ERR("Could not reset pSRAM/%u", __LINE__);
317 		return -EIO;
318 	}
319 
320 	if (memc_mspi_aps6404l_get_vendor_id(psram, &vendor_id)) {
321 		LOG_ERR("Could not read vendor id/%u", __LINE__);
322 		return -EIO;
323 	}
324 	LOG_DBG("Vendor id: 0x%0x", vendor_id);
325 	if (vendor_id != APM_VENDOR_ID) {
326 		LOG_WRN("Vendor ID does not match expected value of 0x%0x/%u", APM_VENDOR_ID,
327 			__LINE__);
328 	}
329 
330 	if (cfg->tar_dev_cfg.io_mode == MSPI_IO_MODE_QUAD) {
331 		if (memc_mspi_aps6404l_command_write(psram, APS6404L_QUAD_MODE_ENTER, 0, NULL, 0)) {
332 			return -EIO;
333 		}
334 	}
335 
336 	if (mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_ALL, &cfg->tar_dev_cfg)) {
337 		LOG_ERR("Failed to config mspi controller/%u", __LINE__);
338 		return -EIO;
339 	}
340 	data->dev_cfg = cfg->tar_dev_cfg;
341 
342 	if (mspi_timing_config(cfg->bus, &cfg->dev_id, cfg->timing_cfg_mask,
343 			       (void *)&cfg->tar_timing_cfg)) {
344 		LOG_ERR("Failed to config mspi timing/%u", __LINE__);
345 		return -EIO;
346 	}
347 	data->timing_cfg = cfg->tar_timing_cfg;
348 
349 	if (cfg->tar_xip_cfg.enable) {
350 		if (mspi_xip_config(cfg->bus, &cfg->dev_id, &cfg->tar_xip_cfg)) {
351 			LOG_ERR("Failed to enable XIP/%u", __LINE__);
352 			return -EIO;
353 		}
354 		data->xip_cfg = cfg->tar_xip_cfg;
355 	}
356 
357 	if (cfg->tar_scramble_cfg.enable) {
358 		if (mspi_scramble_config(cfg->bus, &cfg->dev_id, &cfg->tar_scramble_cfg)) {
359 			LOG_ERR("Failed to enable scrambling/%u", __LINE__);
360 			return -EIO;
361 		}
362 		data->scramble_cfg = cfg->tar_scramble_cfg;
363 	}
364 
365 	release(psram);
366 
367 	return 0;
368 }
369 
370 #define MSPI_DEVICE_CONFIG_SERIAL(n)                                                              \
371 	{                                                                                         \
372 		.ce_num             = DT_INST_PROP(n, mspi_hardware_ce_num),                      \
373 		.freq               = 12000000,                                                   \
374 		.io_mode            = MSPI_IO_MODE_SINGLE,                                        \
375 		.data_rate          = MSPI_DATA_RATE_SINGLE,                                      \
376 		.cpp                = MSPI_CPP_MODE_0,                                            \
377 		.endian             = MSPI_XFER_LITTLE_ENDIAN,                                    \
378 		.ce_polarity        = MSPI_CE_ACTIVE_LOW,                                         \
379 		.dqs_enable         = false,                                                      \
380 		.rx_dummy           = 8,                                                          \
381 		.tx_dummy           = 0,                                                          \
382 		.read_cmd           = APS6404L_FAST_READ,                                         \
383 		.write_cmd          = APS6404L_WRITE,                                             \
384 		.cmd_length         = 1,                                                          \
385 		.addr_length        = 3,                                                          \
386 		.mem_boundary       = 1024,                                                        \
387 		.time_to_break      = 8,                                                         \
388 	}
389 
390 #define MSPI_DEVICE_CONFIG_QUAD(n)                                                                \
391 	{                                                                                         \
392 		.ce_num             = DT_INST_PROP(n, mspi_hardware_ce_num),                      \
393 		.freq               = 24000000,                                                   \
394 		.io_mode            = MSPI_IO_MODE_SINGLE,                                        \
395 		.data_rate          = MSPI_DATA_RATE_SINGLE,                                      \
396 		.cpp                = MSPI_CPP_MODE_0,                                            \
397 		.endian             = MSPI_XFER_LITTLE_ENDIAN,                                    \
398 		.ce_polarity        = MSPI_CE_ACTIVE_LOW,                                         \
399 		.dqs_enable         = false,                                                      \
400 		.rx_dummy           = 6,                                                          \
401 		.tx_dummy           = 0,                                                          \
402 		.read_cmd           = APS6404L_QUAD_READ,                                         \
403 		.write_cmd          = APS6404L_QUAD_WRITE,                                        \
404 		.cmd_length         = 1,                                                          \
405 		.addr_length        = 3,                                                          \
406 		.mem_boundary       = 1024,                                                        \
407 		.time_to_break      = 4,                                                         \
408 	}
409 
410 #if CONFIG_SOC_FAMILY_AMBIQ
411 #define MSPI_TIMING_CONFIG(n)                                                                     \
412 	{                                                                                         \
413 		.ui8WriteLatency    = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 0),             \
414 		.ui8TurnAround      = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 1),             \
415 		.bTxNeg             = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 2),             \
416 		.bRxNeg             = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 3),             \
417 		.bRxCap             = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 4),             \
418 		.ui32TxDQSDelay     = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 5),             \
419 		.ui32RxDQSDelay     = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 6),             \
420 		.ui32RXDQSDelayEXT  = DT_INST_PROP_BY_IDX(n, ambiq_timing_config, 7),             \
421 	}
422 #define MSPI_TIMING_CONFIG_MASK(n) DT_INST_PROP(n, ambiq_timing_config_mask)
423 #else
424 #define MSPI_TIMING_CONFIG(n)
425 #define MSPI_TIMING_CONFIG_MASK(n)
426 #endif
427 
428 #define MEMC_MSPI_APS6404L(n)                                                                     \
429 	static const struct memc_mspi_aps6404l_config                                             \
430 	memc_mspi_aps6404l_config_##n = {                                                         \
431 		.port               = (DT_REG_ADDR(DT_INST_BUS(n)) - REG_MSPI_BASEADDR) /         \
432 					(DT_REG_SIZE(DT_INST_BUS(n)) * 4),                        \
433 		.mem_size           = DT_INST_PROP(n, size) / 8,                                  \
434 		.bus                = DEVICE_DT_GET(DT_INST_BUS(n)),                              \
435 		.dev_id             = MSPI_DEVICE_ID_DT_INST(n),                                  \
436 		.serial_cfg         = MSPI_DEVICE_CONFIG_SERIAL(n),                               \
437 		.quad_cfg           = MSPI_DEVICE_CONFIG_QUAD(n),                                 \
438 		.tar_dev_cfg        = MSPI_DEVICE_CONFIG_DT_INST(n),                              \
439 		.tar_xip_cfg        = MSPI_XIP_CONFIG_DT_INST(n),                                 \
440 		.tar_scramble_cfg   = MSPI_SCRAMBLE_CONFIG_DT_INST(n),                            \
441 		.tar_timing_cfg     = MSPI_TIMING_CONFIG(n),                                      \
442 		.timing_cfg_mask    = MSPI_TIMING_CONFIG_MASK(n),                                 \
443 		.sw_multi_periph    = DT_PROP(DT_INST_BUS(n), software_multiperipheral)           \
444 	};                                                                                        \
445 	static struct memc_mspi_aps6404l_data                                                     \
446 		memc_mspi_aps6404l_data_##n = {                                                   \
447 		.lock = Z_SEM_INITIALIZER(memc_mspi_aps6404l_data_##n.lock, 0, 1),                \
448 	};                                                                                        \
449 	PM_DEVICE_DT_INST_DEFINE(n, memc_mspi_aps6404l_pm_action);                                \
450 	DEVICE_DT_INST_DEFINE(n,                                                                  \
451 			      memc_mspi_aps6404l_init,                                            \
452 			      PM_DEVICE_DT_INST_GET(n),                                           \
453 			      &memc_mspi_aps6404l_data_##n,                                       \
454 			      &memc_mspi_aps6404l_config_##n,                                     \
455 			      POST_KERNEL,                                                        \
456 			      CONFIG_MEMC_INIT_PRIORITY,                                          \
457 			      NULL);
458 
459 DT_INST_FOREACH_STATUS_OKAY(MEMC_MSPI_APS6404L)
460