public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
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

  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