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