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