[PATCH v3 2/2] spi: rockchip: skip the unused FIFO direction on a one-wire device
Cole Munz <[email protected]>
| Newsgroups | org.u-boot-project.lists.u-boot |
|---|---|
| Message-ID | <7b6704538e0e5fabfa2ef8a0f2264697669fad03.1787245113.git.Munzzyy1@proton.me> |
The controller has a transfer-mode field that can run transmit-only or
receive-only instead of both, which leaves the unused FIFO out of the
transfer entirely. The driver never used it for that: claim_bus always
programmed TMOD_TR, and the only other mode came from an opportunistic
switch to TMOD_RO for read-only transfers.
A device described with spi-{tx,rx}-bus-width = <0> has no wire in that
direction at all, so now that the width reaches plat->mode as
SPI_NO_TX/SPI_NO_RX, pick the transfer mode from it. A write-only
display stops clocking receive bytes nobody reads.
The transmit-only case needs one more change. The 8-bit loop paces
itself on the receive FIFO and sets toread unconditionally, so with no
receive path it would wait on a FIFO that stays empty forever. Leave
toread at zero there and let the existing wait_till_not_busy() at the
end of the chunk handle completion, which is the same thing that
already covers a transmit component today.
The restore at the end of a read-only transfer went back to a hardcoded
TMOD_TR, which would undo the device's own mode. Restore what the mode
asks for instead.
Signed-off-by: Cole Munz <[email protected]>
Tested-by: Alexey Charkov <[email protected]>
---
Changes in v3: reworded the toread comment to name what the RX drain
was doing for the transmit path (pacing the loop against the wire),
per Quentin. Comment only; compile check rerun, exit 0.
drivers/spi/rk_spi.c | 29 +++++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c
index 2c3d70ba7159..82009e61202f 100644
--- a/drivers/spi/rk_spi.c
+++ b/drivers/spi/rk_spi.c
@@ -283,6 +283,20 @@ static int rockchip_spi_probe(struct udevice *bus)
return 0;
}
+/*
+ * A device that declares spi-{tx,rx}-bus-width = <0> has no wire in that
+ * direction, so the controller can drop the matching FIFO entirely instead
+ * of clocking bytes nobody reads.
+ */
+static u32 rkspi_base_tmod(struct rockchip_spi_priv *priv)
+{
+ if (priv->mode & SPI_NO_RX)
+ return TMOD_TO;
+ if (priv->mode & SPI_NO_TX)
+ return TMOD_RO;
+ return TMOD_TR;
+}
+
static int rockchip_spi_claim_bus(struct udevice *dev)
{
struct udevice *bus = dev->parent;
@@ -329,8 +343,8 @@ static int rockchip_spi_claim_bus(struct udevice *dev)
/* Frame Format */
ctrlr0 |= FRF_SPI << FRF_SHIFT;
- /* Tx and Rx mode */
- ctrlr0 |= TMOD_TR << TMOD_SHIFT;
+ /* Configure RX/TX mode */
+ ctrlr0 |= rkspi_base_tmod(priv) << TMOD_SHIFT;
writel(ctrlr0, ®s->ctrlr0);
@@ -472,7 +486,14 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
writel(todo - 1, ®s->ctrlr1);
rkspi_enable_chip(regs, true);
- toread = todo;
+ /*
+ * When the RX wire is not routed, the RX FIFO never fills,
+ * so waiting on it would hang. Draining it was also what
+ * paced this loop against the wire, so the transmit-only
+ * path relies on the wait_till_not_busy() below for
+ * completion instead.
+ */
+ toread = (priv->mode & SPI_NO_RX) ? 0 : todo;
/* Only write if we have something to write */
towrite = out ? todo : 0;
while (toread || towrite) {
@@ -513,7 +534,7 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
if (!out)
clrsetbits_le32(®s->ctrlr0,
TMOD_MASK << TMOD_SHIFT,
- TMOD_TR << TMOD_SHIFT);
+ rkspi_base_tmod(priv) << TMOD_SHIFT);
return ret;
}
--
2.55.0