Skip to content

Commit 2e0357c

Browse files
decsnydkalowsk
authored andcommitted
drivers: spi_nxp_lpspi: Fix extra byte issue on v1
The interrupt handling was not deterministic before because it relied on "guessing" if the lpspi was a v1 type that was stalling due to design errata. This obviously ended up being wrong in some cases. So we really need to fix this so that it is deterministic, and my idea to do that is to explicitly count how many words we have written to the TX fifo throughout the whole transfer. As a side effect of making the IRQ more deterministic, we can't support the SPI_HOLD_ON_CS flag for v1 LPSPI anymore. It is fundamentally impossible due to the fact that the transfer can only complete in hardware as a result of CS deasserting. If this is absolutely a requirement to support this flag in the future, my recommendation is to update the driver so that it muxes the pin to a gpio before ending the transfer, but that would kind of defeat the point of having a native CS, at least at the end of the xfer. Signed-off-by: Declan Snyder <declan.snyder@nxp.com>
1 parent 0574ac7 commit 2e0357c

File tree

1 file changed

+69
-56
lines changed

1 file changed

+69
-56
lines changed

drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c

Lines changed: 69 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ LOG_MODULE_DECLARE(spi_lpspi, CONFIG_SPI_LOG_LEVEL);
1212
#include "spi_nxp_lpspi_priv.h"
1313

1414
struct lpspi_driver_data {
15+
size_t total_words_to_clock;
16+
size_t words_clocked;
1517
uint8_t word_size_bytes;
1618
uint8_t lpspi_op_mode;
1719
};
@@ -72,10 +74,10 @@ static inline void lpspi_handle_rx_irq(const struct device *dev)
7274
struct lpspi_data *data = dev->data;
7375
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
7476
struct spi_context *ctx = &data->ctx;
75-
uint8_t rx_fsr = rx_fifo_cur_len(base);
7677
uint8_t total_words_written = 0;
7778
uint8_t total_words_read = 0;
7879
uint8_t words_read;
80+
uint8_t rx_fsr;
7981

8082
base->SR = LPSPI_SR_RDF_MASK;
8183

@@ -125,18 +127,22 @@ static inline void lpspi_fill_tx_fifo(const struct device *dev, const uint8_t *b
125127
buf_len -= word_size;
126128
}
127129

130+
lpspi_data->words_clocked += fill_len;
128131
LOG_DBG("Filled TX FIFO to %d words (%d bytes)", fill_len, offset);
129132
}
130133

131134
/* just fills TX fifo with the specified amount of NOPS */
132135
static void lpspi_fill_tx_fifo_nop(const struct device *dev, size_t fill_len)
133136
{
134137
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
138+
struct lpspi_data *data = dev->data;
139+
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
135140

136141
for (int i = 0; i < fill_len; i++) {
137142
base->TDR = 0;
138143
}
139144

145+
lpspi_data->words_clocked += fill_len;
140146
LOG_DBG("Filled TX fifo with %d NOPs", fill_len);
141147
}
142148

@@ -243,15 +249,14 @@ static void lpspi_isr(const struct device *dev)
243249
struct lpspi_data *data = dev->data;
244250
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
245251
uint8_t word_size_bytes = lpspi_data->word_size_bytes;
246-
uint8_t op_mode = lpspi_data->lpspi_op_mode;
247252
struct spi_context *ctx = &data->ctx;
248253
uint32_t status_flags = base->SR;
249254

250-
if (status_flags & LPSPI_SR_RDF_MASK) {
255+
if (status_flags & LPSPI_SR_RDF_MASK && base->IER & LPSPI_IER_RDIE_MASK) {
251256
lpspi_handle_rx_irq(dev);
252257
}
253258

254-
if (status_flags & LPSPI_SR_TDF_MASK) {
259+
if (status_flags & LPSPI_SR_TDF_MASK && base->IER & LPSPI_IER_TDIE_MASK) {
255260
lpspi_handle_tx_irq(dev);
256261
}
257262

@@ -264,65 +269,59 @@ static void lpspi_isr(const struct device *dev)
264269
return;
265270
}
266271

267-
/* the lpspi v1 has an errata where it doesn't clock the last bit
268-
* in continuous master mode until you write the TCR
269-
*/
270-
bool likely_stalling_v1 = (data->major_version < 2) && (op_mode == SPI_OP_MODE_MASTER) &&
271-
(DIV_ROUND_UP(spi_context_rx_len_left(ctx, word_size_bytes), word_size_bytes) == 1);
272-
273-
if (spi_context_rx_on(ctx)) {
274-
/* capture these values because they could change during this code block */
275-
size_t rx_fifo_len = rx_fifo_cur_len(base);
276-
size_t tx_fifo_len = tx_fifo_cur_len(base);
277-
278-
/*
279-
* Goal here is to provide the number of TX NOPS to match the amount of RX
280-
* we have left to receive, so that we provide the correct number of
281-
* clocks to the bus, since the clocks only happen when TX data is being sent.
282-
*
283-
* The expected RX left is essentially what is left in the spi transfer
284-
* minus what we have just got in the fifo, but prevent underflow of this
285-
* subtraction since it is unsigned.
286-
*/
287-
size_t expected_rx_left = rx_fifo_len < ctx->rx_len ? ctx->rx_len - rx_fifo_len : 0;
272+
/* Both receive and transmit parts disable their interrupt once finished. */
273+
if (base->IER == 0) {
274+
lpspi_end_xfer(dev);
275+
return;
276+
}
288277

278+
/* only explanation at this point is one of two things:
279+
* 1) that rx is bigger than tx and we need to clock nops
280+
* 2) this is a version of LPSPI which will not clock the last bit of the transfer
281+
* in continuous mode until the TCR is written to end the XFER
282+
*/
289283

290-
/*
291-
* We know the expected amount of RX we have left but only fill up to the
292-
* max of the RX fifo size so that we don't have some overflow of the FIFO later.
293-
* Similarly, we shouldn't overfill the TX fifo with too many NOPs.
284+
if (lpspi_data->words_clocked >= lpspi_data->total_words_to_clock) {
285+
/* Due to stalling behavior on older LPSPI, if we know we already wrote all the
286+
* words into the fifo, then we need to end xfer manually by writing TCR
287+
* in order to get last bit clocked out on bus. So all we need to do is touch the
288+
* TCR by writing to fifo through TCR register and wait for final RX interrupt.
294289
*/
295-
size_t tx_fifo_space_left = config->tx_fifo_size - tx_fifo_len;
296-
size_t rx_fifo_space_left = config->rx_fifo_size - rx_fifo_len;
297-
size_t max_fifo_fill = MIN(tx_fifo_space_left, rx_fifo_space_left);
298-
size_t max_fill = MIN(max_fifo_fill, expected_rx_left);
299-
300-
if (likely_stalling_v1 && max_fill > 0) {
301-
max_fill -= 1;
302-
}
290+
base->TCR = base->TCR;
291+
return;
292+
}
303293

304-
/* If we already have some words in the tx fifo, we should count those */
305-
if (max_fill > tx_fifo_len) {
306-
max_fill -= tx_fifo_len;
307-
} else {
308-
max_fill = 0;
309-
}
294+
/* At this point we know only case is that we need to put NOPs in the TX fifo
295+
* in order to get the rest of the RX
296+
*/
310297

311-
/* So now we want to fill the fifo with the max amount of NOPs */
312-
lpspi_fill_tx_fifo_nop(dev, max_fill);
313-
}
298+
size_t rx_fifo_len = rx_fifo_cur_len(base);
299+
size_t tx_fifo_len = tx_fifo_cur_len(base);
300+
size_t words_really_left = lpspi_data->total_words_to_clock - lpspi_data->words_clocked;
301+
302+
/*
303+
* Goal here is to provide the number of TX NOPS to match the amount of RX
304+
* we have left to receive, so that we provide the correct number of
305+
* clocks to the bus, since the clocks only happen when TX data is being sent.
306+
*
307+
* The expected RX left is essentially what is left in the spi transfer
308+
* minus what we have just got in the fifo, but prevent underflow of this
309+
* subtraction since it is unsigned.
310+
*/
311+
size_t expected_rx_left = rx_fifo_len < words_really_left ?
312+
words_really_left - rx_fifo_len : 0;
314313

315-
if (likely_stalling_v1) {
316-
/* Due to stalling behavior on older LPSPI,
317-
* need to end xfer in order to get last bit clocked out on bus.
318-
*/
319-
base->TCR |= LPSPI_TCR_CONT_MASK;
320-
}
314+
/*
315+
* We know the expected amount of RX we have left but only fill up to the
316+
* max of the RX fifo size so that we don't have some overflow of the FIFO later.
317+
* Similarly, we shouldn't overfill the TX fifo with too many NOPs.
318+
*/
319+
size_t tx_fifo_space_left = config->tx_fifo_size - tx_fifo_len;
320+
size_t rx_fifo_space_left = config->rx_fifo_size - rx_fifo_len;
321+
size_t max_fifo_fill = MIN(tx_fifo_space_left, rx_fifo_space_left);
322+
size_t max_fill = MIN(max_fifo_fill, expected_rx_left);
321323

322-
/* Both receive and transmit parts disable their interrupt once finished. */
323-
if (base->IER == 0) {
324-
lpspi_end_xfer(dev);
325-
}
324+
lpspi_fill_tx_fifo_nop(dev, max_fill);
326325
}
327326

328327
static void lpspi_master_setup_native_cs(const struct device *dev, const struct spi_config *spi_cfg)
@@ -372,6 +371,14 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
372371
goto error;
373372
}
374373

374+
if (data->major_version < 2 && spi_cfg->operation & SPI_HOLD_ON_CS) {
375+
/* on this version of LPSPI, due to errata in design
376+
* CS must be deasserted in order to clock all words,
377+
* so HOLD_ON_CS flag cannot be supported.
378+
*/
379+
return -EINVAL;
380+
}
381+
375382
spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, lpspi_data->word_size_bytes);
376383
lpspi_data->lpspi_op_mode = op_mode;
377384

@@ -384,6 +391,12 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
384391
base->IER = 0;
385392
base->SR |= LPSPI_INTERRUPT_BITS;
386393

394+
size_t max_side_clocks = MAX(spi_context_total_tx_len(ctx), spi_context_total_rx_len(ctx));
395+
396+
lpspi_data->total_words_to_clock =
397+
DIV_ROUND_UP(max_side_clocks, lpspi_data->word_size_bytes);
398+
lpspi_data->words_clocked = 0;
399+
387400
LOG_DBG("Starting LPSPI transfer");
388401
spi_context_cs_control(ctx, true);
389402

0 commit comments

Comments
 (0)