From: Sean Anderson <seanga2@gmail.com>
To: u-boot@lists.denx.de
Subject: [PATCH v2 08/10] spi: dw: Add mem_ops
Date: Fri, 7 Aug 2020 10:43:15 -0400 [thread overview]
Message-ID: <20200807144317.282868-9-seanga2@gmail.com> (raw)
In-Reply-To: <20200807144317.282868-1-seanga2@gmail.com>
The designware ssi device has "broken" chip select behaviour [1], and needs
specific manipulation to use the built-in chip select. The existing fix is
to use an external GPIO for chip select, but typically the K210 has SPI3
directly connected to a flash chip with dedicated pins. This makes it
impossible to use the spi_xfer function to use spi, since the CS is
de-asserted in between calls. This patch adds an implementation of
exec_op, which gives correct behaviour when reading/writing spi flash.
[1] https://lkml.org/lkml/2015/12/23/132
Signed-off-by: Sean Anderson <seanga2@gmail.com>
---
This patch was previously part of
https://patchwork.ozlabs.org/project/uboot/list/?series=161576
Changes in v2:
- Add external gpio cs support
- Clean up exec_op
- Convert debug to log_*
- Limit data transfers to 64k
drivers/spi/designware_spi.c | 104 +++++++++++++++++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index d9dc739d7d..62c0bda4cc 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -19,6 +19,7 @@
#include <errno.h>
#include <malloc.h>
#include <spi.h>
+#include <spi-mem.h>
#include <fdtdec.h>
#include <reset.h>
#include <dm/device_compat.h>
@@ -581,6 +582,108 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
return ret;
}
+/*
+ * This function is necessary for reading SPI flash with the native CS
+ * c.f. https://lkml.org/lkml/2015/12/23/132
+ */
+static int dw_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
+{
+ bool read = op->data.dir == SPI_MEM_DATA_IN;
+ int pos, i, ret = 0;
+ struct udevice *bus = slave->dev->parent;
+ struct dw_spi_priv *priv = dev_get_priv(bus);
+ u8 op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
+ u8 op_buf[op_len];
+ u32 cr0;
+
+ if (read)
+ priv->tmode = CTRLR0_TMOD_EPROMREAD;
+ else
+ priv->tmode = CTRLR0_TMOD_TO;
+
+ log_debug("buf=%p len=%u [bytes]\n", op->data.buf.in, op->data.nbytes);
+
+ cr0 = priv->update_cr0(priv);
+ log_debug("cr0=%08x\n", cr0);
+
+ spi_enable_chip(priv, 0);
+ dw_write(priv, DW_SPI_CTRL0, cr0);
+ if (read)
+ dw_write(priv, DW_SPI_CTRL1, op->data.nbytes - 1);
+ spi_enable_chip(priv, 1);
+
+ /* From spi_mem_exec_op */
+ pos = 0;
+ op_buf[pos++] = op->cmd.opcode;
+ if (op->addr.nbytes) {
+ for (i = 0; i < op->addr.nbytes; i++)
+ op_buf[pos + i] = op->addr.val >>
+ (8 * (op->addr.nbytes - i - 1));
+
+ pos += op->addr.nbytes;
+ }
+ if (op->dummy.nbytes)
+ memset(op_buf + pos, 0xff, op->dummy.nbytes);
+
+ external_cs_manage(slave->dev, false);
+
+ priv->tx = &op_buf;
+ priv->tx_end = priv->tx + op_len;
+ priv->rx = NULL;
+ priv->rx_end = NULL;
+ while (priv->tx != priv->tx_end)
+ dw_writer(priv);
+
+ /*
+ * XXX: The following are tight loops! Enabling debug messages may cause
+ * them to fail because we are not reading/writing the fifo fast enough.
+ */
+ if (read) {
+ priv->rx = op->data.buf.in;
+ priv->rx_end = priv->rx + op->data.nbytes;
+
+ dw_write(priv, DW_SPI_SER, 1 << spi_chip_select(slave->dev));
+ while (priv->rx != priv->rx_end)
+ dw_reader(priv);
+ } else {
+ u32 val;
+
+ priv->tx = op->data.buf.out;
+ priv->tx_end = priv->tx + op->data.nbytes;
+
+ /* Fill up the write fifo before starting the transfer */
+ dw_writer(priv);
+ dw_write(priv, DW_SPI_SER, 1 << spi_chip_select(slave->dev));
+ while (priv->tx != priv->tx_end)
+ dw_writer(priv);
+
+ if (readl_poll_timeout(priv->regs + DW_SPI_SR, val,
+ (val & SR_TF_EMPT) && !(val & SR_BUSY),
+ RX_TIMEOUT * 1000)) {
+ ret = -ETIMEDOUT;
+ }
+ }
+
+ dw_write(priv, DW_SPI_SER, 0);
+ external_cs_manage(slave->dev, true);
+
+ log_debug("%u bytes xfered\n", op->data.nbytes);
+ return ret;
+}
+
+/* The size of ctrl1 limits data transfers to 64K */
+static int dw_spi_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op)
+{
+ op->data.nbytes = min(op->data.nbytes, (unsigned int)SZ_64K);
+
+ return 0;
+}
+
+static const struct spi_controller_mem_ops dw_spi_mem_ops = {
+ .exec_op = dw_spi_exec_op,
+ .adjust_op_size = dw_spi_adjust_op_size,
+};
+
static int dw_spi_set_speed(struct udevice *bus, uint speed)
{
struct dw_spi_platdata *plat = dev_get_platdata(bus);
@@ -646,6 +749,7 @@ static int dw_spi_remove(struct udevice *bus)
static const struct dm_spi_ops dw_spi_ops = {
.xfer = dw_spi_xfer,
+ .mem_ops = &dw_spi_mem_ops,
.set_speed = dw_spi_set_speed,
.set_mode = dw_spi_set_mode,
/*
--
2.28.0
next prev parent reply other threads:[~2020-08-07 14:43 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-08-07 14:43 [PATCH v2 00/10] riscv: Add SPI support for Kendryte K210 Sean Anderson
2020-08-07 14:43 ` [PATCH v2 01/10] spi: dw: Convert calls to debug to log_* Sean Anderson
2020-08-07 14:49 ` Marek Vasut
2020-08-07 14:55 ` Sean Anderson
2020-08-08 5:14 ` Heinrich Schuchardt
2020-08-08 11:07 ` Sean Anderson
2020-08-08 14:11 ` Heinrich Schuchardt
2020-08-20 13:26 ` Simon Glass
2020-08-20 13:36 ` Marek Vasut
2020-08-21 0:08 ` Tom Rini
2020-08-21 1:08 ` Marek Vasut
2020-08-07 14:43 ` [PATCH v2 02/10] spi: dw: Rename "cs-gpio" to "cs-gpios" Sean Anderson
2020-08-07 14:43 ` [PATCH v2 03/10] spi: dw: Use generic function to read reg address Sean Anderson
2020-08-07 14:43 ` [PATCH v2 04/10] spi: dw: Rearrange struct dw_spi_priv Sean Anderson
2020-08-07 14:43 ` [PATCH v2 05/10] spi: dw: Add SoC-specific compatible strings Sean Anderson
2020-08-07 14:43 ` [PATCH v2 06/10] spi: dw: Configure ctrlr0 layout based on compatible string Sean Anderson
2020-08-07 14:43 ` [PATCH v2 07/10] spi: dw: Document devicetree binding Sean Anderson
2020-08-07 14:43 ` Sean Anderson [this message]
2020-08-08 11:36 ` [PATCH v2 08/10] spi: dw: Add mem_ops Sean Anderson
2020-08-07 14:43 ` [PATCH v2 09/10] riscv: Add device tree bindings for SPI Sean Anderson
2020-08-12 1:49 ` Rick Chen
2020-08-07 14:43 ` [PATCH v2 10/10] riscv: Add support for SPI on Kendryte K210 Sean Anderson
2020-08-08 5:48 ` Heinrich Schuchardt
2020-08-08 11:15 ` Sean Anderson
2020-08-10 10:49 ` [PATCH v2 00/10] riscv: Add SPI support for " Eugeniy Paltsev
2020-08-10 11:13 ` Sean Anderson
2020-08-10 15:32 ` Eugeniy Paltsev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200807144317.282868-9-seanga2@gmail.com \
--to=seanga2@gmail.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox