Skip to content

spi: dw: Fix non-DMA transmit-only transfers #6286

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 31, 2024

Conversation

pelwell
Copy link
Contributor

@pelwell pelwell commented Jul 29, 2024

Ensure the transmit FIFO has emptied before ending the transfer by dropping the TX threshold to 0 when the last byte has been pushed into the FIFO. Include a similar fix for the non-IRQ paths.

See: #6285
Fixes: 6014649 ("spi: dw: Save bandwidth with the TMOD_TO feature")

@HiassofT
Copy link
Contributor

It is a bit better now, but still not quite right, the TX transfer is often missing one or two clock cycles, see eg this screenshot where TX phase was one cycle short and the ID read back as 2881 instead of 5102:
pr-2881

I've also seen one case where the kernel reported 1440 (so 2 cycles missing) and another one where the ID was read fine but a later SPI transfer failed

@pelwell
Copy link
Contributor Author

pelwell commented Jul 29, 2024

Although the RP1 SPI interface supports transmit-only, it lacks an interrupt-on-idle. When the TX-FIFO-empty interrupt fires, there may be some data left in the TX shift register. Spinning in interrupt context is not recommended, and by the next data is ready to be sent it may not even be necessary to wait, so we can replace any post-TX-wait with a pre-transfer idle-wait.

If this works for you I'll squash it with the previous patch.

@HiassofT
Copy link
Contributor

Still no joy, in case of a single write-only transfer chip-select is de-asserted too early:
pr-write-failed

@pelwell
Copy link
Contributor Author

pelwell commented Jul 29, 2024

I was hoping not to have to resort to a timer, but I can't think of an alternative with decent performance.

Third time lucky?

@@ -246,7 +272,16 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
}
} else if (!dws->tx_len) {
dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
spi_finalize_current_transfer(dws->host);
if (dw_spi_ctlr_busy(dws)) {
dws->idle_wait_retries = 8;
Copy link
Contributor

@P33M P33M Jul 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is an analogue for bits per data element aka "word width", SPI can be configured up to 32. This value should be in one of the TX configuration registers...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be somewhere more accessible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And there was - dws->n_bytes.

@HiassofT
Copy link
Contributor

Thanks a lot for the update, testing with the cirrus logic audio card looks fine so far (also on the scope)

@pelwell
Copy link
Contributor Author

pelwell commented Jul 30, 2024

Thanks for the feedback. I'm trying to tune the wait intervals - exponential backoff feels better than up to 32 timer interrupts - but otherwise this feels like the right fix.

@pelwell
Copy link
Contributor Author

pelwell commented Jul 30, 2024

Apart from squashing the commits, this is the release candidate. It should reduce the number of interrupts taken to detect the end-of-transfer.

pelwell added 2 commits July 31, 2024 11:00
Ensure the transmit FIFO has emptied before ending the transfer by
dropping the TX threshold to 0 when the last byte has been pushed into
the FIFO. Include a similar fix for the non-IRQ paths.

See: raspberrypi#6285
Fixes: 6014649 ("spi: dw: Save bandwidth with the TMOD_TO feature")
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
The DW SPI interface has a 16-bit clock divider, where the bottom bit
of the divisor must be 0. Limit how low the clock speed can go to
prevent the clock divider from being truncated, as that could lead to
a much higher clock rate than requested.

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
@pelwell
Copy link
Contributor Author

pelwell commented Jul 31, 2024

Now tested over a wide range of speeds, during the course of which I discovered that a speed of 3kHz or lower can lead to effectively random speeds due to clock divisor overflow - now fixed in the second commit.

@pelwell pelwell merged commit e929482 into raspberrypi:rpi-6.6.y Jul 31, 2024
11 of 12 checks passed
popcornmix added a commit to raspberrypi/firmware that referenced this pull request Aug 5, 2024
kernel: spi: dw: Fix non-DMA transmit-only transfers
See: raspberrypi/linux#6286

kernel: ARM: dts: bcm2712: Fix invalid polling-delay-passive setting
See: raspberrypi/linux#6290

kernel: dtoverlays: Add overlay for HD44780 via I2C PCF8574 backpack
See: raspberrypi/linux#6293

kernel: DTS: bcm2712: enable SD slot CQE by default on Pi 5
See: raspberrypi/linux#6301
popcornmix added a commit to raspberrypi/rpi-firmware that referenced this pull request Aug 5, 2024
kernel: spi: dw: Fix non-DMA transmit-only transfers
See: raspberrypi/linux#6286

kernel: ARM: dts: bcm2712: Fix invalid polling-delay-passive setting
See: raspberrypi/linux#6290

kernel: dtoverlays: Add overlay for HD44780 via I2C PCF8574 backpack
See: raspberrypi/linux#6293

kernel: DTS: bcm2712: enable SD slot CQE by default on Pi 5
See: raspberrypi/linux#6301
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants