Skip to content

Commit 2b9c51b

Browse files
committed
[nrf fromtree] drivers: mspi_dw: Prevent RX FIFO overflows in Single IO mode
In Single IO mode, where the clock stretching feature is not available, the RX FIFO could get overflowed if the TX FIFO was filled with more dummy bytes than the RX FIFO could receive data items at a given moment. Such problem could be quite easy hit on nRF54H20, for example for longer RX transfers (like 8 kB) at 8 MHz. This commit limits accordingly the number of dummy bytes that can be enqueued in the TX FIFO. Signed-off-by: Andrzej Głąbek <[email protected]> (cherry picked from commit 7b6ba5c)
1 parent 79a3323 commit 2b9c51b

File tree

1 file changed

+40
-7
lines changed

1 file changed

+40
-7
lines changed

drivers/mspi/mspi_dw.c

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ struct mspi_dw_config {
7878
const struct gpio_dt_spec *ce_gpios;
7979
uint8_t ce_gpios_len;
8080
uint8_t tx_fifo_depth_minus_1;
81+
/* Maximum number of items allowed in the TX FIFO when transmitting
82+
* dummy bytes; it must be at least one less than the RX FIFO depth
83+
* to account for a byte that can be partially received (i.e. in
84+
* the shifting register) when tx_dummy_bytes() calculates how many
85+
* bytes can be written to the TX FIFO to not overflow the RX FIFO.
86+
*/
87+
uint8_t max_queued_dummy_bytes;
8188
uint8_t tx_fifo_threshold;
8289
uint8_t rx_fifo_threshold;
8390
DECLARE_REG_ACCESS();
@@ -151,7 +158,11 @@ static void tx_data(const struct device *dev,
151158

152159
if (buf_pos >= buf_end) {
153160
/* Set the threshold to 0 to get the next interrupt
154-
* when the FIFO is completely emptied.
161+
* when the FIFO is completely emptied. This also sets
162+
* the TX start level to 0, so if the transmission was
163+
* not started so far because the FIFO was not filled
164+
* up completely (the start level was set to maximum
165+
* in start_next_packet()), it will be started now.
155166
*/
156167
write_txftlr(dev, 0);
157168
break;
@@ -170,11 +181,22 @@ static bool tx_dummy_bytes(const struct device *dev)
170181
{
171182
struct mspi_dw_data *dev_data = dev->data;
172183
const struct mspi_dw_config *dev_config = dev->config;
173-
uint8_t fifo_room = dev_config->tx_fifo_depth_minus_1 + 1
184+
uint8_t fifo_room = dev_config->max_queued_dummy_bytes
174185
- FIELD_GET(TXFLR_TXTFL_MASK, read_txflr(dev));
186+
uint8_t rx_fifo_items = FIELD_GET(RXFLR_RXTFL_MASK, read_rxflr(dev));
175187
uint16_t dummy_bytes = dev_data->dummy_bytes;
176188
const uint8_t dummy_val = 0;
177189

190+
/* Subtract the number of items that are already stored in the RX
191+
* FIFO to avoid overflowing it; `max_queued_dummy_bytes` accounts
192+
* that one byte that can be partially received, thus not included
193+
* in the value from the RXFLR register.
194+
*/
195+
if (fifo_room <= rx_fifo_items) {
196+
return false;
197+
}
198+
fifo_room -= rx_fifo_items;
199+
178200
if (dummy_bytes > fifo_room) {
179201
dev_data->dummy_bytes = dummy_bytes - fifo_room;
180202

@@ -189,8 +211,10 @@ static bool tx_dummy_bytes(const struct device *dev)
189211
write_dr(dev, dummy_val);
190212
} while (--dummy_bytes);
191213

192-
/* Set the threshold to 0 to get the next interrupt when the FIFO is
193-
* completely emptied.
214+
/* Set the TX start level to 0, so that the transmission will be
215+
* started now if it hasn't been yet. The threshold value is also
216+
* set to 0 here, but it doesn't really matter, as the interrupt
217+
* will be anyway disabled.
194218
*/
195219
write_txftlr(dev, 0);
196220

@@ -290,12 +314,16 @@ static void mspi_dw_isr(const struct device *dev)
290314

291315
if (int_status & ISR_TXEIS_BIT) {
292316
if (tx_dummy_bytes(dev)) {
317+
/* All the required dummy bytes were
318+
* written to the FIFO; disable the TXE
319+
* interrupt, as it's no longer needed.
320+
*/
293321
write_imr(dev, IMR_RXFIM_BIT);
294322
}
295323

296324
int_status = read_isr(dev);
297325
}
298-
} while (int_status);
326+
} while (int_status != 0);
299327
}
300328

301329
if (finished) {
@@ -923,8 +951,11 @@ static int start_next_packet(const struct device *dev, k_timeout_t timeout)
923951
* clock stretching feature does not work yet, or in Standard
924952
* SPI mode, where the clock stretching is not available at all.
925953
*/
926-
write_txftlr(dev, FIELD_PREP(TXFTLR_TXFTHR_MASK,
927-
dev_config->tx_fifo_depth_minus_1) |
954+
uint8_t start_level = dev_data->dummy_bytes != 0
955+
? dev_config->max_queued_dummy_bytes - 1
956+
: dev_config->tx_fifo_depth_minus_1;
957+
958+
write_txftlr(dev, FIELD_PREP(TXFTLR_TXFTHR_MASK, start_level) |
928959
FIELD_PREP(TXFTLR_TFT_MASK,
929960
dev_config->tx_fifo_threshold));
930961
} else {
@@ -1406,6 +1437,8 @@ static DEVICE_API(mspi, drv_api) = {
14061437
TX_FIFO_DEPTH(inst))
14071438
#define MSPI_DW_FIFO_PROPS(inst) \
14081439
.tx_fifo_depth_minus_1 = TX_FIFO_DEPTH(inst) - 1, \
1440+
.max_queued_dummy_bytes = MIN(RX_FIFO_DEPTH(inst) - 1, \
1441+
TX_FIFO_DEPTH(inst)), \
14091442
.tx_fifo_threshold = \
14101443
DT_INST_PROP_OR(inst, tx_fifo_threshold, \
14111444
7 * TX_FIFO_DEPTH(inst) / 8 - 1), \

0 commit comments

Comments
 (0)