@@ -71,6 +71,12 @@ struct mspi_dw_data {
71
71
/* For locking of controller configuration. */
72
72
struct k_sem cfg_lock ;
73
73
struct mspi_xfer xfer ;
74
+
75
+ #if defined(CONFIG_MSPI_DW_HANDLE_FIFOS_IN_SYSTEM_WORKQUEUE )
76
+ struct k_work fifo_work ;
77
+ const struct device * dev ;
78
+ uint32_t imr ;
79
+ #endif
74
80
};
75
81
76
82
struct mspi_dw_config {
@@ -111,7 +117,7 @@ DEFINE_MM_REG_RD_WR(rxftlr, 0x1c)
111
117
DEFINE_MM_REG_RD (txflr , 0x20 )
112
118
DEFINE_MM_REG_RD (rxflr , 0x24 )
113
119
DEFINE_MM_REG_RD (sr , 0x28 )
114
- DEFINE_MM_REG_WR (imr , 0x2c )
120
+ DEFINE_MM_REG_RD_WR (imr , 0x2c )
115
121
DEFINE_MM_REG_RD (isr , 0x30 )
116
122
DEFINE_MM_REG_RD (risr , 0x34 )
117
123
DEFINE_MM_REG_RD_WR (dr , 0x60 )
@@ -218,6 +224,8 @@ static bool tx_dummy_bytes(const struct device *dev)
218
224
write_dr (dev , dummy_val );
219
225
} while (-- dummy_bytes );
220
226
227
+ dev_data -> dummy_bytes = 0 ;
228
+
221
229
/* Set the TX start level to 0, so that the transmission will be
222
230
* started now if it hasn't been yet. The threshold value is also
223
231
* set to 0 here, but it doesn't really matter, as the interrupt
@@ -280,7 +288,18 @@ static bool read_rx_fifo(const struct device *dev,
280
288
return false;
281
289
}
282
290
283
- static void mspi_dw_isr (const struct device * dev )
291
+ static inline void set_imr (const struct device * dev , uint32_t imr )
292
+ {
293
+ #if defined(CONFIG_MSPI_DW_HANDLE_FIFOS_IN_SYSTEM_WORKQUEUE )
294
+ struct mspi_dw_data * dev_data = dev -> data ;
295
+
296
+ dev_data -> imr = imr ;
297
+ #else
298
+ write_imr (dev , imr );
299
+ #endif
300
+ }
301
+
302
+ static void handle_fifos (const struct device * dev )
284
303
{
285
304
struct mspi_dw_data * dev_data = dev -> data ;
286
305
const struct mspi_xfer_packet * packet =
@@ -302,42 +321,82 @@ static void mspi_dw_isr(const struct device *dev)
302
321
finished = true;
303
322
}
304
323
} else {
305
- uint32_t int_status = read_isr (dev );
324
+ for (;;) {
325
+ /* Use RISR, not ISR, because when this function is
326
+ * executed through the system workqueue, all interrupts
327
+ * are masked (IMR is 0).
328
+ */
329
+ uint32_t int_status = read_risr (dev );
306
330
307
- do {
308
- if (int_status & ISR_RXFIS_BIT ) {
331
+ if (int_status & RISR_RXFIR_BIT ) {
309
332
if (read_rx_fifo (dev , packet )) {
310
333
finished = true;
311
334
break ;
312
335
}
313
336
314
- if (read_risr ( dev ) & RISR_RXOIR_BIT ) {
337
+ if (int_status & RISR_RXOIR_BIT ) {
315
338
finished = true;
316
339
break ;
317
340
}
318
341
319
- int_status = read_isr (dev );
342
+ /* Refresh interrupt status, as during reading
343
+ * from the RX FIFO, the TX FIFO status might
344
+ * have changed.
345
+ */
346
+ int_status = read_risr (dev );
320
347
}
321
348
322
- if (int_status & ISR_TXEIS_BIT ) {
323
- if (tx_dummy_bytes (dev )) {
324
- /* All the required dummy bytes were
325
- * written to the FIFO; disable the TXE
326
- * interrupt, as it's no longer needed.
327
- */
328
- write_imr (dev , IMR_RXFIM_BIT );
329
- }
349
+ if (dev_data -> dummy_bytes == 0 ||
350
+ !(int_status & RISR_TXEIR_BIT )) {
351
+ break ;
352
+ }
330
353
331
- int_status = read_isr (dev );
354
+ if (tx_dummy_bytes (dev )) {
355
+ /* All the required dummy bytes were written
356
+ * to the FIFO; disable the TXE interrupt,
357
+ * as it's no longer needed.
358
+ */
359
+ set_imr (dev , IMR_RXFIM_BIT );
332
360
}
333
- } while ( int_status != 0 );
361
+ }
334
362
}
335
363
336
364
if (finished ) {
337
- write_imr (dev , 0 );
365
+ set_imr (dev , 0 );
338
366
339
367
k_sem_give (& dev_data -> finished );
340
368
}
369
+ }
370
+
371
+ #if defined(CONFIG_MSPI_DW_HANDLE_FIFOS_IN_SYSTEM_WORKQUEUE )
372
+ static void fifo_work_handler (struct k_work * work )
373
+ {
374
+ struct mspi_dw_data * dev_data =
375
+ CONTAINER_OF (work , struct mspi_dw_data , fifo_work );
376
+ const struct device * dev = dev_data -> dev ;
377
+
378
+ handle_fifos (dev );
379
+
380
+ write_imr (dev , dev_data -> imr );
381
+ }
382
+ #endif
383
+
384
+ static void mspi_dw_isr (const struct device * dev )
385
+ {
386
+ #if defined(CONFIG_MSPI_DW_HANDLE_FIFOS_IN_SYSTEM_WORKQUEUE )
387
+ struct mspi_dw_data * dev_data = dev -> data ;
388
+ int rc ;
389
+
390
+ dev_data -> imr = read_imr (dev );
391
+ write_imr (dev , 0 );
392
+
393
+ rc = k_work_submit (& dev_data -> fifo_work );
394
+ if (rc < 0 ) {
395
+ LOG_ERR ("k_work_submit failed: %d\n" , rc );
396
+ }
397
+ #else
398
+ handle_fifos (dev );
399
+ #endif
341
400
342
401
vendor_specific_irq_clear (dev );
343
402
}
@@ -1426,6 +1485,11 @@ static int dev_init(const struct device *dev)
1426
1485
k_sem_init (& dev_data -> cfg_lock , 1 , 1 );
1427
1486
k_sem_init (& dev_data -> ctx_lock , 1 , 1 );
1428
1487
1488
+ #if defined(CONFIG_MSPI_DW_HANDLE_FIFOS_IN_SYSTEM_WORKQUEUE )
1489
+ dev_data -> dev = dev ;
1490
+ k_work_init (& dev_data -> fifo_work , fifo_work_handler );
1491
+ #endif
1492
+
1429
1493
for (ce_gpio = dev_config -> ce_gpios ;
1430
1494
ce_gpio < & dev_config -> ce_gpios [dev_config -> ce_gpios_len ];
1431
1495
ce_gpio ++ ) {
0 commit comments