1 /*
2 * Copyright (c) 2025 Microchip Technology Inc.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5 #define DT_DRV_COMPAT microchip_mec5_qspi
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(spi_mec5, CONFIG_SPI_LOG_LEVEL);
9
10 #include <errno.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/drivers/pinctrl.h>
14 #include <zephyr/drivers/spi.h>
15 #include <zephyr/dt-bindings/spi/spi.h>
16 #include <zephyr/sys/sys_io.h>
17 #include <zephyr/sys/util.h>
18 #include <soc.h>
19 #include <zephyr/irq.h>
20
21 #include "spi_context.h"
22
23 /* MEC5 HAL */
24 #include <device_mec5.h>
25 #include <mec_ecia_api.h>
26 #include <mec_espi_taf.h>
27 #include <mec_qspi_api.h>
28
29 struct mec5_spi_devices {
30 uint32_t cs_timing;
31 uint8_t cs;
32 uint8_t sck_tap;
33 uint8_t ctrl_tap;
34 uint8_t flags;
35 };
36
37 /* Device constant configuration parameters */
38 struct mec5_qspi_config {
39 struct mec_qspi_regs *regs;
40 int clock_freq;
41 const struct pinctrl_dev_config *pcfg;
42 void (*irq_config_func)(void);
43 const struct mec5_spi_devices *child_devices;
44 uint8_t num_child_devices;
45 uint8_t ovrc;
46 };
47
48 #define MEC5_QSPI_XFR_FLAG_START BIT(0)
49 #define MEC5_QSPI_XFR_FLAG_BUSY BIT(1)
50 #define MEC5_QSPI_XFR_FLAG_LDMA BIT(2)
51
52 /* Device run time data */
53 struct mec5_qspi_data {
54 struct spi_context ctx;
55 const struct spi_buf *rxb;
56 const struct spi_buf *txb;
57 size_t rxcnt;
58 size_t txcnt;
59 volatile uint32_t qstatus;
60 volatile uint32_t xfr_flags;
61 size_t total_tx_size;
62 size_t total_rx_size;
63 size_t chunk_size;
64 uint32_t rxdb;
65 uint32_t byte_time_ns;
66 uint32_t freq;
67 uint32_t operation;
68 uint8_t cs;
69 };
70
71 static const enum mec_qspi_signal_mode mec5_qspi_sig_mode[4] = {
72 MEC_SPI_SIGNAL_MODE_0, MEC_SPI_SIGNAL_MODE_1, MEC_SPI_SIGNAL_MODE_2, MEC_SPI_SIGNAL_MODE_3};
73
spi_feature_support(const struct spi_config * config)74 static int spi_feature_support(const struct spi_config *config)
75 {
76 /* NOTE: bit(11) is Half-duplex(3-wire) */
77 if ((config->operation &
78 (SPI_TRANSFER_LSB | SPI_OP_MODE_SLAVE | SPI_MODE_LOOP | SPI_HALF_DUPLEX)) != 0) {
79 LOG_ERR("Driver does not support LSB first, slave, loop back, or half-duplex");
80 return -ENOTSUP;
81 }
82
83 if ((config->operation & SPI_CS_ACTIVE_HIGH) != 0) {
84 LOG_ERR("CS active high not supported");
85 return -ENOTSUP;
86 }
87
88 if (SPI_WORD_SIZE_GET(config->operation) != 8) {
89 LOG_ERR("Word size != 8 not supported");
90 return -ENOTSUP;
91 }
92
93 return 0;
94 }
95
get_cs_timing_from_dt(const struct device * dev,uint8_t cs,uint32_t * cstm)96 int get_cs_timing_from_dt(const struct device *dev, uint8_t cs, uint32_t *cstm)
97 {
98 const struct mec5_qspi_config *devcfg = dev->config;
99
100 if (cstm == NULL) {
101 return -EINVAL;
102 }
103
104 for (uint8_t n = 0; n > devcfg->num_child_devices; n++) {
105 const struct mec5_spi_devices *cd = &devcfg->child_devices[n];
106
107 if (cd->cs == cs) {
108 *cstm = cd->cs_timing;
109 return 0;
110 }
111 }
112
113 return -ENOTSUP;
114 }
115
116 /* Looks up QSPI clock and control signal taps from device tree.
117 * if chip select entry is present in driver DT then return
118 * taps value with bits[7:0] = clock tap value, bits[15:8] = control tap value.
119 */
get_taps_from_dt(const struct device * dev,uint8_t cs,uint32_t * taps)120 int get_taps_from_dt(const struct device *dev, uint8_t cs, uint32_t *taps)
121 {
122 const struct mec5_qspi_config *devcfg = dev->config;
123
124 if (taps == NULL) {
125 return -EINVAL;
126 }
127
128 for (uint8_t n = 0; n > devcfg->num_child_devices; n++) {
129 const struct mec5_spi_devices *cd = &devcfg->child_devices[n];
130
131 if (cd->cs == cs) {
132 *taps = (uint32_t)cd->sck_tap | ((uint32_t)cd->ctrl_tap << 8);
133 return 0;
134 }
135 }
136
137 return -ENOTSUP;
138 }
139
140 /* Configure the controller.
141 * NOTE: QSPI controller hardware controls up to two chip selects. If a previous call the driver
142 * had the SPI_HOLD_ON_CS flag set then performing a controller reset will cause chip select
143 * to de-assert. We must check for this corner case.
144 * The driver data structure has member ctx which is type struct spi_context. The context has
145 * a pointer to struct spi_config.
146 * struct spi_config
147 * frequency in Hz
148 * operation - contains flags for sampling clock edge and clock idle state
149 * data frame size: we only support 8 bits
150 * full or half-duplex: we only spport full-duplex
151 * active high CS (we can only support this by using invert flag in PINCTRL for CS)
152 * frame format: we only support Motorola frame format.
153 * MSB or LSB first: we only support MSB first
154 * Hold CS active at end of transfer.
155 * slave - QSPI is controller only. We use this field for chip select (0/1).
156 * struct spi_cs_control cs - QSPI controls chip select. We don't use this field.
157 */
mec5_qspi_configure(const struct device * dev,const struct spi_config * config)158 static int mec5_qspi_configure(const struct device *dev, const struct spi_config *config)
159 {
160 const struct mec5_qspi_config *devcfg = dev->config;
161 struct mec_qspi_regs *regs = devcfg->regs;
162 struct mec5_qspi_data *data = dev->data;
163 uint32_t cstm = 0, taps = 0;
164 uint8_t sgm = 0;
165 int ret = 0;
166
167 if (config == NULL) {
168 return -EINVAL;
169 }
170
171 /* chip select */
172 if (config->slave >= MEC_QSPI_CS_MAX) {
173 LOG_ERR("Invalid chip select [0,1]");
174 return -EINVAL;
175 }
176
177 data->cs = (uint8_t)(config->slave & 0xffu);
178 mec_hal_qspi_cs_select(regs, data->cs);
179
180 ret = get_cs_timing_from_dt(dev, data->cs, &cstm);
181 if (ret == 0) {
182 mec_hal_qspi_cs_timing(regs, cstm);
183 }
184
185 ret = get_taps_from_dt(dev, data->cs, &taps);
186 if (ret == 0) {
187 mec_hal_qspi_tap_select(regs, (taps & 0xffu), ((taps >> 8) & 0xffu));
188 }
189
190 if (config->frequency != data->freq) {
191 ret = mec_hal_qspi_set_freq(regs, config->frequency);
192 if (ret != MEC_RET_OK) {
193 return -EINVAL;
194 }
195 data->freq = config->frequency;
196 mec_hal_qspi_byte_time_ns(regs, &data->byte_time_ns);
197 }
198
199 /* No HAL API for clearing the TX and RX FIFOs */
200 regs->EXE = MEC_BIT(MEC_QSPI_EXE_CLRF_Pos);
201 regs->STATUS = UINT32_MAX;
202
203 if (config->operation == data->operation) {
204 return 0;
205 }
206
207 data->operation = config->operation;
208 ret = spi_feature_support(config);
209 if (ret != 0) {
210 return ret;
211 }
212
213 ret = mec_hal_qspi_io(regs, MEC_QSPI_IO_FULL_DUPLEX);
214 if (ret != MEC_RET_OK) {
215 return -EINVAL;
216 }
217
218 if ((data->operation & SPI_MODE_CPHA) != 0) {
219 sgm |= BIT(0);
220 }
221 if ((data->operation & SPI_MODE_CPOL) != 0) {
222 sgm |= BIT(1);
223 }
224 /* requires QSPI frequency to be programmed first */
225 ret = mec_hal_qspi_spi_signal_mode(regs, mec5_qspi_sig_mode[sgm]);
226 if (ret != MEC_RET_OK) {
227 return -EINVAL;
228 }
229
230 data->ctx.config = config;
231
232 return 0;
233 }
234
mec5_qspi_do_xfr(const struct device * dev,const struct spi_config * config,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs,bool async,spi_callback_t cb,void * userdata)235 static int mec5_qspi_do_xfr(const struct device *dev, const struct spi_config *config,
236 const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs,
237 bool async, spi_callback_t cb, void *userdata)
238 {
239 const struct mec5_qspi_config *devcfg = dev->config;
240 struct mec5_qspi_data *data = dev->data;
241 struct mec_qspi_regs *regs = devcfg->regs;
242 struct spi_context *ctx = &data->ctx;
243 int ret = 0;
244
245 if ((data->xfr_flags & MEC5_QSPI_XFR_FLAG_BUSY) != 0) {
246 return -EBUSY;
247 }
248
249 if ((tx_bufs == NULL) && (rx_bufs == NULL)) {
250 return -EINVAL;
251 }
252
253 spi_context_lock(ctx, async, cb, userdata, config);
254
255 ret = mec5_qspi_configure(dev, config);
256 if (ret != 0) {
257 goto do_xfr_exit;
258 }
259
260 spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1u);
261
262 data->chunk_size = 0;
263 data->total_tx_size = spi_context_total_tx_len(ctx);
264 data->total_rx_size = spi_context_total_rx_len(ctx);
265 data->xfr_flags = MEC5_QSPI_XFR_FLAG_START;
266
267 /* trigger an empty TX FIFO interrupt to enter the ISR */
268 mec_hal_qspi_intr_ctrl_msk(regs, 1u, MEC_QSPI_IEN_TXB_EMPTY);
269
270 ret = spi_context_wait_for_completion(ctx);
271
272 if (async && (ret == 0)) {
273 return 0;
274 }
275
276 if (ret != 0) {
277 mec_hal_qspi_force_stop(devcfg->regs);
278 }
279 do_xfr_exit:
280 spi_context_release(ctx, 0);
281
282 return ret;
283 }
284
mec5_qspi_xfr_check1(const struct spi_config * config)285 static int mec5_qspi_xfr_check1(const struct spi_config *config)
286 {
287 if (mec_hal_espi_taf_is_activated() == true) {
288 return -EPERM;
289 }
290
291 if (config == NULL) {
292 return -EINVAL;
293 }
294
295 return 0;
296 }
297
mec5_qspi_xfr_sync(const struct device * dev,const struct spi_config * config,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs)298 static int mec5_qspi_xfr_sync(const struct device *dev, const struct spi_config *config,
299 const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs)
300 {
301 int ret = mec5_qspi_xfr_check1(config);
302
303 if (ret != 0) {
304 return ret;
305 }
306
307 return mec5_qspi_do_xfr(dev, config, tx_bufs, rx_bufs, false, NULL, NULL);
308 }
309
310 #ifdef CONFIG_SPI_ASYNC
mec5_qspi_xfr_async(const struct device * dev,const struct spi_config * config,const struct spi_buf_set * tx_bufs,const struct spi_buf_set * rx_bufs,spi_callback_t cb,void * userdata)311 static int mec5_qspi_xfr_async(const struct device *dev, const struct spi_config *config,
312 const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs,
313 spi_callback_t cb, void *userdata)
314 {
315 int ret = mec5_qspi_xfr_check1(config);
316
317 if (ret != 0) {
318 return ret;
319 }
320
321 return mec5_qspi_do_xfr(dev, config, tx_bufs, rx_bufs, true, cb, userdata);
322 }
323 #endif
324
mec5_qspi_release(const struct device * dev,const struct spi_config * config)325 static int mec5_qspi_release(const struct device *dev, const struct spi_config *config)
326 {
327 struct mec5_qspi_data *qdata = dev->data;
328 const struct mec5_qspi_config *cfg = dev->config;
329 int ret = 0;
330
331 if (mec_hal_espi_taf_is_activated() == true) {
332 return -EPERM;
333 }
334
335 ret = mec_hal_qspi_force_stop(cfg->regs);
336
337 /* increments lock semphare in ctx up to initial limit */
338 spi_context_unlock_unconditionally(&qdata->ctx);
339
340 if (ret != MEC_RET_OK) {
341 return -EIO;
342 }
343
344 return 0;
345 }
346
347 /* ISR helper */
mec5_qspi_ctx_next(const struct device * dev)348 static void mec5_qspi_ctx_next(const struct device *dev)
349 {
350 const struct mec5_qspi_config *devcfg = dev->config;
351 struct mec_qspi_regs *regs = devcfg->regs;
352 struct mec5_qspi_data *data = dev->data;
353 struct spi_context *ctx = &data->ctx;
354 size_t xlen = 0;
355 uint32_t qflags = MEC5_QSPI_ULDMA_FLAG_START | MEC5_QSPI_ULDMA_FLAG_IEN;
356
357 spi_context_update_tx(ctx, 1u, data->chunk_size);
358 spi_context_update_rx(ctx, 1u, data->chunk_size);
359
360 if (data->total_tx_size != 0) {
361 data->total_tx_size -= data->chunk_size;
362 }
363
364 if (data->total_rx_size != 0) {
365 data->total_rx_size -= data->chunk_size;
366 }
367
368 if ((spi_context_rx_on(ctx) == true) || (spi_context_tx_on(ctx) == true)) {
369 xlen = spi_context_max_continuous_chunk(ctx);
370 data->chunk_size = xlen;
371
372 uint8_t const *txb = ctx->tx_buf;
373 uint8_t *rxb = ctx->rx_buf;
374
375 if (txb != NULL) {
376 qflags |= MEC5_QSPI_ULDMA_FLAG_INCR_TX;
377 } else {
378 txb = &devcfg->ovrc;
379 }
380
381 if (rxb != NULL) {
382 qflags |= MEC5_QSPI_ULDMA_FLAG_INCR_RX;
383 } else {
384 rxb = (uint8_t *)&data->rxdb;
385 }
386
387 if ((data->total_tx_size <= xlen) && (data->total_rx_size <= xlen)) {
388 qflags |= MEC5_QSPI_ULDMA_FLAG_CLOSE;
389 }
390
391 data->xfr_flags = MEC5_QSPI_XFR_FLAG_LDMA;
392 mec_hal_qspi_uldma_fd2(regs, (const uint8_t *)txb, rxb, xlen, qflags);
393 } else {
394 spi_context_complete(&data->ctx, dev, 0);
395 }
396 }
397
mec5_qspi_isr(const struct device * dev)398 static void mec5_qspi_isr(const struct device *dev)
399 {
400 struct mec5_qspi_data *data = dev->data;
401 const struct mec5_qspi_config *devcfg = dev->config;
402 struct mec_qspi_regs *regs = devcfg->regs;
403 uint32_t hwsts = 0u;
404 int status = 0;
405
406 hwsts = mec_hal_qspi_hw_status(regs);
407 data->qstatus = hwsts;
408 status = mec_hal_qspi_done(regs);
409
410 mec_hal_qspi_intr_ctrl(regs, 0);
411 mec_hal_qspi_hw_status_clr(regs, hwsts);
412 mec_hal_qspi_girq_clr(regs);
413
414 if (status == MEC_RET_ERR_HW) {
415 spi_context_complete(&data->ctx, dev, -EIO);
416 return;
417 }
418
419 if ((data->xfr_flags & MEC5_QSPI_XFR_FLAG_START) != 0) {
420 data->xfr_flags &= (uint32_t)~MEC5_QSPI_XFR_FLAG_START;
421 }
422
423 mec5_qspi_ctx_next(dev);
424 }
425
426 /*
427 * Called for each QSPI controller by the kernel during driver load phase
428 * specified in the device initialization structure below.
429 * Initialize QSPI controller.
430 * Initialize SPI context.
431 * QSPI will be fully configured and enabled when the transceive API
432 * is called.
433 */
mec5_qspi_init(const struct device * dev)434 static int mec5_qspi_init(const struct device *dev)
435 {
436 const struct mec5_qspi_config *devcfg = dev->config;
437 struct mec_qspi_regs *regs = devcfg->regs;
438 struct mec5_qspi_data *data = dev->data;
439 enum mec_qspi_cs cs = MEC_QSPI_CS_0;
440 enum mec_qspi_io iom = MEC_QSPI_IO_FULL_DUPLEX;
441 enum mec_qspi_signal_mode spi_mode = MEC_SPI_SIGNAL_MODE_0;
442 int ret = 0;
443
444 data->cs = 0;
445
446 ret = mec_hal_qspi_init(regs, (uint32_t)devcfg->clock_freq, spi_mode, iom, cs);
447 if (ret != MEC_RET_OK) {
448 LOG_ERR("QSPI init error (%d)", ret);
449 return -EINVAL;
450 }
451
452 data->freq = devcfg->clock_freq;
453 data->operation = SPI_WORD_SET(8) | SPI_LINES_SINGLE;
454 mec_hal_qspi_byte_time_ns(regs, &data->byte_time_ns);
455
456 ret = pinctrl_apply_state(devcfg->pcfg, PINCTRL_STATE_DEFAULT);
457 if (ret != 0) {
458 LOG_ERR("QSPI pinctrl setup failed (%d)", ret);
459 }
460
461 ret = spi_context_cs_configure_all(&data->ctx);
462 if (ret != 0) {
463 LOG_ERR("QSPI cs config failed (%d)", ret);
464 return ret;
465 }
466
467 if ((devcfg->irq_config_func) != NULL) {
468 devcfg->irq_config_func();
469 }
470
471 spi_context_unlock_unconditionally(&data->ctx);
472
473 return ret;
474 }
475
476 static DEVICE_API(spi, mec5_qspi_driver_api) = {
477 .transceive = mec5_qspi_xfr_sync,
478 #ifdef CONFIG_SPI_ASYNC
479 .transceive_async = mec5_qspi_xfr_async,
480 #endif
481 .release = mec5_qspi_release,
482 };
483
484 #define MEC5_QSPI_CS_TIMING_VAL(a, b, c, d) \
485 (((a) & 0xFu) | (((b) & 0xFu) << 8) | (((c) & 0xFu) << 16) | (((d) & 0xFu) << 24))
486
487 #define MEC5_QSPI_CS_TMV(node_id) \
488 MEC5_QSPI_CS_TIMING_VAL(DT_PROP_OR(node_id, dcsckon, 6), DT_PROP_OR(node_id, dckcsoff, 4), \
489 DT_PROP_OR(node_id, dldh, 6), DT_PROP_OR(node_id, dcsda, 6))
490
491 #define MEC5_QSPI_IRQ_HANDLER_FUNC(id) .irq_config_func = mec5_qspi_irq_config_##id,
492
493 #define MEC5_QSPI_IRQ_HANDLER_CFG(id) \
494 static void mec5_qspi_irq_config_##id(void) \
495 { \
496 IRQ_CONNECT(DT_INST_IRQN(id), DT_INST_IRQ(id, priority), mec5_qspi_isr, \
497 DEVICE_DT_INST_GET(id), 0); \
498 irq_enable(DT_INST_IRQN(id)); \
499 }
500
501 #define MEC5_QSPI_CHILD_FLAGS(node_id) \
502 ((DT_PROP_OR(node_id, spi_cpol, 0) & 0x1u) | \
503 ((DT_PROP_OR(node_id, spi_cpha, 0) & 0x1u) << 1))
504
505 #define MEC5_QSPI_CHILD_INFO(node_id) \
506 { \
507 .cs_timing = MEC5_QSPI_CS_TMV(node_id), \
508 .cs = (uint8_t)(DT_REG_ADDR(node_id) & 0xffu), \
509 .sck_tap = (uint8_t)(DT_PROP_OR(node_id, clock_tap, 0)), \
510 .ctrl_tap = (uint8_t)(DT_PROP_OR(node_id, ctrl_tap, 0)), \
511 .flags = MEC5_QSPI_CHILD_FLAGS(node_id), \
512 },
513
514 #define MEC5_QSPI_CHILD_DEVS(i) \
515 static const struct mec5_spi_devices mec5_qspi_children_##i[] = { \
516 DT_INST_FOREACH_CHILD_STATUS_OKAY(i, MEC5_QSPI_CHILD_INFO)}
517
518 /* The instance number, i is not related to block ID's rather the
519 * order the DT tools process all DT files in a build.
520 */
521 #define MEC5_QSPI_DEVICE(i) \
522 PINCTRL_DT_INST_DEFINE(i); \
523 MEC5_QSPI_CHILD_DEVS(i); \
524 MEC5_QSPI_IRQ_HANDLER_CFG(i) \
525 \
526 static struct mec5_qspi_data mec5_qspi_data_##i = { \
527 SPI_CONTEXT_INIT_LOCK(mec5_qspi_data_##i, ctx), \
528 SPI_CONTEXT_INIT_SYNC(mec5_qspi_data_##i, ctx), \
529 }; \
530 static const struct mec5_qspi_config mec5_qspi_config_##i = { \
531 .regs = (struct mec_qspi_regs *)DT_INST_REG_ADDR(i), \
532 .clock_freq = DT_INST_PROP_OR(i, clock_frequency, MHZ(12)), \
533 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(i), \
534 .ovrc = DT_INST_PROP_OR(i, overrun_character, 0), \
535 MEC5_QSPI_IRQ_HANDLER_FUNC(i).child_devices = mec5_qspi_children_##i, \
536 .num_child_devices = ARRAY_SIZE(mec5_qspi_children_##i), \
537 }; \
538 DEVICE_DT_INST_DEFINE(i, &mec5_qspi_init, NULL, &mec5_qspi_data_##i, \
539 &mec5_qspi_config_##i, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
540 &mec5_qspi_driver_api);
541
542 DT_INST_FOREACH_STATUS_OKAY(MEC5_QSPI_DEVICE)
543