diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/mtd/spi/spi-nor-ids.c | 1 | ||||
| -rw-r--r-- | drivers/spi/rk_spi.c | 33 | ||||
| -rw-r--r-- | drivers/spi/spi-uclass.c | 16 |
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, ®s->ctrlr0); @@ -472,7 +486,11 @@ 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. + */ + 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(®s->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: |
