All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v2 0/3] mips: spi: mscc: Add fast bitbang SPI driver
@ 2019-01-07 13:28 Lars Povlsen
  2019-01-07 13:28 ` [U-Boot] [PATCH v2 1/3] " Lars Povlsen
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Lars Povlsen @ 2019-01-07 13:28 UTC (permalink / raw)
  To: u-boot

These 3 patches add an optimized SPI bitbang driver for MSCC SOCs that
does not sport the designware SPI hardware controller.

The driver more than doubles the performance for bulk SPI transfers.

This is based off the u-boot-mips/next repository.

v2 changes:
 - Moved lowlevel delay stuff into arch common header file
 - remove superfluous license and DECLARE_GLOBAL_DATA_PTR
 - Moved defconfig changes to DT patch
 - Removed obsoleted gpio-mscc-bitbang-spi driver

Lars Povlsen (3):
  mips: spi: mscc: Add fast bitbang SPI driver
  mips: mscc: DT: Update luton device tree to use fast SPI driver
  mips: gpio: mscc: Obsoleted gpio-mscc-bitbang-spi.c

 MAINTAINERS                               |   1 +
 arch/mips/dts/mscc,luton.dtsi             |  15 +-
 arch/mips/mach-mscc/include/mach/common.h |  38 ++++
 configs/mscc_luton_defconfig              |   3 +-
 drivers/gpio/Kconfig                      |   7 -
 drivers/gpio/Makefile                     |   1 -
 drivers/gpio/gpio-mscc-bitbang-spi.c      | 122 -----------
 drivers/spi/Kconfig                       |   7 +
 drivers/spi/Makefile                      |   1 +
 drivers/spi/mscc_bb_spi.c                 | 253 ++++++++++++++++++++++
 10 files changed, 304 insertions(+), 144 deletions(-)
 delete mode 100644 drivers/gpio/gpio-mscc-bitbang-spi.c
 create mode 100644 drivers/spi/mscc_bb_spi.c

-- 
2.19.2

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [U-Boot] [PATCH v2 1/3] mips: spi: mscc: Add fast bitbang SPI driver
  2019-01-07 13:28 [U-Boot] [PATCH v2 0/3] mips: spi: mscc: Add fast bitbang SPI driver Lars Povlsen
@ 2019-01-07 13:28 ` Lars Povlsen
  2019-01-07 17:32   ` Daniel Schwierzeck
  2019-01-07 13:28 ` [U-Boot] [PATCH v2 2/3] mips: mscc: DT: Update luton device tree to use fast " Lars Povlsen
  2019-01-07 13:28 ` [U-Boot] [PATCH v2 3/3] mips: gpio: mscc: Obsoleted gpio-mscc-bitbang-spi.c Lars Povlsen
  2 siblings, 1 reply; 6+ messages in thread
From: Lars Povlsen @ 2019-01-07 13:28 UTC (permalink / raw)
  To: u-boot

This patch add a new SPI driver for MSCC SOCs that does not sport the
designware SPI hardware controller.

Performance gain: 7.664 seconds vs. 17.633 for 1 Mbyte write.

Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
 MAINTAINERS                               |   1 +
 arch/mips/mach-mscc/include/mach/common.h |  38 ++++
 drivers/spi/Kconfig                       |   7 +
 drivers/spi/Makefile                      |   1 +
 drivers/spi/mscc_bb_spi.c                 | 253 ++++++++++++++++++++++
 5 files changed, 300 insertions(+)
 create mode 100644 drivers/spi/mscc_bb_spi.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 494962e9b3..0cee99ef56 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -524,6 +524,7 @@ F:	arch/mips/dts/ocelot*
 F:	board/mscc/
 F:	configs/mscc*
 F:	drivers/gpio/mscc_sgpio.c
+F:	drivers/spi/mscc_bb_spi.c
 F:	include/configs/vcoreiii.h
 
 MIPS JZ4780
diff --git a/arch/mips/mach-mscc/include/mach/common.h b/arch/mips/mach-mscc/include/mach/common.h
index d18ae78bfd..7765c060ed 100644
--- a/arch/mips/mach-mscc/include/mach/common.h
+++ b/arch/mips/mach-mscc/include/mach/common.h
@@ -29,6 +29,44 @@
 
 /* Common utility functions */
 
+/*
+ * Perform a number of NOP instructions, blocks of 8 instructions.
+ * The (inlined) function will not affect cache or processor state.
+ */
+static inline void mscc_vcoreiii_nop_delay(int delay)
+{
+	while (delay > 0) {
+#define DELAY_8_NOPS() asm volatile("nop; nop; nop; nop; nop; nop; nop; nop;")
+		switch (delay) {
+		case 8:
+			DELAY_8_NOPS();
+			/* fallthrough */
+		case 7:
+			DELAY_8_NOPS();
+			/* fallthrough */
+		case 6:
+			DELAY_8_NOPS();
+			/* fallthrough */
+		case 5:
+			DELAY_8_NOPS();
+			/* fallthrough */
+		case 4:
+			DELAY_8_NOPS();
+			/* fallthrough */
+		case 3:
+			DELAY_8_NOPS();
+			/* fallthrough */
+		case 2:
+			DELAY_8_NOPS();
+			/* fallthrough */
+		case 1:
+			DELAY_8_NOPS();
+		}
+		delay -= 8;
+#undef DELAY_8_NOPS
+	}
+}
+
 int mscc_phy_rd_wr(u8 read,
 		   u32 miim_controller,
 		   u8 miim_addr,
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a7bb5b35c2..de4d62dd8f 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -294,6 +294,13 @@ config SOFT_SPI
 	 Enable Soft SPI driver. This driver is to use GPIO simulate
 	 the SPI protocol.
 
+config MSCC_BB_SPI
+	bool "MSCC bitbang SPI driver"
+	depends on SOC_VCOREIII
+	help
+	  Enable MSCC bitbang SPI driver. This driver can be used on
+	  MSCC SOCs.
+
 config CF_SPI
 	bool "ColdFire SPI driver"
 	help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 392a925795..4acec3ea17 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o
 obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
 obj-$(CONFIG_MTK_QSPI) += mtk_qspi.o
 obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o
+obj-$(CONFIG_MSCC_BB_SPI) += mscc_bb_spi.o
 obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o
 obj-$(CONFIG_MXC_SPI) += mxc_spi.o
 obj-$(CONFIG_MXS_SPI) += mxs_spi.o
diff --git a/drivers/spi/mscc_bb_spi.c b/drivers/spi/mscc_bb_spi.c
new file mode 100644
index 0000000000..5685878597
--- /dev/null
+++ b/drivers/spi/mscc_bb_spi.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Microsemi SoCs spi driver
+ *
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <malloc.h>
+#include <spi.h>
+#include <dm.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+struct mscc_bb_platdata {
+	void __iomem *regs;
+	u32 deactivate_delay_us;
+};
+
+struct mscc_bb_priv {
+	void __iomem *regs;
+	bool cs_active;   /* State flag as to whether CS is asserted */
+	int cs_num;
+	u32 svalue;			/* Value to start transfer with */
+	u32 clk1;			/* Clock value start */
+	u32 clk2;			/* Clock value 2nd phase */
+};
+
+/* Delay 24 instructions for this particular application */
+#define hold_time_delay() mscc_vcoreiii_nop_delay(3)
+
+static int mscc_bb_spi_cs_activate(struct mscc_bb_priv *priv, int mode, int cs)
+{
+	if (!priv->cs_active) {
+		int cpha = mode & SPI_CPHA;
+		u32 cs_value;
+
+		priv->cs_num = cs;
+
+		if (cpha) {
+			/* Initial clock starts SCK=1 */
+			priv->clk1 = ICPU_SW_MODE_SW_SPI_SCK;
+			priv->clk2 = 0;
+		} else {
+			/* Initial clock starts SCK=0 */
+			priv->clk1 = 0;
+			priv->clk2 = ICPU_SW_MODE_SW_SPI_SCK;
+		}
+
+		/* Enable bitbang, SCK_OE, SDO_OE */
+		priv->svalue = (ICPU_SW_MODE_SW_PIN_CTRL_MODE | /* Bitbang */
+				ICPU_SW_MODE_SW_SPI_SCK_OE    | /* SCK_OE */
+				ICPU_SW_MODE_SW_SPI_SDO_OE);   /* SDO OE */
+
+		/* Add CS */
+		if (cs >= 0) {
+			cs_value =
+				ICPU_SW_MODE_SW_SPI_CS_OE(BIT(cs)) |
+				ICPU_SW_MODE_SW_SPI_CS(BIT(cs));
+		} else {
+			cs_value = 0;
+		}
+
+		priv->svalue |= cs_value;
+
+		/* Enable the CS in HW, Initial clock value */
+		writel(priv->svalue | priv->clk2, priv->regs);
+
+		priv->cs_active = true;
+		debug("Activated CS%d\n", priv->cs_num);
+	}
+
+	return 0;
+}
+
+static int mscc_bb_spi_cs_deactivate(struct mscc_bb_priv *priv, int deact_delay)
+{
+	if (priv->cs_active) {
+		/* Keep driving the CLK to its current value while
+		 * actively deselecting CS.
+		 */
+		u32 value = readl(priv->regs);
+
+		value &= ~ICPU_SW_MODE_SW_SPI_CS_M;
+		writel(value, priv->regs);
+		hold_time_delay();
+
+		/* Stop driving the clock, but keep CS with nCS == 1 */
+		value &= ~ICPU_SW_MODE_SW_SPI_SCK_OE;
+		writel(value, priv->regs);
+
+		/* Deselect hold time delay */
+		if (deact_delay)
+			udelay(deact_delay);
+
+		/* Drop everything */
+		writel(0, priv->regs);
+
+		priv->cs_active = false;
+		debug("Deactivated CS%d\n", priv->cs_num);
+	}
+
+	return 0;
+}
+
+int mscc_bb_spi_claim_bus(struct udevice *dev)
+{
+	return 0;
+}
+
+int mscc_bb_spi_release_bus(struct udevice *dev)
+{
+	return 0;
+}
+
+int mscc_bb_spi_xfer(struct udevice *dev, unsigned int bitlen,
+		     const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
+	struct mscc_bb_platdata *bus_plat = dev_get_platdata(bus);
+	struct mscc_bb_priv *priv = dev_get_priv(bus);
+	u32             i, count;
+	const u8	*txd = dout;
+	u8		*rxd = din;
+
+	debug("spi_xfer: slave %s:%s cs%d mode %d, dout %p din %p bitlen %u\n",
+	      dev->parent->name, dev->name, plat->cs,  plat->mode, dout,
+	      din, bitlen);
+
+	if (flags & SPI_XFER_BEGIN)
+		mscc_bb_spi_cs_activate(priv, plat->mode, plat->cs);
+
+	count = bitlen / 8;
+	for (i = 0; i < count; i++) {
+		u32 rx = 0, mask = 0x80, value;
+
+		while (mask) {
+			/* Initial condition: CLK is low. */
+			value = priv->svalue;
+			if (txd && txd[i] & mask)
+				value |= ICPU_SW_MODE_SW_SPI_SDO;
+
+			/* Drive data while taking CLK low. The device
+			 * we're accessing will sample on the
+			 * following rising edge and will output data
+			 * on this edge for us to be sampled at the
+			 * end of this loop.
+			 */
+			writel(value | priv->clk1, priv->regs);
+
+			/* Wait for t_setup. All devices do have a
+			 * setup-time, so we always insert some delay
+			 * here. Some devices have a very long
+			 * setup-time, which can be adjusted by the
+			 * user through vcoreiii_device->delay.
+			 */
+			hold_time_delay();
+
+			/* Drive the clock high. */
+			writel(value | priv->clk2, priv->regs);
+
+			/* Wait for t_hold. See comment about t_setup
+			 * above.
+			 */
+			hold_time_delay();
+
+			/* We sample as close to the next falling edge
+			 * as possible.
+			 */
+			value = readl(priv->regs);
+			if (value & ICPU_SW_MODE_SW_SPI_SDI)
+				rx |= mask;
+			mask >>= 1;
+		}
+		if (rxd) {
+			debug("Read 0x%02x\n", rx);
+			rxd[i] = (u8)rx;
+		}
+		debug("spi_xfer: byte %d/%d\n", i + 1, count);
+	}
+
+	debug("spi_xfer: done\n");
+
+	if (flags & SPI_XFER_END)
+		mscc_bb_spi_cs_deactivate(priv, bus_plat->deactivate_delay_us);
+
+	return 0;
+}
+
+int mscc_bb_spi_set_speed(struct udevice *dev, unsigned int speed)
+{
+	/* Accept any speed */
+	return 0;
+}
+
+int mscc_bb_spi_set_mode(struct udevice *dev, unsigned int mode)
+{
+	return 0;
+}
+
+static const struct dm_spi_ops mscc_bb_ops = {
+	.claim_bus	= mscc_bb_spi_claim_bus,
+	.release_bus	= mscc_bb_spi_release_bus,
+	.xfer		= mscc_bb_spi_xfer,
+	.set_speed	= mscc_bb_spi_set_speed,
+	.set_mode	= mscc_bb_spi_set_mode,
+};
+
+static const struct udevice_id mscc_bb_ids[] = {
+	{ .compatible = "mscc,luton-bb-spi" },
+	{ }
+};
+
+static int mscc_bb_spi_probe(struct udevice *bus)
+{
+	struct mscc_bb_priv *priv = dev_get_priv(bus);
+	struct mscc_bb_platdata *plat = dev_get_platdata(bus);
+
+	debug("%s: loaded, priv %p, plat %p\n", __func__, priv, plat);
+
+	/* Initialize */
+	priv->regs = plat->regs;
+	priv->cs_active = false;
+
+	return 0;
+}
+
+static int mscc_bb_spi_ofdata_to_platdata(struct udevice *bus)
+{
+	struct mscc_bb_platdata *plat = dev_get_platdata(bus);
+
+	plat->regs = (void __iomem *)dev_read_addr(bus);
+
+	plat->deactivate_delay_us =
+		dev_read_u32_default(bus, "spi-deactivate-delay", 0);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(mscc_bb) = {
+	.name	= "mscc_bb",
+	.id	= UCLASS_SPI,
+	.of_match = mscc_bb_ids,
+	.ops	= &mscc_bb_ops,
+	.ofdata_to_platdata = mscc_bb_spi_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct mscc_bb_platdata),
+	.priv_auto_alloc_size = sizeof(struct mscc_bb_priv),
+	.probe	= mscc_bb_spi_probe,
+};
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [U-Boot] [PATCH v2 2/3] mips: mscc: DT: Update luton device tree to use fast SPI driver
  2019-01-07 13:28 [U-Boot] [PATCH v2 0/3] mips: spi: mscc: Add fast bitbang SPI driver Lars Povlsen
  2019-01-07 13:28 ` [U-Boot] [PATCH v2 1/3] " Lars Povlsen
@ 2019-01-07 13:28 ` Lars Povlsen
  2019-01-07 13:28 ` [U-Boot] [PATCH v2 3/3] mips: gpio: mscc: Obsoleted gpio-mscc-bitbang-spi.c Lars Povlsen
  2 siblings, 0 replies; 6+ messages in thread
From: Lars Povlsen @ 2019-01-07 13:28 UTC (permalink / raw)
  To: u-boot

Thes patch change the luton base device tree to use the newly added
SPI bitbang driver.

It also updates the "mscc_luton_defconfig" to use the new driver.

Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
 arch/mips/dts/mscc,luton.dtsi | 15 ++-------------
 configs/mscc_luton_defconfig  |  3 ++-
 2 files changed, 4 insertions(+), 14 deletions(-)

diff --git a/arch/mips/dts/mscc,luton.dtsi b/arch/mips/dts/mscc,luton.dtsi
index 87e27c6de5..d11ec4884d 100644
--- a/arch/mips/dts/mscc,luton.dtsi
+++ b/arch/mips/dts/mscc,luton.dtsi
@@ -84,21 +84,10 @@
 			gpio-ranges = <&sgpio 0 0 64>;
 		};
 
-		gpio_spi_bitbang: gpio at 10000064 {
-			compatible = "mscc,spi-bitbang-gpio";
-			reg = <0x10000064 0x4>;
-			gpio-controller;
-			#gpio-cells = <2>;
-
-		};
-
 		spi0: spi-bitbang {
-			compatible = "spi-gpio";
+			compatible = "mscc,luton-bb-spi";
 			status = "okay";
-			gpio-sck = <&gpio_spi_bitbang 6 0>;
-			gpio-miso = <&gpio_spi_bitbang 0 0>;
-			gpio-mosi = <&gpio_spi_bitbang 5 0>;
-			cs-gpios = <&gpio_spi_bitbang 1 0>;
+			reg = <0x10000064 0x4>;
 			num-chipselects = <1>;
 			#address-cells = <1>;
 			#size-cells = <0>;
diff --git a/configs/mscc_luton_defconfig b/configs/mscc_luton_defconfig
index 65f0672c1e..d48a93a2a5 100644
--- a/configs/mscc_luton_defconfig
+++ b/configs/mscc_luton_defconfig
@@ -34,6 +34,7 @@ CONFIG_CMD_DHCP=y
 # CONFIG_NET_TFTP_VARS is not set
 # CONFIG_CMD_NFS is not set
 CONFIG_CMD_PING=y
+CONFIG_CMD_TIME=y
 CONFIG_CMD_MTDPARTS=y
 CONFIG_MTDIDS_DEFAULT="nor0=spi_flash"
 CONFIG_MTDPARTS_DEFAULT="mtdparts=spi_flash:1m(UBoot),256k(Env),256k(Env.bk),512k(Unused),6m(linux)"
@@ -66,5 +67,5 @@ CONFIG_DEBUG_UART_SHIFT=2
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
-CONFIG_SOFT_SPI=y
+CONFIG_MSCC_BB_SPI=y
 CONFIG_LZMA=y
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [U-Boot] [PATCH v2 3/3] mips: gpio: mscc: Obsoleted gpio-mscc-bitbang-spi.c
  2019-01-07 13:28 [U-Boot] [PATCH v2 0/3] mips: spi: mscc: Add fast bitbang SPI driver Lars Povlsen
  2019-01-07 13:28 ` [U-Boot] [PATCH v2 1/3] " Lars Povlsen
  2019-01-07 13:28 ` [U-Boot] [PATCH v2 2/3] mips: mscc: DT: Update luton device tree to use fast " Lars Povlsen
@ 2019-01-07 13:28 ` Lars Povlsen
  2 siblings, 0 replies; 6+ messages in thread
From: Lars Povlsen @ 2019-01-07 13:28 UTC (permalink / raw)
  To: u-boot

With the new mscc_bb_spi.c driver, there is no longer use for the
gpio-mscc-bitbang-spi.c driver.

Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
 drivers/gpio/Kconfig                 |   7 --
 drivers/gpio/Makefile                |   1 -
 drivers/gpio/gpio-mscc-bitbang-spi.c | 122 ---------------------------
 3 files changed, 130 deletions(-)
 delete mode 100644 drivers/gpio/gpio-mscc-bitbang-spi.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index aa55ff43c4..14a14be917 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -99,13 +99,6 @@ config LPC32XX_GPIO
 	help
 	  Support for the LPC32XX GPIO driver.
 
-config MSCC_BITBANG_SPI_GPIO
-	bool "Microsemi bitbang spi GPIO driver"
-	depends on DM_GPIO && SOC_VCOREIII
-	help
-	  Support controlling the GPIO used for SPI bitbang by software. Can
-	  be used by the VCoreIII SoCs, but it was mainly useful for Luton.
-
 config MSCC_SGPIO
 	bool "Microsemi Serial GPIO driver"
 	depends on DM_GPIO && SOC_VCOREIII
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index be2b3c792f..7c479efe2d 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -59,5 +59,4 @@ obj-$(CONFIG_MSM_GPIO)		+= msm_gpio.o
 obj-$(CONFIG_$(SPL_)PCF8575_GPIO)	+= pcf8575_gpio.o
 obj-$(CONFIG_PM8916_GPIO)	+= pm8916_gpio.o
 obj-$(CONFIG_MT7621_GPIO)	+= mt7621_gpio.o
-obj-$(CONFIG_MSCC_BITBANG_SPI_GPIO)	+= gpio-mscc-bitbang-spi.o
 obj-$(CONFIG_MSCC_SGPIO)	+= mscc_sgpio.o
diff --git a/drivers/gpio/gpio-mscc-bitbang-spi.c b/drivers/gpio/gpio-mscc-bitbang-spi.c
deleted file mode 100644
index b675f9052c..0000000000
--- a/drivers/gpio/gpio-mscc-bitbang-spi.c
+++ /dev/null
@@ -1,122 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Microsemi SoCs pinctrl driver
- *
- * Author: <gregory.clement@bootlin.com>
- * License: Dual MIT/GPL
- * Copyright (c) 2018 Microsemi Corporation
- */
-
-#include <common.h>
-#include <asm-generic/gpio.h>
-#include <asm/io.h>
-#include <dm.h>
-#include <errno.h>
-
-enum {
-	SDI,
-	CS0,
-	CS1,
-	CS2,
-	CS3,
-	SDO,
-	SCK
-};
-
-static const int pinmap[] = { 0, 5, 6, 7, 8, 10, 12 };
-
-#define SW_SPI_CSn_OE	 0x1E	/* bits 1 to 4 */
-#define SW_SPI_CS0_OE	 BIT(1)
-#define SW_SPI_SDO_OE	 BIT(9)
-#define SW_SPI_SCK_OE	 BIT(11)
-#define SW_PIN_CTRL_MODE BIT(13)
-
-struct mscc_bb_spi_gpio {
-	void __iomem *regs;
-	u32 cache_val;
-};
-
-static int mscc_bb_spi_gpio_set(struct udevice *dev, unsigned oft, int val)
-{
-	struct mscc_bb_spi_gpio *gpio = dev_get_priv(dev);
-
-	if (val)
-		gpio->cache_val |= BIT(pinmap[oft]);
-	else
-		gpio->cache_val &= ~BIT(pinmap[oft]);
-
-	writel(gpio->cache_val, gpio->regs);
-
-	return 0;
-}
-
-static int mscc_bb_spi_gpio_direction_output(struct udevice *dev, unsigned oft,
-					     int val)
-{
-	if (oft == 0) {
-		pr_err("SW_SPI_DSI can't be used as output\n");
-		return -ENOTSUPP;
-	}
-
-	mscc_bb_spi_gpio_set(dev, oft, val);
-
-	return 0;
-}
-
-static int mscc_bb_spi_gpio_direction_input(struct udevice *dev, unsigned oft)
-{
-	return 0;
-}
-
-static int mscc_bb_spi_gpio_get(struct udevice *dev, unsigned int oft)
-{
-	struct mscc_bb_spi_gpio *gpio = dev_get_priv(dev);
-	u32 val = readl(gpio->regs);
-
-	return !!(val & BIT(pinmap[oft]));
-}
-
-static const struct dm_gpio_ops mscc_bb_spi_gpio_ops = {
-	.direction_output	= mscc_bb_spi_gpio_direction_output,
-	.direction_input	= mscc_bb_spi_gpio_direction_input,
-	.set_value		= mscc_bb_spi_gpio_set,
-	.get_value		= mscc_bb_spi_gpio_get,
-};
-
-static int mscc_bb_spi_gpio_probe(struct udevice *dev)
-{
-	struct mscc_bb_spi_gpio *gpio = dev_get_priv(dev);
-	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
-
-	gpio->regs = dev_remap_addr(dev);
-	if (!gpio->regs)
-		return -EINVAL;
-
-	uc_priv->bank_name = dev->name;
-	uc_priv->gpio_count = ARRAY_SIZE(pinmap);
-	/*
-	 * Enable software mode to control the SPI pin, enables the
-	 * output mode for most of the pin and initialize the cache
-	 * value in the same time
-	 */
-
-	gpio->cache_val = SW_PIN_CTRL_MODE | SW_SPI_SCK_OE | SW_SPI_SDO_OE |
-	    SW_SPI_CS0_OE;
-	writel(gpio->cache_val, gpio->regs);
-
-	return 0;
-}
-
-static const struct udevice_id mscc_bb_spi_gpio_ids[] = {
-	{.compatible = "mscc,spi-bitbang-gpio"},
-	{}
-};
-
-U_BOOT_DRIVER(gpio_mscc_bb_spi) = {
-	.name	= "gpio-mscc-spi-bitbang",
-	.id	= UCLASS_GPIO,
-	.ops	= &mscc_bb_spi_gpio_ops,
-	.probe	= mscc_bb_spi_gpio_probe,
-	.of_match = of_match_ptr(mscc_bb_spi_gpio_ids),
-	.priv_auto_alloc_size = sizeof(struct mscc_bb_spi_gpio),
-};
-- 
2.19.2

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [U-Boot] [PATCH v2 1/3] mips: spi: mscc: Add fast bitbang SPI driver
  2019-01-07 13:28 ` [U-Boot] [PATCH v2 1/3] " Lars Povlsen
@ 2019-01-07 17:32   ` Daniel Schwierzeck
  2019-01-08  8:54     ` Lars.Povlsen at microchip.com
  0 siblings, 1 reply; 6+ messages in thread
From: Daniel Schwierzeck @ 2019-01-07 17:32 UTC (permalink / raw)
  To: u-boot



Am 07.01.19 um 14:28 schrieb Lars Povlsen:
> This patch add a new SPI driver for MSCC SOCs that does not sport the
> designware SPI hardware controller.
> 
> Performance gain: 7.664 seconds vs. 17.633 for 1 Mbyte write.
> 
> Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
> ---
>  MAINTAINERS                               |   1 +
>  arch/mips/mach-mscc/include/mach/common.h |  38 ++++
>  drivers/spi/Kconfig                       |   7 +
>  drivers/spi/Makefile                      |   1 +
>  drivers/spi/mscc_bb_spi.c                 | 253 ++++++++++++++++++++++
>  5 files changed, 300 insertions(+)
>  create mode 100644 drivers/spi/mscc_bb_spi.c
> 

Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>

nits below

> diff --git a/MAINTAINERS b/MAINTAINERS
> index 494962e9b3..0cee99ef56 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -524,6 +524,7 @@ F:	arch/mips/dts/ocelot*
>  F:	board/mscc/
>  F:	configs/mscc*
>  F:	drivers/gpio/mscc_sgpio.c
> +F:	drivers/spi/mscc_bb_spi.c
>  F:	include/configs/vcoreiii.h
>  
>  MIPS JZ4780
> diff --git a/arch/mips/mach-mscc/include/mach/common.h b/arch/mips/mach-mscc/include/mach/common.h
> index d18ae78bfd..7765c060ed 100644
> --- a/arch/mips/mach-mscc/include/mach/common.h
> +++ b/arch/mips/mach-mscc/include/mach/common.h
> @@ -29,6 +29,44 @@
>  
>  /* Common utility functions */
>  
> +/*
> + * Perform a number of NOP instructions, blocks of 8 instructions.
> + * The (inlined) function will not affect cache or processor state.
> + */
> +static inline void mscc_vcoreiii_nop_delay(int delay)
> +{
> +	while (delay > 0) {
> +#define DELAY_8_NOPS() asm volatile("nop; nop; nop; nop; nop; nop; nop; nop;")
> +		switch (delay) {
> +		case 8:
> +			DELAY_8_NOPS();
> +			/* fallthrough */
> +		case 7:
> +			DELAY_8_NOPS();
> +			/* fallthrough */
> +		case 6:
> +			DELAY_8_NOPS();
> +			/* fallthrough */
> +		case 5:
> +			DELAY_8_NOPS();
> +			/* fallthrough */
> +		case 4:
> +			DELAY_8_NOPS();
> +			/* fallthrough */
> +		case 3:
> +			DELAY_8_NOPS();
> +			/* fallthrough */
> +		case 2:
> +			DELAY_8_NOPS();
> +			/* fallthrough */
> +		case 1:
> +			DELAY_8_NOPS();
> +		}
> +		delay -= 8;
> +#undef DELAY_8_NOPS
> +	}
> +}
> +
>  int mscc_phy_rd_wr(u8 read,
>  		   u32 miim_controller,
>  		   u8 miim_addr,
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index a7bb5b35c2..de4d62dd8f 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -294,6 +294,13 @@ config SOFT_SPI
>  	 Enable Soft SPI driver. This driver is to use GPIO simulate
>  	 the SPI protocol.
>  
> +config MSCC_BB_SPI
> +	bool "MSCC bitbang SPI driver"
> +	depends on SOC_VCOREIII
> +	help
> +	  Enable MSCC bitbang SPI driver. This driver can be used on
> +	  MSCC SOCs.
> +
>  config CF_SPI
>  	bool "ColdFire SPI driver"
>  	help
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index 392a925795..4acec3ea17 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -36,6 +36,7 @@ obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o
>  obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
>  obj-$(CONFIG_MTK_QSPI) += mtk_qspi.o
>  obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o
> +obj-$(CONFIG_MSCC_BB_SPI) += mscc_bb_spi.o
>  obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o
>  obj-$(CONFIG_MXC_SPI) += mxc_spi.o
>  obj-$(CONFIG_MXS_SPI) += mxs_spi.o
> diff --git a/drivers/spi/mscc_bb_spi.c b/drivers/spi/mscc_bb_spi.c
> new file mode 100644
> index 0000000000..5685878597
> --- /dev/null
> +++ b/drivers/spi/mscc_bb_spi.c
> @@ -0,0 +1,253 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/*
> + * Microsemi SoCs spi driver
> + *
> + * Copyright (c) 2018 Microsemi Corporation
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <malloc.h>
> +#include <spi.h>
> +#include <dm.h>
> +#include <asm/gpio.h>
> +#include <asm/io.h>
> +#include <linux/delay.h>
> +
> +struct mscc_bb_platdata {
> +	void __iomem *regs;
> +	u32 deactivate_delay_us;
> +};

you could drop this along with mscc_bb_spi_ofdata_to_platdata() if you
don't need to support a non-device-tree config or a SPL with DM and
platdata only (I guess neither is true for MSCC platform). Otherwise you
can init mscc_bb_priv from device-tree in your probe function.

> +
> +struct mscc_bb_priv {
> +	void __iomem *regs;
> +	bool cs_active;   /* State flag as to whether CS is asserted */
> +	int cs_num;
> +	u32 svalue;			/* Value to start transfer with */
> +	u32 clk1;			/* Clock value start */
> +	u32 clk2;			/* Clock value 2nd phase */
> +};
> +
> +/* Delay 24 instructions for this particular application */
> +#define hold_time_delay() mscc_vcoreiii_nop_delay(3)
> +
> +static int mscc_bb_spi_cs_activate(struct mscc_bb_priv *priv, int mode, int cs)
> +{
> +	if (!priv->cs_active) {
> +		int cpha = mode & SPI_CPHA;
> +		u32 cs_value;
> +
> +		priv->cs_num = cs;
> +
> +		if (cpha) {
> +			/* Initial clock starts SCK=1 */
> +			priv->clk1 = ICPU_SW_MODE_SW_SPI_SCK;
> +			priv->clk2 = 0;
> +		} else {
> +			/* Initial clock starts SCK=0 */
> +			priv->clk1 = 0;
> +			priv->clk2 = ICPU_SW_MODE_SW_SPI_SCK;
> +		}
> +
> +		/* Enable bitbang, SCK_OE, SDO_OE */
> +		priv->svalue = (ICPU_SW_MODE_SW_PIN_CTRL_MODE | /* Bitbang */
> +				ICPU_SW_MODE_SW_SPI_SCK_OE    | /* SCK_OE */
> +				ICPU_SW_MODE_SW_SPI_SDO_OE);   /* SDO OE */
> +
> +		/* Add CS */
> +		if (cs >= 0) {
> +			cs_value =
> +				ICPU_SW_MODE_SW_SPI_CS_OE(BIT(cs)) |
> +				ICPU_SW_MODE_SW_SPI_CS(BIT(cs));
> +		} else {
> +			cs_value = 0;
> +		}
> +
> +		priv->svalue |= cs_value;
> +
> +		/* Enable the CS in HW, Initial clock value */
> +		writel(priv->svalue | priv->clk2, priv->regs);
> +
> +		priv->cs_active = true;
> +		debug("Activated CS%d\n", priv->cs_num);
> +	}
> +
> +	return 0;
> +}
> +
> +static int mscc_bb_spi_cs_deactivate(struct mscc_bb_priv *priv, int deact_delay)
> +{
> +	if (priv->cs_active) {
> +		/* Keep driving the CLK to its current value while
> +		 * actively deselecting CS.
> +		 */
> +		u32 value = readl(priv->regs);
> +
> +		value &= ~ICPU_SW_MODE_SW_SPI_CS_M;
> +		writel(value, priv->regs);
> +		hold_time_delay();
> +
> +		/* Stop driving the clock, but keep CS with nCS == 1 */
> +		value &= ~ICPU_SW_MODE_SW_SPI_SCK_OE;
> +		writel(value, priv->regs);
> +
> +		/* Deselect hold time delay */
> +		if (deact_delay)
> +			udelay(deact_delay);
> +
> +		/* Drop everything */
> +		writel(0, priv->regs);
> +
> +		priv->cs_active = false;
> +		debug("Deactivated CS%d\n", priv->cs_num);
> +	}
> +
> +	return 0;
> +}
> +
> +int mscc_bb_spi_claim_bus(struct udevice *dev)
> +{
> +	return 0;
> +}
> +
> +int mscc_bb_spi_release_bus(struct udevice *dev)
> +{
> +	return 0;
> +}
> +
> +int mscc_bb_spi_xfer(struct udevice *dev, unsigned int bitlen,
> +		     const void *dout, void *din, unsigned long flags)
> +{
> +	struct udevice *bus = dev_get_parent(dev);
> +	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
> +	struct mscc_bb_platdata *bus_plat = dev_get_platdata(bus);
> +	struct mscc_bb_priv *priv = dev_get_priv(bus);
> +	u32             i, count;
> +	const u8	*txd = dout;
> +	u8		*rxd = din;
> +
> +	debug("spi_xfer: slave %s:%s cs%d mode %d, dout %p din %p bitlen %u\n",
> +	      dev->parent->name, dev->name, plat->cs,  plat->mode, dout,
> +	      din, bitlen);
> +
> +	if (flags & SPI_XFER_BEGIN)
> +		mscc_bb_spi_cs_activate(priv, plat->mode, plat->cs);
> +
> +	count = bitlen / 8;
> +	for (i = 0; i < count; i++) {
> +		u32 rx = 0, mask = 0x80, value;
> +
> +		while (mask) {
> +			/* Initial condition: CLK is low. */
> +			value = priv->svalue;
> +			if (txd && txd[i] & mask)
> +				value |= ICPU_SW_MODE_SW_SPI_SDO;
> +
> +			/* Drive data while taking CLK low. The device
> +			 * we're accessing will sample on the
> +			 * following rising edge and will output data
> +			 * on this edge for us to be sampled at the
> +			 * end of this loop.
> +			 */
> +			writel(value | priv->clk1, priv->regs);
> +
> +			/* Wait for t_setup. All devices do have a
> +			 * setup-time, so we always insert some delay
> +			 * here. Some devices have a very long
> +			 * setup-time, which can be adjusted by the
> +			 * user through vcoreiii_device->delay.
> +			 */
> +			hold_time_delay();
> +
> +			/* Drive the clock high. */
> +			writel(value | priv->clk2, priv->regs);
> +
> +			/* Wait for t_hold. See comment about t_setup
> +			 * above.
> +			 */
> +			hold_time_delay();
> +
> +			/* We sample as close to the next falling edge
> +			 * as possible.
> +			 */
> +			value = readl(priv->regs);
> +			if (value & ICPU_SW_MODE_SW_SPI_SDI)
> +				rx |= mask;
> +			mask >>= 1;
> +		}
> +		if (rxd) {
> +			debug("Read 0x%02x\n", rx);
> +			rxd[i] = (u8)rx;
> +		}
> +		debug("spi_xfer: byte %d/%d\n", i + 1, count);
> +	}
> +
> +	debug("spi_xfer: done\n");
> +
> +	if (flags & SPI_XFER_END)
> +		mscc_bb_spi_cs_deactivate(priv, bus_plat->deactivate_delay_us);
> +
> +	return 0;
> +}
> +
> +int mscc_bb_spi_set_speed(struct udevice *dev, unsigned int speed)
> +{
> +	/* Accept any speed */
> +	return 0;
> +}
> +
> +int mscc_bb_spi_set_mode(struct udevice *dev, unsigned int mode)
> +{
> +	return 0;
> +}
> +
> +static const struct dm_spi_ops mscc_bb_ops = {
> +	.claim_bus	= mscc_bb_spi_claim_bus,
> +	.release_bus	= mscc_bb_spi_release_bus,
> +	.xfer		= mscc_bb_spi_xfer,
> +	.set_speed	= mscc_bb_spi_set_speed,
> +	.set_mode	= mscc_bb_spi_set_mode,
> +};
> +
> +static const struct udevice_id mscc_bb_ids[] = {
> +	{ .compatible = "mscc,luton-bb-spi" },
> +	{ }
> +};
> +
> +static int mscc_bb_spi_probe(struct udevice *bus)
> +{
> +	struct mscc_bb_priv *priv = dev_get_priv(bus);
> +	struct mscc_bb_platdata *plat = dev_get_platdata(bus);
> +
> +	debug("%s: loaded, priv %p, plat %p\n", __func__, priv, plat);
> +
> +	/* Initialize */
> +	priv->regs = plat->regs;
> +	priv->cs_active = false;
> +
> +	return 0;
> +}
> +
> +static int mscc_bb_spi_ofdata_to_platdata(struct udevice *bus)
> +{
> +	struct mscc_bb_platdata *plat = dev_get_platdata(bus);
> +
> +	plat->regs = (void __iomem *)dev_read_addr(bus);
> +
> +	plat->deactivate_delay_us =
> +		dev_read_u32_default(bus, "spi-deactivate-delay", 0);

I think this property should have a "mscc," prefix if it's a custom
properry?

> +
> +	return 0;
> +}
> +
> +U_BOOT_DRIVER(mscc_bb) = {
> +	.name	= "mscc_bb",
> +	.id	= UCLASS_SPI,
> +	.of_match = mscc_bb_ids,
> +	.ops	= &mscc_bb_ops,
> +	.ofdata_to_platdata = mscc_bb_spi_ofdata_to_platdata,
> +	.platdata_auto_alloc_size = sizeof(struct mscc_bb_platdata),
> +	.priv_auto_alloc_size = sizeof(struct mscc_bb_priv),
> +	.probe	= mscc_bb_spi_probe,
> +};
> 

-- 
- Daniel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [U-Boot] [PATCH v2 1/3] mips: spi: mscc: Add fast bitbang SPI driver
  2019-01-07 17:32   ` Daniel Schwierzeck
@ 2019-01-08  8:54     ` Lars.Povlsen at microchip.com
  0 siblings, 0 replies; 6+ messages in thread
From: Lars.Povlsen at microchip.com @ 2019-01-08  8:54 UTC (permalink / raw)
  To: u-boot

Hi again,

Thank you for your input, I will submit a (hopefully)
final v3 patch right away.

Comments below,

---Lars

> -----Original Message-----
> From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
> Sent: Monday, January 7, 2019 18:32
> To: Lars Povlsen - M31675 <Lars.Povlsen@microchip.com>; u-
> boot at lists.denx.de
> Cc: gregory.clement at bootlin.com; Horatiu Vultur - M31836
> <Horatiu.Vultur@microchip.com>
> Subject: Re: [PATCH v2 1/3] mips: spi: mscc: Add fast bitbang SPI driver
> 
> 
> 
> Am 07.01.19 um 14:28 schrieb Lars Povlsen:
> > This patch add a new SPI driver for MSCC SOCs that does not sport the
> > designware SPI hardware controller.
> >
> > Performance gain: 7.664 seconds vs. 17.633 for 1 Mbyte write.
> >
> > Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
> > ---
> >  MAINTAINERS                               |   1 +
> >  arch/mips/mach-mscc/include/mach/common.h |  38 ++++
> >  drivers/spi/Kconfig                       |   7 +
> >  drivers/spi/Makefile                      |   1 +
> >  drivers/spi/mscc_bb_spi.c                 | 253
> ++++++++++++++++++++++
> >  5 files changed, 300 insertions(+)
> >  create mode 100644 drivers/spi/mscc_bb_spi.c
> >
> 
> Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
> 
> nits below
> 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 494962e9b3..0cee99ef56 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -524,6 +524,7 @@ F:	arch/mips/dts/ocelot*
> >  F:	board/mscc/
> >  F:	configs/mscc*
> >  F:	drivers/gpio/mscc_sgpio.c
> > +F:	drivers/spi/mscc_bb_spi.c
> >  F:	include/configs/vcoreiii.h
> >
> >  MIPS JZ4780
> > diff --git a/arch/mips/mach-mscc/include/mach/common.h
> b/arch/mips/mach-mscc/include/mach/common.h
> > index d18ae78bfd..7765c060ed 100644
> > --- a/arch/mips/mach-mscc/include/mach/common.h
> > +++ b/arch/mips/mach-mscc/include/mach/common.h
> > @@ -29,6 +29,44 @@
> >
> >  /* Common utility functions */
> >
> > +/*
> > + * Perform a number of NOP instructions, blocks of 8 instructions.
> > + * The (inlined) function will not affect cache or processor state.
> > + */
> > +static inline void mscc_vcoreiii_nop_delay(int delay)
> > +{
> > +	while (delay > 0) {
> > +#define DELAY_8_NOPS() asm volatile("nop; nop; nop; nop; nop; nop;
> nop; nop;")
> > +		switch (delay) {
> > +		case 8:
> > +			DELAY_8_NOPS();
> > +			/* fallthrough */
> > +		case 7:
> > +			DELAY_8_NOPS();
> > +			/* fallthrough */
> > +		case 6:
> > +			DELAY_8_NOPS();
> > +			/* fallthrough */
> > +		case 5:
> > +			DELAY_8_NOPS();
> > +			/* fallthrough */
> > +		case 4:
> > +			DELAY_8_NOPS();
> > +			/* fallthrough */
> > +		case 3:
> > +			DELAY_8_NOPS();
> > +			/* fallthrough */
> > +		case 2:
> > +			DELAY_8_NOPS();
> > +			/* fallthrough */
> > +		case 1:
> > +			DELAY_8_NOPS();
> > +		}
> > +		delay -= 8;
> > +#undef DELAY_8_NOPS
> > +	}
> > +}
> > +
> >  int mscc_phy_rd_wr(u8 read,
> >  		   u32 miim_controller,
> >  		   u8 miim_addr,
> > diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> > index a7bb5b35c2..de4d62dd8f 100644
> > --- a/drivers/spi/Kconfig
> > +++ b/drivers/spi/Kconfig
> > @@ -294,6 +294,13 @@ config SOFT_SPI
> >  	 Enable Soft SPI driver. This driver is to use GPIO simulate
> >  	 the SPI protocol.
> >
> > +config MSCC_BB_SPI
> > +	bool "MSCC bitbang SPI driver"
> > +	depends on SOC_VCOREIII
> > +	help
> > +	  Enable MSCC bitbang SPI driver. This driver can be used on
> > +	  MSCC SOCs.
> > +
> >  config CF_SPI
> >  	bool "ColdFire SPI driver"
> >  	help
> > diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> > index 392a925795..4acec3ea17 100644
> > --- a/drivers/spi/Makefile
> > +++ b/drivers/spi/Makefile
> > @@ -36,6 +36,7 @@ obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o
> >  obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
> >  obj-$(CONFIG_MTK_QSPI) += mtk_qspi.o
> >  obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o
> > +obj-$(CONFIG_MSCC_BB_SPI) += mscc_bb_spi.o
> >  obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o
> >  obj-$(CONFIG_MXC_SPI) += mxc_spi.o
> >  obj-$(CONFIG_MXS_SPI) += mxs_spi.o
> > diff --git a/drivers/spi/mscc_bb_spi.c b/drivers/spi/mscc_bb_spi.c
> > new file mode 100644
> > index 0000000000..5685878597
> > --- /dev/null
> > +++ b/drivers/spi/mscc_bb_spi.c
> > @@ -0,0 +1,253 @@
> > +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> > +/*
> > + * Microsemi SoCs spi driver
> > + *
> > + * Copyright (c) 2018 Microsemi Corporation
> > + */
> > +
> > +#include <common.h>
> > +#include <dm.h>
> > +#include <errno.h>
> > +#include <malloc.h>
> > +#include <spi.h>
> > +#include <dm.h>
> > +#include <asm/gpio.h>
> > +#include <asm/io.h>
> > +#include <linux/delay.h>
> > +
> > +struct mscc_bb_platdata {
> > +	void __iomem *regs;
> > +	u32 deactivate_delay_us;
> > +};
> 
> you could drop this along with mscc_bb_spi_ofdata_to_platdata() if you
> don't need to support a non-device-tree config or a SPL with DM and
> platdata only (I guess neither is true for MSCC platform). Otherwise you
> can init mscc_bb_priv from device-tree in your probe function.

We only use DT configs, so I will move this to the probe func.

> 
> > +
> > +struct mscc_bb_priv {
> > +	void __iomem *regs;
> > +	bool cs_active;   /* State flag as to whether CS is asserted */
> > +	int cs_num;
> > +	u32 svalue;			/* Value to start transfer with */
> > +	u32 clk1;			/* Clock value start */
> > +	u32 clk2;			/* Clock value 2nd phase */
> > +};
> > +
> > +/* Delay 24 instructions for this particular application */
> > +#define hold_time_delay() mscc_vcoreiii_nop_delay(3)
> > +
> > +static int mscc_bb_spi_cs_activate(struct mscc_bb_priv *priv, int
> mode, int cs)
> > +{
> > +	if (!priv->cs_active) {
> > +		int cpha = mode & SPI_CPHA;
> > +		u32 cs_value;
> > +
> > +		priv->cs_num = cs;
> > +
> > +		if (cpha) {
> > +			/* Initial clock starts SCK=1 */
> > +			priv->clk1 = ICPU_SW_MODE_SW_SPI_SCK;
> > +			priv->clk2 = 0;
> > +		} else {
> > +			/* Initial clock starts SCK=0 */
> > +			priv->clk1 = 0;
> > +			priv->clk2 = ICPU_SW_MODE_SW_SPI_SCK;
> > +		}
> > +
> > +		/* Enable bitbang, SCK_OE, SDO_OE */
> > +		priv->svalue = (ICPU_SW_MODE_SW_PIN_CTRL_MODE | /* Bitbang */
> > +				ICPU_SW_MODE_SW_SPI_SCK_OE    | /* SCK_OE */
> > +				ICPU_SW_MODE_SW_SPI_SDO_OE);   /* SDO OE */
> > +
> > +		/* Add CS */
> > +		if (cs >= 0) {
> > +			cs_value =
> > +				ICPU_SW_MODE_SW_SPI_CS_OE(BIT(cs)) |
> > +				ICPU_SW_MODE_SW_SPI_CS(BIT(cs));
> > +		} else {
> > +			cs_value = 0;
> > +		}
> > +
> > +		priv->svalue |= cs_value;
> > +
> > +		/* Enable the CS in HW, Initial clock value */
> > +		writel(priv->svalue | priv->clk2, priv->regs);
> > +
> > +		priv->cs_active = true;
> > +		debug("Activated CS%d\n", priv->cs_num);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int mscc_bb_spi_cs_deactivate(struct mscc_bb_priv *priv, int
> deact_delay)
> > +{
> > +	if (priv->cs_active) {
> > +		/* Keep driving the CLK to its current value while
> > +		 * actively deselecting CS.
> > +		 */
> > +		u32 value = readl(priv->regs);
> > +
> > +		value &= ~ICPU_SW_MODE_SW_SPI_CS_M;
> > +		writel(value, priv->regs);
> > +		hold_time_delay();
> > +
> > +		/* Stop driving the clock, but keep CS with nCS == 1 */
> > +		value &= ~ICPU_SW_MODE_SW_SPI_SCK_OE;
> > +		writel(value, priv->regs);
> > +
> > +		/* Deselect hold time delay */
> > +		if (deact_delay)
> > +			udelay(deact_delay);
> > +
> > +		/* Drop everything */
> > +		writel(0, priv->regs);
> > +
> > +		priv->cs_active = false;
> > +		debug("Deactivated CS%d\n", priv->cs_num);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int mscc_bb_spi_claim_bus(struct udevice *dev)
> > +{
> > +	return 0;
> > +}
> > +
> > +int mscc_bb_spi_release_bus(struct udevice *dev)
> > +{
> > +	return 0;
> > +}
> > +
> > +int mscc_bb_spi_xfer(struct udevice *dev, unsigned int bitlen,
> > +		     const void *dout, void *din, unsigned long flags)
> > +{
> > +	struct udevice *bus = dev_get_parent(dev);
> > +	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
> > +	struct mscc_bb_platdata *bus_plat = dev_get_platdata(bus);
> > +	struct mscc_bb_priv *priv = dev_get_priv(bus);
> > +	u32             i, count;
> > +	const u8	*txd = dout;
> > +	u8		*rxd = din;
> > +
> > +	debug("spi_xfer: slave %s:%s cs%d mode %d, dout %p din %p bitlen
> %u\n",
> > +	      dev->parent->name, dev->name, plat->cs,  plat->mode, dout,
> > +	      din, bitlen);
> > +
> > +	if (flags & SPI_XFER_BEGIN)
> > +		mscc_bb_spi_cs_activate(priv, plat->mode, plat->cs);
> > +
> > +	count = bitlen / 8;
> > +	for (i = 0; i < count; i++) {
> > +		u32 rx = 0, mask = 0x80, value;
> > +
> > +		while (mask) {
> > +			/* Initial condition: CLK is low. */
> > +			value = priv->svalue;
> > +			if (txd && txd[i] & mask)
> > +				value |= ICPU_SW_MODE_SW_SPI_SDO;
> > +
> > +			/* Drive data while taking CLK low. The device
> > +			 * we're accessing will sample on the
> > +			 * following rising edge and will output data
> > +			 * on this edge for us to be sampled at the
> > +			 * end of this loop.
> > +			 */
> > +			writel(value | priv->clk1, priv->regs);
> > +
> > +			/* Wait for t_setup. All devices do have a
> > +			 * setup-time, so we always insert some delay
> > +			 * here. Some devices have a very long
> > +			 * setup-time, which can be adjusted by the
> > +			 * user through vcoreiii_device->delay.
> > +			 */
> > +			hold_time_delay();
> > +
> > +			/* Drive the clock high. */
> > +			writel(value | priv->clk2, priv->regs);
> > +
> > +			/* Wait for t_hold. See comment about t_setup
> > +			 * above.
> > +			 */
> > +			hold_time_delay();
> > +
> > +			/* We sample as close to the next falling edge
> > +			 * as possible.
> > +			 */
> > +			value = readl(priv->regs);
> > +			if (value & ICPU_SW_MODE_SW_SPI_SDI)
> > +				rx |= mask;
> > +			mask >>= 1;
> > +		}
> > +		if (rxd) {
> > +			debug("Read 0x%02x\n", rx);
> > +			rxd[i] = (u8)rx;
> > +		}
> > +		debug("spi_xfer: byte %d/%d\n", i + 1, count);
> > +	}
> > +
> > +	debug("spi_xfer: done\n");
> > +
> > +	if (flags & SPI_XFER_END)
> > +		mscc_bb_spi_cs_deactivate(priv, bus_plat-
> >deactivate_delay_us);
> > +
> > +	return 0;
> > +}
> > +
> > +int mscc_bb_spi_set_speed(struct udevice *dev, unsigned int speed)
> > +{
> > +	/* Accept any speed */
> > +	return 0;
> > +}
> > +
> > +int mscc_bb_spi_set_mode(struct udevice *dev, unsigned int mode)
> > +{
> > +	return 0;
> > +}
> > +
> > +static const struct dm_spi_ops mscc_bb_ops = {
> > +	.claim_bus	= mscc_bb_spi_claim_bus,
> > +	.release_bus	= mscc_bb_spi_release_bus,
> > +	.xfer		= mscc_bb_spi_xfer,
> > +	.set_speed	= mscc_bb_spi_set_speed,
> > +	.set_mode	= mscc_bb_spi_set_mode,
> > +};
> > +
> > +static const struct udevice_id mscc_bb_ids[] = {
> > +	{ .compatible = "mscc,luton-bb-spi" },
> > +	{ }
> > +};
> > +
> > +static int mscc_bb_spi_probe(struct udevice *bus)
> > +{
> > +	struct mscc_bb_priv *priv = dev_get_priv(bus);
> > +	struct mscc_bb_platdata *plat = dev_get_platdata(bus);
> > +
> > +	debug("%s: loaded, priv %p, plat %p\n", __func__, priv, plat);
> > +
> > +	/* Initialize */
> > +	priv->regs = plat->regs;
> > +	priv->cs_active = false;
> > +
> > +	return 0;
> > +}
> > +
> > +static int mscc_bb_spi_ofdata_to_platdata(struct udevice *bus)
> > +{
> > +	struct mscc_bb_platdata *plat = dev_get_platdata(bus);
> > +
> > +	plat->regs = (void __iomem *)dev_read_addr(bus);
> > +
> > +	plat->deactivate_delay_us =
> > +		dev_read_u32_default(bus, "spi-deactivate-delay", 0);
> 
> I think this property should have a "mscc," prefix if it's a custom
> properry?

At last count, 7 other drivers were using this property, so I was assuming
it was no so custom.

> 
> > +
> > +	return 0;
> > +}
> > +
> > +U_BOOT_DRIVER(mscc_bb) = {
> > +	.name	= "mscc_bb",
> > +	.id	= UCLASS_SPI,
> > +	.of_match = mscc_bb_ids,
> > +	.ops	= &mscc_bb_ops,
> > +	.ofdata_to_platdata = mscc_bb_spi_ofdata_to_platdata,
> > +	.platdata_auto_alloc_size = sizeof(struct mscc_bb_platdata),
> > +	.priv_auto_alloc_size = sizeof(struct mscc_bb_priv),
> > +	.probe	= mscc_bb_spi_probe,
> > +};
> >
> 
> --
> - Daniel

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-01-08  8:54 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-07 13:28 [U-Boot] [PATCH v2 0/3] mips: spi: mscc: Add fast bitbang SPI driver Lars Povlsen
2019-01-07 13:28 ` [U-Boot] [PATCH v2 1/3] " Lars Povlsen
2019-01-07 17:32   ` Daniel Schwierzeck
2019-01-08  8:54     ` Lars.Povlsen at microchip.com
2019-01-07 13:28 ` [U-Boot] [PATCH v2 2/3] mips: mscc: DT: Update luton device tree to use fast " Lars Povlsen
2019-01-07 13:28 ` [U-Boot] [PATCH v2 3/3] mips: gpio: mscc: Obsoleted gpio-mscc-bitbang-spi.c Lars Povlsen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.