summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-08-29 09:56:00 -0600
committerTom Rini <[email protected]>2026-08-29 09:56:00 -0600
commit856a00aeb61c1d4e7825257e54219599f8e34a6c (patch)
tree0b02f08085d5db33af937a34e861e86c7d60fa84 /drivers
parent043b4280138d45c50340c0f899935b83be4375b7 (diff)
parented58bafd0b24e15b734c624bdaf00b876e5d32e6 (diff)
Merge tag 'u-boot-rockchip-2027.01-20260828' of https://git.u-boot-project.org/u-boot/custodians/u-boot-rockchip into nextnext
- Fixed possible SPI hangs when only PICO is routed (TX-only), - Added support for ROC-RK3399-PC-PLUS (via roc-pc-rk3399_defconfig)
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/spi/spi-nor-ids.c1
-rw-r--r--drivers/spi/rk_spi.c33
-rw-r--r--drivers/spi/spi-uclass.c16
3 files changed, 43 insertions, 7 deletions
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 31a2ba49a87..90aa1025176 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -673,6 +673,7 @@ const struct flash_info spi_nor_ids[] = {
{ INFO("XM25QH64A", 0x207017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("XM25QH64C", 0x204017, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("XM25QH128A", 0x207018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { INFO("XM25QH128C", 0x204018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("XM25QU128C", 0x204118, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ INFO("XM25QH256C", 0x204019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ INFO("XM25QU256C", 0x204119, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c
index 2c3d70ba715..54befd54b09 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, &regs->ctrlr0);
@@ -472,7 +486,11 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
writel(todo - 1, &regs->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.
+ */
+ toread = (priv->mode & SPI_NO_RX) ? 0 : todo;
/* Only write if we have something to write */
towrite = out ? todo : 0;
while (toread || towrite) {
@@ -492,9 +510,10 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
}
/*
- * In case that there's a transmit-component, we need to wait
- * until the control goes idle before we can disable the SPI
- * control logic (as this will implicitly flush the FIFOs).
+ * With a transmit component the TX FIFO can still hold data
+ * that has not been shifted onto the wire. Wait until the
+ * controller goes idle before disabling it, as disabling
+ * clears the FIFOs.
*/
if (out) {
ret = rkspi_wait_till_not_busy(regs);
@@ -513,7 +532,7 @@ static int rockchip_spi_xfer(struct udevice *dev, unsigned int bitlen,
if (!out)
clrsetbits_le32(&regs->ctrlr0,
TMOD_MASK << TMOD_SHIFT,
- TMOD_TR << TMOD_SHIFT);
+ rkspi_base_tmod(priv) << TMOD_SHIFT);
return ret;
}
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 120565df149..dd1843ffac1 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -105,6 +105,7 @@ int dm_spi_set_wordlen(struct udevice *dev, unsigned int wordlen)
int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
+ struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
struct udevice *bus = dev->parent;
struct dm_spi_ops *ops = spi_get_ops(bus);
@@ -113,6 +114,15 @@ int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
if (!ops->xfer)
return -ENOSYS;
+ /*
+ * A device with no wire in one direction cannot transfer in it,
+ * so reject the request here rather than in every driver.
+ */
+ if (din && (slave_plat->mode & SPI_NO_RX))
+ return -EINVAL;
+ if (dout && (slave_plat->mode & SPI_NO_TX))
+ return -EINVAL;
+
return ops->xfer(dev, bitlen, dout, din, flags);
}
@@ -229,6 +239,9 @@ static int spi_child_post_bind(struct udevice *dev)
/* Device DUAL/QUAD mode */
value = dev_read_u32_default(dev, "spi-tx-bus-width", 1);
switch (value) {
+ case 0:
+ mode |= SPI_NO_TX;
+ break;
case 1:
break;
case 2:
@@ -247,6 +260,9 @@ static int spi_child_post_bind(struct udevice *dev)
value = dev_read_u32_default(dev, "spi-rx-bus-width", 1);
switch (value) {
+ case 0:
+ mode |= SPI_NO_RX;
+ break;
case 1:
break;
case 2: