Skip to content

Commit e9d964f

Browse files
decsnynashif
authored andcommitted
spi_nxp_lpspi: Fix fifo fill logic
Fixing some issues with the TX fifo fill logic in two places: First in the normal fill function, it didn't take into account a situation where the TX fifo is already partially filled. This currently doesn't cause a problem because the driver is written in a way that the watermark is always 0 for TDF, but in case the watermark were anything else it would cause a problem. Second, when filling the TX fifo with NOPS in order to clock the rest of the RX in from the bus, the calculation regarding the current TX fifo length was just wrong and was leading to a bug in some cases where there was a subtraction underflow and billions of NOPs were being filled. Also, there could be a problem where a few extra NOPs are put in the TX fifo if we don't count what we already have in the TX fifo, so fixing that as well. Signed-off-by: Declan Snyder <declan.snyder@nxp.com>
1 parent 7aa0778 commit e9d964f

File tree

1 file changed

+34
-8
lines changed

1 file changed

+34
-8
lines changed

drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,14 @@ static void lpspi_fill_tx_fifo_nop(const struct device *dev, size_t fill_len)
144144
static void lpspi_next_tx_fill(const struct device *dev)
145145
{
146146
const struct lpspi_config *config = dev->config;
147+
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
147148
struct lpspi_data *data = dev->data;
148149
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
149150
struct spi_context *ctx = &data->ctx;
150-
size_t fill_len;
151+
uint8_t left_in_fifo = tx_fifo_cur_len(base);
152+
size_t fill_len = MIN(ctx->tx_len, config->tx_fifo_size - left_in_fifo);
151153
size_t actual_filled = 0;
152154

153-
fill_len = MIN(ctx->tx_len, config->tx_fifo_size);
154-
155155
const struct spi_buf *current_buf = ctx->current_tx;
156156
const uint8_t *cur_buf_pos = ctx->tx_buf;
157157
size_t cur_buf_len_left = ctx->tx_len;
@@ -254,15 +254,41 @@ static void lpspi_isr(const struct device *dev)
254254
}
255255

256256
if (spi_context_rx_on(ctx)) {
257+
/* capture these values because they could change during this code block */
257258
size_t rx_fifo_len = rx_fifo_cur_len(base);
259+
size_t tx_fifo_len = tx_fifo_cur_len(base);
260+
261+
/*
262+
* Goal here is to provide the number of TX NOPS to match the amount of RX
263+
* we have left to receive, so that we provide the correct number of
264+
* clocks to the bus, since the clocks only happen when TX data is being sent.
265+
*
266+
* The expected RX left is essentially what is left in the spi transfer
267+
* minus what we have just got in the fifo, but prevent underflow of this
268+
* subtraction since it is unsigned.
269+
*/
258270
size_t expected_rx_left = rx_fifo_len < ctx->rx_len ? ctx->rx_len - rx_fifo_len : 0;
259-
size_t max_fill = MIN(expected_rx_left, config->rx_fifo_size);
260-
size_t tx_current_fifo_len = tx_fifo_cur_len(base);
261271

262-
size_t fill_len = tx_current_fifo_len < ctx->rx_len ?
263-
max_fill - tx_current_fifo_len : 0;
264272

265-
lpspi_fill_tx_fifo_nop(dev, fill_len);
273+
/*
274+
* We know the expected amount of RX we have left but only fill up to the
275+
* max of the RX fifo size so that we don't have some overflow of the FIFO later.
276+
* Similarly, we shouldn't overfill the TX fifo with too many NOPs.
277+
*/
278+
size_t tx_fifo_space_left = config->tx_fifo_size - tx_fifo_len;
279+
size_t rx_fifo_space_left = config->rx_fifo_size - rx_fifo_len;
280+
size_t max_fifo_fill = MIN(tx_fifo_space_left, rx_fifo_space_left);
281+
size_t max_fill = MIN(max_fifo_fill, expected_rx_left);
282+
283+
/* If we already have some words in the tx fifo, we should count those */
284+
if (max_fill > tx_fifo_len) {
285+
max_fill -= tx_fifo_len;
286+
} else {
287+
max_fill = 0;
288+
}
289+
290+
/* So now we want to fill the fifo with the max amount of NOPs */
291+
lpspi_fill_tx_fifo_nop(dev, max_fill);
266292
}
267293

268294
if ((DIV_ROUND_UP(spi_context_rx_len_left(ctx, word_size_bytes), word_size_bytes) == 1) &&

0 commit comments

Comments
 (0)