From: Sean Anderson <seanga2@gmail.com>
To: u-boot@lists.denx.de
Subject: [RFC PATCH 10/13] spi: dw: Use a mux to access registers
Date: Thu, 4 Feb 2021 23:39:20 -0500 [thread overview]
Message-ID: <20210205043924.149504-11-seanga2@gmail.com> (raw)
In-Reply-To: <20210205043924.149504-1-seanga2@gmail.com>
To enter XIP mode, the xip_en signal must be asserted. The exact method of
setting xip_en is integration-specific, but on the K210 (and Baikal-T1) it
is set by a bit in a system configuration register. To handle this, use a
mux to select the state of xip_en before every access to control registers.
Signed-off-by: Sean Anderson <seanga2@gmail.com>
---
drivers/spi/designware_spi.c | 133 ++++++++++++++++++++++++++++++++++-
1 file changed, 130 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index c41c5b4982..6f74a471e3 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -19,6 +19,7 @@
#include <fdtdec.h>
#include <log.h>
#include <malloc.h>
+#include <mux.h>
#include <reset.h>
#include <spi.h>
#include <spi-mem.h>
@@ -209,6 +210,7 @@ struct dw_spi_priv {
struct clk clk;
struct reset_ctl_bulk resets;
struct gpio_desc cs_gpio; /* External chip-select gpio */
+ struct mux_control *mux; /* XIP mode mux */
void __iomem *regs;
fdt_size_t regs_size;
@@ -225,6 +227,7 @@ struct dw_spi_priv {
unsigned int freq; /* Default frequency */
unsigned int mode;
+ u32 mux_xip_state; /* Mux state to enable XIP mode */
u32 fifo_len; /* depth of the FIFO buffer */
int bits_per_word;
@@ -346,11 +349,79 @@ static int dw_spi_of_to_plat(struct udevice *bus)
return request_gpio_cs(bus);
}
-/* Restart the controller, disable all interrupts, clean rx fifo */
-static void spi_hw_init(struct udevice *bus, struct dw_spi_priv *priv)
+static int dw_spi_mux(struct udevice *dev, bool xip)
{
+ struct dw_spi_priv *priv = dev_get_priv(dev);
+
+ if (!priv->mux)
+ return 0;
+
+ if (xip && priv->mux_xip_state)
+ return mux_control_select(priv->mux, priv->mux_xip_state);
+ else
+ return mux_control_select(priv->mux, 0);
+}
+
+/*
+ * dw_spi_mux_regs() - Select the control registers using the XIP mux
+ * @dev: The device to mux
+ *
+ * This selects the control registers using the XIP mux, driving the xip_en
+ * signal low. This function must be called before any accesses to control
+ * registers.
+ *
+ * Return: 0 on success or negative error value
+ */
+static inline int dw_spi_mux_regs(struct udevice *dev)
+{
+ return dw_spi_mux(dev, false);
+}
+
+/*
+ * dw_spi_mux_xip() - Select the control registers using the XIP mux
+ * @dev: The device to mux
+ *
+ * This selects XIP mode using the XIP mux, driving the xip_en signal high. This
+ * function must be called before any XIP accesses.
+ *
+ * Return: 0 on success or negative error value
+ */
+static inline int dw_spi_mux_xip(struct udevice *dev)
+{
+ return dw_spi_mux(dev, true);
+}
+
+/*
+ * dw_spi_mux_deselect()
+ * @dev: The device to mux
+ *
+ * This deselects the XIP mux, returning it to its default state. This must be
+ * called after control register or XIP accesses are finished, before other
+ * calls to @dw_spi_mux_regs or @dw_spi_mux_xip.
+ */
+static void dw_spi_mux_deselect(struct udevice *dev)
+{
+ int err;
+ struct dw_spi_priv *priv = dev_get_priv(dev);
+
+ if (!priv->mux)
+ return;
+
+ err = mux_control_deselect(priv->mux);
+ if (err)
+ dev_warn(dev, "could not deselect mux (err %d)\n", err);
+}
+
+/* Restart the controller, disable all interrupts, clean rx fifo */
+static int spi_hw_init(struct udevice *bus, struct dw_spi_priv *priv)
+{
+ int ret;
u32 cr0;
+ ret = dw_spi_mux_regs(bus);
+ if (ret)
+ return ret;
+
dw_write(priv, DW_SPI_SSIENR, 0);
dw_write(priv, DW_SPI_IMR, 0);
@@ -415,6 +486,9 @@ static void spi_hw_init(struct udevice *bus, struct dw_spi_priv *priv)
/* Set receive fifo interrupt level register for clock stretching */
dw_write(priv, DW_SPI_RXFTLR, priv->fifo_len - 1);
+
+ dw_spi_mux_deselect(bus);
+ return 0;
}
/*
@@ -480,6 +554,33 @@ static int dw_spi_reset(struct udevice *bus)
return 0;
}
+int dw_spi_get_mux(struct udevice *bus)
+{
+ int ret;
+ struct dw_spi_priv *priv = dev_get_priv(bus);
+
+ ret = mux_get_by_index(bus, 0, &priv->mux);
+ if (ret) {
+ /*
+ * Return 0 if error due to !CONFIG_MUX or mux
+ * DT property is not present.
+ */
+ if (ret == -ENOENT || ret == -ENOTSUPP)
+ return 0;
+
+ dev_warn(bus, "Couldn't get xip mux (error %d)\n", ret);
+ return ret;
+ }
+
+ ret = dev_read_u32(bus, "mux-xip-state", &priv->mux_xip_state);
+ if (ret || priv->mux_xip_state > 1) {
+ dev_warn(bus, "Invalid/missing mux-xip-state property\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int dw_spi_probe(struct udevice *bus)
{
struct dw_spi_plat *plat = dev_get_plat(bus);
@@ -499,6 +600,10 @@ static int dw_spi_probe(struct udevice *bus)
if (ret)
return ret;
+ ret = dw_spi_get_mux(bus);
+ if (ret)
+ return ret;
+
/* Currently only bits_per_word == 8 supported */
priv->bits_per_word = 8;
@@ -506,7 +611,12 @@ static int dw_spi_probe(struct udevice *bus)
/* Basic HW init */
priv->caps = dev_get_driver_data(bus);
- spi_hw_init(bus, priv);
+ ret = spi_hw_init(bus, priv);
+ if (ret)
+ return ret;
+
+ if (!priv->mux)
+ priv->caps &= DW_SPI_CAP_XIP;
version = dw_read(priv, DW_SPI_VERSION);
dev_dbg(bus,
@@ -713,6 +823,10 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
return -1;
}
+ ret = dw_spi_mux_regs(bus);
+ if (ret)
+ return ret;
+
frames = bitlen / priv->bits_per_word;
/* Start the transaction if necessary. */
@@ -779,6 +893,8 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
if (flags & SPI_XFER_END)
external_cs_manage(dev, true);
+ dw_spi_mux_deselect(bus);
+
return ret;
}
@@ -831,6 +947,10 @@ static int dw_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
else
priv->tmode = CTRLR0_TMOD_TO;
+ ret = dw_spi_mux_regs(bus);
+ if (ret)
+ return ret;
+
cr0 = dw_spi_update_cr0(priv);
spi_cr0 = dw_spi_update_spi_cr0(op);
dev_dbg(bus, "cr0=%08x spi_cr0=%08x buf=%p len=%u [bytes]\n", cr0,
@@ -891,6 +1011,7 @@ static int dw_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
}
dw_write(priv, DW_SPI_SER, 0);
external_cs_manage(slave->dev, true);
+ dw_spi_mux_deselect(bus);
dev_dbg(bus, "%u bytes xfered\n", op->data.nbytes);
return ret;
@@ -943,10 +1064,15 @@ static const struct spi_controller_mem_ops dw_spi_mem_ops = {
static int dw_spi_set_speed(struct udevice *bus, uint speed)
{
+ int ret;
struct dw_spi_plat *plat = dev_get_plat(bus);
struct dw_spi_priv *priv = dev_get_priv(bus);
u16 clk_div;
+ ret = dw_spi_mux_regs(bus);
+ if (ret)
+ return ret;
+
if (speed > plat->frequency)
speed = plat->frequency;
@@ -960,6 +1086,7 @@ static int dw_spi_set_speed(struct udevice *bus, uint speed)
/* Enable controller after writing control registers */
dw_write(priv, DW_SPI_SSIENR, 1);
+ mux_control_deselect(priv->mux);
priv->freq = speed;
dev_dbg(bus, "speed=%d clk_div=%d\n", priv->freq, clk_div);
--
2.29.2
next prev parent reply other threads:[~2021-02-05 4:39 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-05 4:39 [RFC PATCH 00/13] spi: dw: Add support for XIP mode Sean Anderson
2021-02-05 4:39 ` [RFC PATCH 01/13] linux err: Synchronize with Linux 5.10 Sean Anderson
2021-02-07 14:37 ` Simon Glass
2021-02-05 4:39 ` [RFC PATCH 02/13] spi-mem: Add dirmap API from Linux Sean Anderson
2021-02-05 4:39 ` [RFC PATCH 03/13] mtd: spi-nor: use spi-mem dirmap API Sean Anderson
2021-02-05 4:39 ` [RFC PATCH 04/13] core: ofnode: Fix inconsistent returns of *_read_u32_array Sean Anderson
2021-02-07 14:37 ` Simon Glass
2021-02-05 4:39 ` [RFC PATCH 05/13] mux: Inline mux functions when CONFIG_MUX is disabled Sean Anderson
2021-02-05 7:32 ` Pratyush Yadav
2021-02-05 4:39 ` [RFC PATCH 06/13] mux: Define a stub for mux_get_by_index if " Sean Anderson
2021-02-05 10:53 ` Pratyush Yadav
2021-02-05 4:39 ` [RFC PATCH 07/13] mux: mmio: Only complain about idle-states if it is malformed Sean Anderson
2021-02-05 11:06 ` Pratyush Yadav
2021-02-05 13:28 ` Sean Anderson
2021-02-05 4:39 ` [RFC PATCH 08/13] spi: dw: Define XIP registers Sean Anderson
2021-02-05 4:39 ` [RFC PATCH 09/13] spi: dw: Add XIP and XIP_CONCURRENT caps Sean Anderson
2021-02-05 4:39 ` Sean Anderson [this message]
2021-02-05 4:39 ` [RFC PATCH 11/13] spi: dw: Add support for DIRMAP Sean Anderson
2021-02-05 4:39 ` [RFC PATCH 12/13] riscv: k210: Increase SPI3 bus clock to CPU speed Sean Anderson
2021-02-05 4:39 ` [RFC PATCH 13/13] riscv: k210: Add bindings for SPI XIP Sean Anderson
2021-02-05 4:43 ` [RFC PATCH 00/13] spi: dw: Add support for XIP mode Sean Anderson
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=20210205043924.149504-11-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