@@ -71,6 +71,12 @@ struct mspi_dw_data {
7171 /* For locking of controller configuration. */
7272 struct k_sem cfg_lock ;
7373 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
7480};
7581
7682struct mspi_dw_config {
@@ -111,7 +117,7 @@ DEFINE_MM_REG_RD_WR(rxftlr, 0x1c)
111117DEFINE_MM_REG_RD (txflr , 0x20 )
112118DEFINE_MM_REG_RD (rxflr , 0x24 )
113119DEFINE_MM_REG_RD (sr , 0x28 )
114- DEFINE_MM_REG_WR (imr , 0x2c )
120+ DEFINE_MM_REG_RD_WR (imr , 0x2c )
115121DEFINE_MM_REG_RD (isr , 0x30 )
116122DEFINE_MM_REG_RD (risr , 0x34 )
117123DEFINE_MM_REG_RD_WR (dr , 0x60 )
@@ -218,6 +224,8 @@ static bool tx_dummy_bytes(const struct device *dev)
218224 write_dr (dev , dummy_val );
219225 } while (-- dummy_bytes );
220226
227+ dev_data -> dummy_bytes = 0 ;
228+
221229 /* Set the TX start level to 0, so that the transmission will be
222230 * started now if it hasn't been yet. The threshold value is also
223231 * 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,
280288 return false;
281289}
282290
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 )
284303{
285304 struct mspi_dw_data * dev_data = dev -> data ;
286305 const struct mspi_xfer_packet * packet =
@@ -302,42 +321,82 @@ static void mspi_dw_isr(const struct device *dev)
302321 finished = true;
303322 }
304323 } 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 );
306330
307- do {
308- if (int_status & ISR_RXFIS_BIT ) {
331+ if (int_status & RISR_RXFIR_BIT ) {
309332 if (read_rx_fifo (dev , packet )) {
310333 finished = true;
311334 break ;
312335 }
313336
314- if (read_risr ( dev ) & RISR_RXOIR_BIT ) {
337+ if (int_status & RISR_RXOIR_BIT ) {
315338 finished = true;
316339 break ;
317340 }
318341
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 );
320347 }
321348
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+ }
330353
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 );
332360 }
333- } while ( int_status != 0 );
361+ }
334362 }
335363
336364 if (finished ) {
337- write_imr (dev , 0 );
365+ set_imr (dev , 0 );
338366
339367 k_sem_give (& dev_data -> finished );
340368 }
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
341400
342401 vendor_specific_irq_clear (dev );
343402}
@@ -1426,6 +1485,11 @@ static int dev_init(const struct device *dev)
14261485 k_sem_init (& dev_data -> cfg_lock , 1 , 1 );
14271486 k_sem_init (& dev_data -> ctx_lock , 1 , 1 );
14281487
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+
14291493 for (ce_gpio = dev_config -> ce_gpios ;
14301494 ce_gpio < & dev_config -> ce_gpios [dev_config -> ce_gpios_len ];
14311495 ce_gpio ++ ) {
0 commit comments