All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/2] spi: driver for Cirrus EP93xx SPI controller
@ 2010-04-20 15:11 ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-20 15:11 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hello,

This is fourth iteration of the driver. I tried to address most of the review
comments I received.

Changes to previous version:
	- dropped polling mode, there is no real use for that
	- changes according review comments by Grant Likely, Martin Guy,
	  and H. Hartley Sweeten

Previous version can be found here (with review comments):
	http://lists.infradead.org/pipermail/linux-arm-kernel/2010-April/012941.html

Let's hope I didn't forget anything.

Tested with my TS-7260 board with mmc_spi and at25 drivers.

Note that patch 2/2 depends on patch that is already in Russell's patch
tracking system:
	http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=5998/1

Thanks,
MW

Mika Westerberg (2):
  spi: implemented driver for Cirrus EP93xx SPI controller
  ep93xx: SPI driver platform support code

 arch/arm/mach-ep93xx/clock.c                    |   14 +
 arch/arm/mach-ep93xx/core.c                     |   48 ++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h  |   32 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    2 +
 drivers/spi/Kconfig                             |   11 +
 drivers/spi/Makefile                            |    1 +
 drivers/spi/ep93xx_spi.c                        |  992 +++++++++++++++++++++++
 8 files changed, 1101 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
 create mode 100644 drivers/spi/ep93xx_spi.c


------------------------------------------------------------------------------
Download Intel® Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev

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

* [PATCH v4 0/2] spi: driver for Cirrus EP93xx SPI controller
@ 2010-04-20 15:11 ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-20 15:11 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

This is fourth iteration of the driver. I tried to address most of the review
comments I received.

Changes to previous version:
	- dropped polling mode, there is no real use for that
	- changes according review comments by Grant Likely, Martin Guy,
	  and H. Hartley Sweeten

Previous version can be found here (with review comments):
	http://lists.infradead.org/pipermail/linux-arm-kernel/2010-April/012941.html

Let's hope I didn't forget anything.

Tested with my TS-7260 board with mmc_spi and at25 drivers.

Note that patch 2/2 depends on patch that is already in Russell's patch
tracking system:
	http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=5998/1

Thanks,
MW

Mika Westerberg (2):
  spi: implemented driver for Cirrus EP93xx SPI controller
  ep93xx: SPI driver platform support code

 arch/arm/mach-ep93xx/clock.c                    |   14 +
 arch/arm/mach-ep93xx/core.c                     |   48 ++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h  |   32 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    2 +
 drivers/spi/Kconfig                             |   11 +
 drivers/spi/Makefile                            |    1 +
 drivers/spi/ep93xx_spi.c                        |  992 +++++++++++++++++++++++
 8 files changed, 1101 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
 create mode 100644 drivers/spi/ep93xx_spi.c

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-20 15:11 ` Mika Westerberg
@ 2010-04-20 15:11     ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-20 15:11 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).

Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>
---
 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h |   32 +
 drivers/spi/Kconfig                            |   11 +
 drivers/spi/Makefile                           |    1 +
 drivers/spi/ep93xx_spi.c                       |  992 ++++++++++++++++++++++++
 4 files changed, 1036 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
 create mode 100644 drivers/spi/ep93xx_spi.c

diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
new file mode 100644
index 0000000..98935d8
--- /dev/null
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
@@ -0,0 +1,32 @@
+#ifndef __ASM_MACH_EP93XX_SPI_H
+#define __ASM_MACH_EP93XX_SPI_H
+
+struct spi_device;
+
+/**
+ * struct ep93xx_spi_info - EP93xx specific SPI descriptor
+ * @num_chipselect: number of chip selects on this board, must be
+ *                  at least one
+ * @cs_control: chip select control function. Can be %NULL if not needed.
+ *
+ * This structure is passed from board support files to EP93xx SPI controller
+ * driver. It provides callback hook to control chip select lines that are
+ * allocated in board support files during the board initialization.
+ */
+struct ep93xx_spi_info {
+	int	num_chipselect;
+	/*
+	 * cs_control() - control board chipselect GPIO lines
+	 * @spi: SPI device whose chipselect is controlled
+	 * @value: value to set the chip select line to
+	 *
+	 * This function is used to control board specific chip select lines.
+	 * @value is either %0 or %1.
+	 *
+	 * This function is called from thread context and can sleep if
+	 * necessary.
+	 */
+	void	(*cs_control)(struct spi_device *spi, int value);
+};
+
+#endif /* __ASM_MACH_EP93XX_SPI_H */
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a191fa2..5852340 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -117,6 +117,17 @@ config SPI_DAVINCI
 	help
 	  SPI master controller for DaVinci and DA8xx SPI modules.
 
+config SPI_EP93XX
+	tristate "Cirrus Logic EP93xx SPI controller"
+	depends on ARCH_EP93XX
+	help
+	  This enables using the Cirrus EP93xx SPI controller in master
+	  mode. This driver supports EP9301, EP9302, EP9307, EP9312 and EP9315
+	  chips.
+
+	  To compile this driver as a module, choose M here. The module will be
+	  called ep93xx_spi.
+
 config SPI_GPIO
 	tristate "GPIO-based bitbanging SPI Master"
 	depends on GENERIC_GPIO
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d7d0f89..377f845 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_SPI_DAVINCI)		+= davinci_spi.o
 obj-$(CONFIG_SPI_DESIGNWARE)		+= dw_spi.o
 obj-$(CONFIG_SPI_DW_PCI)		+= dw_spi_pci.o
 obj-$(CONFIG_SPI_DW_MMIO)		+= dw_spi_mmio.o
+obj-$(CONFIG_SPI_EP93XX)		+= ep93xx_spi.o
 obj-$(CONFIG_SPI_GPIO)			+= spi_gpio.o
 obj-$(CONFIG_SPI_IMX)			+= spi_imx.o
 obj-$(CONFIG_SPI_LM70_LLP)		+= spi_lm70llp.o
diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
new file mode 100644
index 0000000..310032d
--- /dev/null
+++ b/drivers/spi/ep93xx_spi.c
@@ -0,0 +1,992 @@
+/*
+ * Driver for Cirrus Logic EP93xx SPI controller.
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Explicit FIFO handling code was inspired by amba-pl022 driver.
+ *
+ * For more information about the SPI controller see documentation on Cirrus
+ * Logic web site:
+ *     http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/spi/spi.h>
+
+#include <mach/ep93xx_spi.h>
+
+#define SSPCR0			0x0000
+#define SSPCR0_MODE_SHIFT	6
+#define SSPCR0_SCR_SHIFT	8
+
+#define SSPCR1			0x0004
+#define SSPCR1_RIE		BIT(0)
+#define SSPCR1_TIE		BIT(1)
+#define SSPCR1_RORIE		BIT(2)
+#define SSPCR1_LBM		BIT(3)
+#define SSPCR1_SSE		BIT(4)
+#define SSPCR1_MS		BIT(5)
+#define SSPCR1_SOD		BIT(6)
+
+#define SSPDR			0x0008
+
+#define SSPSR			0x000c
+#define SSPSR_TFE		BIT(0)
+#define SSPSR_TNF		BIT(1)
+#define SSPSR_RNE		BIT(2)
+#define SSPSR_RFF		BIT(3)
+#define SSPSR_BSY		BIT(4)
+#define SSPCPSR			0x0010
+
+#define SSPIIR			0x0014
+#define SSPIIR_RIS		BIT(0)
+#define SSPIIR_TIS		BIT(1)
+#define SSPIIR_RORIS		BIT(2)
+#define SSPICR			SSPIIR
+
+/* timeout in milliseconds */
+#define SPI_TIMEOUT		5
+/* maximum depth of RX/TX FIFO */
+#define SPI_FIFO_SIZE		8
+
+/**
+ * struct ep93xx_spi - EP93xx SPI controller structure
+ * @lock: spinlock that protects concurrent accesses to fields @running,
+ *        @current_msg and @msg_queue
+ * @pdev: pointer to platform device
+ * @clk: clock for the controller
+ * @regs_base: pointer to ioremap()'d registers
+ * @irq: IRQ number used by the driver
+ * @min_rate: minimum clock rate (in Hz) supported by the controller
+ * @max_rate: maximum clock rate (in Hz) supported by the controller
+ * @running: is the queue running
+ * @msg_queue: queue for the messages
+ * @wq: workqueue used by the driver
+ * @msg_work: work that is queued for the driver
+ * @wait: wait here until given transfer is completed
+ * @current_msg: message that is currently processed (or %NULL if none)
+ * @spi_dev: pointer to device that was previously selected
+ * @tx: current byte in transfer to transmit
+ * @rx: current byte in transfer to receive
+ * @fifo_level: how full is FIFO (%0..%SPI_FIFO_SIZE - %1). Receiving one
+ *              frame decreases this level and sending one frame increases it.
+ * @cs_control: chip select control function
+ *
+ * This structure holds EP93xx SPI controller specific information. When
+ * @running is %true, driver accepts transfer requests from protocol drivers.
+ * @current_msg is used to hold pointer to the message that is currently
+ * processed. If @current_msg is %NULL, it means that no processing is going
+ * on.
+ *
+ * Most of the fields are only written once and they can be accessed without
+ * taking the @lock. Fields that are accessed concurrently are: @current_msg,
+ * @running and @msg_queue.
+ */
+struct ep93xx_spi {
+	spinlock_t			lock;
+	const struct platform_device	*pdev;
+	struct clk			*clk;
+	void __iomem			*regs_base;
+	int				irq;
+	unsigned long			min_rate;
+	unsigned long			max_rate;
+	bool				running;
+	struct workqueue_struct		*wq;
+	struct work_struct		msg_work;
+	struct completion		wait;
+	struct list_head		msg_queue;
+	struct spi_message		*current_msg;
+	size_t				tx;
+	size_t				rx;
+	size_t				fifo_level;
+	void				(*cs_control)(struct spi_device *, int);
+};
+
+/**
+ * struct ep93xx_spi_chip - SPI device hardware settings
+ * @spi: back pointer to the SPI device
+ * @rate: max rate in hz this chip supports
+ * @div_cpsr: cpsr (pre-scaler) divider
+ * @div_scr: scr divider
+ * @dss: bits per word (4 - 16 bits)
+ *
+ * This structure is used to store hardware register specific settings for each
+ * SPI device. Settings are written to hardware by function
+ * ep93xx_spi_chip_setup().
+ */
+struct ep93xx_spi_chip {
+	const struct spi_device	*spi;
+	unsigned long		rate;
+	u8			div_cpsr;
+	u8			div_scr;
+	u8			dss;
+};
+
+/* converts bits per word to CR0.DSS value */
+#define bits_per_word_to_dss(bpw)	((bpw) - 1)
+
+static inline void
+ep93xx_spi_write_u8(const struct ep93xx_spi *espi, u16 reg, u8 value)
+{
+	__raw_writeb(value, espi->regs_base + reg);
+}
+
+static inline u8
+ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
+{
+	return __raw_readb(spi->regs_base + reg);
+}
+
+static inline void
+ep93xx_spi_write_u16(const struct ep93xx_spi *espi, u16 reg, u16 value)
+{
+	__raw_writew(value, espi->regs_base + reg);
+}
+
+static inline u16
+ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
+{
+	return __raw_readw(spi->regs_base + reg);
+}
+
+/**
+ * ep93xx_spi_enable() - enables the SPI controller and clock
+ * @espi: ep93xx SPI controller struct
+ *
+ * This function enables the SPI controller and its clock. Returns %0 in case
+ * of success and negative error in case if failure.
+ */
+static int ep93xx_spi_enable(const struct ep93xx_spi *espi)
+{
+	u8 regval;
+	int err;
+
+	err = clk_enable(espi->clk);
+	if (err)
+		return err;
+
+	regval = ep93xx_spi_read_u8(espi, SSPCR1);
+	regval |= SSPCR1_SSE;
+	ep93xx_spi_write_u8(espi, SSPCR1, regval);
+
+	return 0;
+}
+
+/**
+ * ep93xx_spi_disable() - disables the SPI controller and clock
+ * @espi: ep93xx SPI controller struct
+ *
+ * Function disables SPI controller and its clock.
+ */
+static void ep93xx_spi_disable(const struct ep93xx_spi *espi)
+{
+	u8 regval;
+
+	regval = ep93xx_spi_read_u8(espi, SSPCR1);
+	regval &= ~SSPCR1_SSE;
+	ep93xx_spi_write_u8(espi, SSPCR1, regval);
+
+	clk_disable(espi->clk);
+}
+
+/**
+ * ep93xx_spi_enable_interrupts() - enables all SPI interrupts
+ * @espi: ep93xx SPI controller struct
+ *
+ * Enables all SPI interrupts: receive overrun (ROR), transmit, and receive.
+ */
+static inline void
+ep93xx_spi_enable_interrupts(const struct ep93xx_spi *espi)
+{
+	u8 regval;
+
+	regval = ep93xx_spi_read_u8(espi, SSPCR1);
+	regval |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
+	ep93xx_spi_write_u8(espi, SSPCR1, regval);
+}
+
+/**
+ * ep93xx_spi_disable_interrupts() - disables all SPI interrupts
+ * @espi: ep93xx SPI controller struct
+ *
+ * Disables all SPI interrupts.
+ */
+static inline void
+ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
+{
+	u8 regval;
+
+	regval = ep93xx_spi_read_u8(espi, SSPCR1);
+	regval &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
+	ep93xx_spi_write_u8(espi, SSPCR1, regval);
+}
+
+/**
+ * ep93xx_spi_calc_divisors() - calculates SPI clock divisors
+ * @espi: ep93xx SPI controller struct
+ * @chip: divisors are calculated for this chip
+ * @rate: desired SPI output clock rate
+ *
+ * Function calculates cpsr (clock pre-scaler) and scr divisors based on
+ * given @rate and places them to @chip->div_cpsr and @chip->div_scr. If,
+ * for some reason, divisors cannot be calculated nothing is stored and
+ * %-EINVAL is returned.
+ */
+static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
+				    struct ep93xx_spi_chip *chip,
+				    unsigned long rate)
+{
+	unsigned long spi_clk_rate = clk_get_rate(espi->clk);
+	int cpsr, scr;
+
+	/*
+	 * Make sure that max value is between values supported by the
+	 * controller. Note that minimum value is already checked in
+	 * ep93xx_spi_transfer().
+	 */
+	rate = clamp(rate, espi->min_rate, espi->max_rate);
+
+	/*
+	 * Calculate divisors so that we can get speed according the
+	 * following formula:
+	 *	rate = spi_clock_rate / (cpsr * (1 + scr))
+	 *
+	 * cpsr must be even number and starts from 2, scr can be any number
+	 * between 0 and 255.
+	 */
+	for (cpsr = 2; cpsr <= 254; cpsr += 2) {
+		for (scr = 0; scr <= 255; scr++) {
+			if ((spi_clk_rate / (cpsr * (scr + 1))) <= rate) {
+				chip->div_scr = (u8)scr;
+				chip->div_cpsr = (u8)cpsr;
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * ep93xx_spi_select_device() - select given SPI device
+ * @espi: ep93xx SPI controller struct
+ * @spi: SPI device to select
+ *
+ * Function asserts chipselect line as specified in @spi->chip_select in board
+ * specific manner.
+ *
+ * Note that this function is called from a thread context and can sleep.
+ */
+static inline void ep93xx_spi_select_device(const struct ep93xx_spi *espi,
+					    struct spi_device *spi)
+{
+	if (espi->cs_control)
+		espi->cs_control(spi, !!(spi->mode & SPI_CS_HIGH));
+}
+
+/**
+ * ep93xx_spi_deselect_device() - deselects given SPI device
+ * @espi: ep93xx SPI controller struct
+ * @spi: SPI device to deselect
+ *
+ * Function deasserts chipselect line as specified in @spi->chip_select in board
+ * specific manner.
+ *
+ * Note that this function is called from a thread context and can sleep.
+ */
+static inline void ep93xx_spi_deselect_device(const struct ep93xx_spi *espi,
+					      struct spi_device *spi)
+{
+	if (espi->cs_control)
+		espi->cs_control(spi, !(spi->mode & SPI_CS_HIGH));
+}
+
+/**
+ * ep93xx_spi_setup() - setup an SPI device
+ * @spi: SPI device to setup
+ *
+ * This function sets up SPI device mode, speed etc. Can be called multiple
+ * times for a single device. Returns %0 in case of success, negative error in
+ * case of failure. When this function returns success, the device is
+ * deselected.
+ */
+static int ep93xx_spi_setup(struct spi_device *spi)
+{
+	struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
+	struct ep93xx_spi_chip *chip;
+
+	if (spi->bits_per_word < 4 || spi->bits_per_word > 16) {
+		dev_err(&espi->pdev->dev, "invalid bits per word %d\n",
+			spi->bits_per_word);
+		return -EINVAL;
+	}
+
+	chip = spi_get_ctldata(spi);
+	if (!chip) {
+		chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+		if (!chip)
+			return -ENOMEM;
+
+		spi_set_ctldata(spi, chip);
+		chip->spi = spi;
+	}
+
+	if (spi->max_speed_hz != chip->rate) {
+		int err;
+
+		err = ep93xx_spi_calc_divisors(espi, chip, spi->max_speed_hz);
+		if (err != 0) {
+			spi_set_ctldata(spi, NULL);
+			kfree(chip);
+			return err;
+		}
+		chip->rate = spi->max_speed_hz;
+	}
+
+	chip->dss = bits_per_word_to_dss(spi->bits_per_word);
+
+	ep93xx_spi_deselect_device(espi, spi);
+	return 0;
+}
+
+/**
+ * ep93xx_spi_transfer() - queue message to be transferred
+ * @spi: target SPI device
+ * @msg: message to be transferred
+ *
+ * This function is called by SPI device drivers when they are going to transfer
+ * a new message. It simply puts the message in the queue and schedules
+ * workqueue to perform the actual transfer later on.
+ *
+ * Returns %0 on success and negative error in case of failure.
+ */
+static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+	struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
+	struct spi_transfer *t;
+	unsigned long flags;
+
+	if (!msg || !msg->complete)
+		return -EINVAL;
+
+	/* first validate each transfer */
+	list_for_each_entry(t, &msg->transfers, transfer_list) {
+		if (t->bits_per_word) {
+			if (t->bits_per_word < 4 || t->bits_per_word > 16)
+				return -EINVAL;
+		}
+		if (t->speed_hz && t->speed_hz < espi->min_rate)
+				return -EINVAL;
+	}
+
+	/*
+	 * Now that we own the message, let's initialize it so that it is
+	 * suitable for us. We use @msg->status to signal whether there was
+	 * error in transfer and @msg->state is used to hold pointer to the
+	 * current transfer (or %NULL if no active current transfer).
+	 */
+	msg->state = NULL;
+	msg->status = 0;
+	msg->actual_length = 0;
+
+	spin_lock_irqsave(&espi->lock, flags);
+	if (!espi->running) {
+		spin_unlock_irqrestore(&espi->lock, flags);
+		return -ESHUTDOWN;
+	}
+	list_add_tail(&msg->queue, &espi->msg_queue);
+	queue_work(espi->wq, &espi->msg_work);
+	spin_unlock_irqrestore(&espi->lock, flags);
+
+	return 0;
+}
+
+/**
+ * ep93xx_spi_cleanup() - cleans up master controller specific state
+ * @spi: SPI device to cleanup
+ *
+ * This function releases master controller specific state for given @spi
+ * device.
+ */
+static void ep93xx_spi_cleanup(struct spi_device *spi)
+{
+	struct ep93xx_spi_chip *chip;
+
+	chip = spi_get_ctldata(spi);
+	if (chip) {
+		spi_set_ctldata(spi, NULL);
+		kfree(chip);
+	}
+}
+
+/**
+ * ep93xx_spi_chip_setup() - configures hardware according to given @chip
+ * @espi: ep93xx SPI controller struct
+ * @chip: chip specific settings
+ *
+ * This function sets up the actual hardware registers with settings given in
+ * @chip. Note that no validation is done so make sure that callers validate
+ * settings before calling this.
+ */
+static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
+				  const struct ep93xx_spi_chip *chip)
+{
+	u16 cr0;
+
+	cr0 = chip->div_scr << SSPCR0_SCR_SHIFT;
+	cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT;
+	cr0 |= chip->dss;
+
+	dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
+		chip->spi->mode, chip->div_cpsr, chip->div_scr, chip->dss);
+	dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0);
+
+	ep93xx_spi_write_u8(espi, SSPCPSR, chip->div_cpsr);
+	ep93xx_spi_write_u16(espi, SSPCR0, cr0);
+}
+
+/**
+ * ep93xx_spi_process_transfer() - processes one SPI transfer
+ * @espi: ep93xx SPI controller struct
+ * @msg: current message
+ * @t: transfer to process
+ *
+ * This function processes one SPI transfer given in @t. Function waits until
+ * transfer is complete (may sleep) and updates @msg->status based on whether
+ * transfer was succesfully processed or not.
+ */
+static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
+					struct spi_message *msg,
+					struct spi_transfer *t)
+{
+	struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi);
+
+	msg->state = t;
+
+	/*
+	 * Handle any transfer specific settings if needed. We use
+	 * temporary chip settings here and restore original later when
+	 * the transfer is finished.
+	 */
+	if (t->speed_hz || t->bits_per_word) {
+		struct ep93xx_spi_chip tmp_chip = *chip;
+
+		if (t->speed_hz) {
+			int err;
+
+			err = ep93xx_spi_calc_divisors(espi, &tmp_chip,
+						       t->speed_hz);
+			if (err) {
+				dev_err(&espi->pdev->dev,
+					"failed to adjust speed\n");
+				msg->status = err;
+				return;
+			}
+		}
+
+		if (t->bits_per_word)
+			tmp_chip.dss = bits_per_word_to_dss(t->bits_per_word);
+
+		/*
+		 * Set up temporary new hw settings for this transfer.
+		 */
+		ep93xx_spi_chip_setup(espi, &tmp_chip);
+	}
+
+	espi->rx = 0;
+	espi->tx = 0;
+
+	/*
+	 * Now everything is set up for the current transfer. Enable interrupts
+	 * and wait for the transfer to complete.
+	 */
+	ep93xx_spi_enable_interrupts(espi);
+	wait_for_completion(&espi->wait);
+
+	/*
+	 * In case of error during transmit, we bail out from processing
+	 * the message.
+	 */
+	if (msg->status)
+		return;
+
+	/*
+	 * After this transfer is finished, perform any possible
+	 * post-transfer actions requested by the protocol driver.
+	 */
+	if (t->delay_usecs) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(usecs_to_jiffies(t->delay_usecs));
+	}
+	if (t->cs_change) {
+		/*
+		 * In case protocol driver is asking us to drop the
+		 * chipselect briefly, we let the scheduler to handle
+		 * any "delay" here.
+		 */
+		if (!list_is_last(&t->transfer_list, &msg->transfers)) {
+			ep93xx_spi_deselect_device(espi, msg->spi);
+			cond_resched();
+			ep93xx_spi_select_device(espi, msg->spi);
+		}
+	}
+
+	if (t->speed_hz || t->bits_per_word)
+		ep93xx_spi_chip_setup(espi, chip);
+}
+
+/*
+ * ep93xx_spi_process_message() - process one SPI message
+ * @espi: ep93xx SPI controller struct
+ * @msg: message to process
+ *
+ * This function processes a single SPI message. We go through all transfers in
+ * the message and pass them to ep93xx_spi_process_transfer(). Chipselect is
+ * asserted during the whole message (unless per transfer cs_change is set).
+ *
+ * @msg->status contains %0 in case of success or negative error code in case of
+ * failure.
+ */
+static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
+				       struct spi_message *msg)
+{
+	unsigned long timeout;
+	struct spi_transfer *t;
+	int err;
+
+	/*
+	 * Enable the SPI controller and its clock.
+	 */
+	err = ep93xx_spi_enable(espi);
+	if (err) {
+		dev_err(&espi->pdev->dev, "failed to enable SPI controller\n");
+		msg->status = err;
+		return;
+	}
+
+	/*
+	 * Just to be sure: flush any data from RX FIFO.
+	 */
+	timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT);
+	while (ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_RNE) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(&espi->pdev->dev,
+				 "timeout while flushing RX fifo\n");
+			msg->status = -ETIMEDOUT;
+			return;
+		}
+		ep93xx_spi_read_u16(espi, SSPDR);
+	}
+
+	/*
+	 * We explicitly handle FIFO level. This way we don't have to check TX
+	 * FIFO status using %SSPSR_TNF bit which may cause RX FIFO overruns.
+	 */
+	espi->fifo_level = 0;
+
+	/*
+	 * Update SPI controller registers according to spi device and assert
+	 * the chipselect.
+	 */
+	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
+	ep93xx_spi_select_device(espi, msg->spi);
+
+	list_for_each_entry(t, &msg->transfers, transfer_list) {
+		ep93xx_spi_process_transfer(espi, msg, t);
+		if (msg->status)
+			break;
+	}
+
+	/*
+	 * Now the whole message is transferred (or failed for some reason). We
+	 * deselect the device and disable the SPI controller.
+	 */
+	ep93xx_spi_deselect_device(espi, msg->spi);
+	ep93xx_spi_disable(espi);
+}
+
+#define work_to_espi(work) (container_of((work), struct ep93xx_spi, msg_work))
+
+/**
+ * ep93xx_spi_work() - EP93xx SPI workqueue worker function
+ * @work: work struct
+ *
+ * Workqueue worker function. This function is called when there are new
+ * SPI messages to be processed. Message is taken out from the queue and then
+ * passed to ep93xx_spi_process_message().
+ *
+ * After message is transferred, protocol driver is notified by calling
+ * @msg->complete(). In case of error, @msg->status is set to negative error
+ * number, otherwise it contains zero (and @msg->actual_length is updated).
+ */
+static void ep93xx_spi_work(struct work_struct *work)
+{
+	struct ep93xx_spi *espi = work_to_espi(work);
+	struct spi_message *msg;
+
+	spin_lock_irq(&espi->lock);
+	if (!espi->running || espi->current_msg ||
+		list_empty(&espi->msg_queue)) {
+		spin_unlock_irq(&espi->lock);
+		return;
+	}
+	msg = list_first_entry(&espi->msg_queue, struct spi_message, queue);
+	list_del_init(&msg->queue);
+	espi->current_msg = msg;
+	spin_unlock_irq(&espi->lock);
+
+	ep93xx_spi_process_message(espi, msg);
+
+	/*
+	 * Update the current message and re-schedule ourselves if there are
+	 * more messages in the queue.
+	 */
+	spin_lock_irq(&espi->lock);
+	espi->current_msg = NULL;
+	if (espi->running && !list_empty(&espi->msg_queue))
+		queue_work(espi->wq, &espi->msg_work);
+	spin_unlock_irq(&espi->lock);
+
+	/* notify the protocol driver that we are done with this message */
+	msg->complete(msg->context);
+}
+
+/**
+ * bits_per_word() - returns bits per word for current message
+ */
+static inline int bits_per_word(const struct ep93xx_spi *espi)
+{
+	struct spi_message *msg = espi->current_msg;
+	struct spi_transfer *t = msg->state;
+
+	return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
+}
+
+static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+	if (bits_per_word(espi) > 8) {
+		u16 tx_val = 0;
+
+		if (t->tx_buf)
+			tx_val = ((u16 *)t->tx_buf)[espi->tx];
+		ep93xx_spi_write_u16(espi, SSPDR, tx_val);
+		espi->tx += sizeof(tx_val);
+	} else {
+		u8 tx_val = 0;
+
+		if (t->tx_buf)
+			tx_val = ((u8 *)t->tx_buf)[espi->tx];
+		ep93xx_spi_write_u8(espi, SSPDR, tx_val);
+		espi->tx += sizeof(tx_val);
+	}
+}
+
+static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+	if (bits_per_word(espi) > 8) {
+		u16 rx_val;
+
+		rx_val = ep93xx_spi_read_u16(espi, SSPDR);
+		if (t->rx_buf)
+			((u16 *)t->rx_buf)[espi->rx] = rx_val;
+		espi->rx += sizeof(rx_val);
+	} else {
+		u8 rx_val;
+
+		rx_val = ep93xx_spi_read_u8(espi, SSPDR);
+		if (t->rx_buf)
+			((u8 *)t->rx_buf)[espi->rx] = rx_val;
+		espi->rx += sizeof(rx_val);
+	}
+}
+
+/**
+ * ep93xx_spi_read_write() - perform next RX/TX transfer
+ * @espi: ep93xx SPI controller struct
+ *
+ * This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
+ * called several times, the whole transfer will be completed. Returns %0 when
+ * current transfer was not yet completed otherwise length of the transfer
+ * (>%0). When this function is finished, RX FIFO should be empty and TX FIFO
+ * should be full.
+ */
+static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
+{
+	struct spi_message *msg = espi->current_msg;
+	struct spi_transfer *t = msg->state;
+
+	/* read as long as RX FIFO has frames in it */
+	while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
+		ep93xx_do_read(espi, t);
+		espi->fifo_level--;
+	}
+
+	/* write as long as TX FIFO has room */
+	while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
+		ep93xx_do_write(espi, t);
+		espi->fifo_level++;
+	}
+
+	if (espi->rx == t->len) {
+		msg->actual_length += t->len;
+		return t->len;
+	}
+
+	return 0;
+}
+
+/**
+ * ep93xx_spi_interrupt() - SPI interrupt handler
+ * @irq: IRQ number (not used)
+ * @dev_id: pointer to EP93xx controller struct
+ *
+ * This function handles TX/RX/ROR interrupts that come from the SPI controller.
+ * Returns %IRQ_HANDLED when interrupt was handled and %IRQ_NONE in case the
+ * @irq was not handled.
+ */
+static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
+{
+	struct ep93xx_spi *espi = dev_id;
+	u8 irq_status;
+
+	irq_status = ep93xx_spi_read_u8(espi, SSPIIR);
+
+	if (!(irq_status & (SSPIIR_RORIS | SSPIIR_TIS | SSPIIR_RIS)))
+		return IRQ_NONE; /* not for us */
+
+	/* clear the interrupt */
+	ep93xx_spi_write_u8(espi, SSPICR, 0);
+
+	/*
+	 * If we got ROR (receive overrun) interrupt we know that something is
+	 * wrong. Just abort the message.
+	 */
+	if (unlikely(irq_status & SSPIIR_RORIS)) {
+		dev_warn(&espi->pdev->dev,
+			 "receive overrun, aborting the message\n");
+		espi->current_msg->status = -EIO;
+	} else {
+		/*
+		 * Interrupt is either RX (RIS) or TX (TIS). For both cases we
+		 * simply execute next data transfer.
+		 */
+		if (!ep93xx_spi_read_write(espi)) {
+			/*
+			 * In normal case, there still is some processing left
+			 * for current transfer. Let's wait for the next
+			 * interrupt then.
+			 */
+			return IRQ_HANDLED;
+		}
+	}
+
+	/*
+	 * Current transfer is finished, either with error or with success. In
+	 * any case we disable interrupts and notify the worker to handle
+	 * any post-processing of the message.
+	 */
+	ep93xx_spi_disable_interrupts(espi);
+	complete(&espi->wait);
+	return IRQ_HANDLED;
+}
+
+static int __init ep93xx_spi_probe(struct platform_device *pdev)
+{
+	struct spi_master *master;
+	struct ep93xx_spi_info *info;
+	struct ep93xx_spi *espi;
+	struct resource *res;
+	int error;
+
+	info = pdev->dev.platform_data;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(*espi));
+	if (!master) {
+		dev_err(&pdev->dev, "failed to allocate spi master\n");
+		return -ENOMEM;
+	}
+
+	master->setup = ep93xx_spi_setup;
+	master->transfer = ep93xx_spi_transfer;
+	master->cleanup = ep93xx_spi_cleanup;
+	master->bus_num = 0;
+	master->num_chipselect = info->num_chipselect;
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
+	platform_set_drvdata(pdev, master);
+
+	espi = spi_master_get_devdata(master);
+	espi->cs_control = info->cs_control;
+
+	espi->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(espi->clk)) {
+		dev_err(&pdev->dev, "unable to get spi clock\n");
+		error = PTR_ERR(espi->clk);
+		goto fail_release_master;
+	}
+
+	spin_lock_init(&espi->lock);
+	init_completion(&espi->wait);
+
+	/*
+	 * Calculate maximum and minimum supported clock rates
+	 * for the controller.
+	 */
+	espi->max_rate = clk_get_rate(espi->clk) / 2;
+	espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
+	espi->pdev = pdev;
+
+	espi->irq = platform_get_irq(pdev, 0);
+	if (espi->irq < 0) {
+		error = -EBUSY;
+		dev_err(&pdev->dev, "failed to get irq resources\n");
+		goto fail_put_clock;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "unable to get iomem resource\n");
+		error = -ENODEV;
+		goto fail_put_clock;
+	}
+
+	res = request_mem_region(res->start, resource_size(res), pdev->name);
+	if (!res) {
+		dev_err(&pdev->dev, "unable to request iomem resources\n");
+		error = -EBUSY;
+		goto fail_put_clock;
+	}
+
+	espi->regs_base = ioremap(res->start, resource_size(res));
+	if (!espi->regs_base) {
+		dev_err(&pdev->dev, "failed to map resources\n");
+		error = -ENODEV;
+		goto fail_free_mem;
+	}
+
+	error = request_irq(espi->irq, ep93xx_spi_interrupt, 0,
+			    "ep93xx-spi", espi);
+	if (error) {
+		dev_err(&pdev->dev, "failed to request irq\n");
+		goto fail_unmap_regs;
+	}
+
+	espi->wq = create_singlethread_workqueue("ep93xx_spid");
+	if (!espi->wq) {
+		dev_err(&pdev->dev, "unable to create workqueue\n");
+		goto fail_free_irq;
+	}
+	INIT_WORK(&espi->msg_work, ep93xx_spi_work);
+	INIT_LIST_HEAD(&espi->msg_queue);
+	espi->running = true;
+
+	/* make sure that the hardware is disabled */
+	ep93xx_spi_write_u8(espi, SSPCR1, 0);
+
+	error =	spi_register_master(master);
+	if (error) {
+		dev_err(&pdev->dev, "failed to register SPI master\n");
+		goto fail_free_queue;
+	}
+
+	dev_info(&pdev->dev, "EP93xx SPI Controller at 0x%08lx irq %d\n",
+		 (unsigned long)res->start, espi->irq);
+
+	return 0;
+
+fail_free_queue:
+	destroy_workqueue(espi->wq);
+fail_free_irq:
+	free_irq(espi->irq, espi);
+fail_unmap_regs:
+	iounmap(espi->regs_base);
+fail_free_mem:
+	release_mem_region(res->start, resource_size(res));
+fail_put_clock:
+	clk_put(espi->clk);
+fail_release_master:
+	spi_master_put(master);
+	platform_set_drvdata(pdev, NULL);
+
+	return error;
+}
+
+static int __exit ep93xx_spi_remove(struct platform_device *pdev)
+{
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct ep93xx_spi *espi = spi_master_get_devdata(master);
+	struct resource *res;
+
+	spin_lock_irq(&espi->lock);
+	espi->running = false;
+	spin_unlock_irq(&espi->lock);
+
+	destroy_workqueue(espi->wq);
+
+	/*
+	 * Complete remaining messages with %-ESHUTDOWN status.
+	 */
+	spin_lock_irq(&espi->lock);
+	while (!list_empty(&espi->msg_queue)) {
+		struct spi_message *msg;
+
+		msg = list_first_entry(&espi->msg_queue,
+				       struct spi_message, queue);
+		list_del_init(&msg->queue);
+		msg->status = -ESHUTDOWN;
+		spin_unlock_irq(&espi->lock);
+		msg->complete(msg->context);
+		spin_lock_irq(&espi->lock);
+	}
+	spin_unlock_irq(&espi->lock);
+
+	free_irq(espi->irq, espi);
+	iounmap(espi->regs_base);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+	clk_put(espi->clk);
+	platform_set_drvdata(pdev, NULL);
+
+	spi_unregister_master(master);
+	return 0;
+}
+
+static struct platform_driver ep93xx_spi_driver = {
+	.driver		= {
+		.name	= "ep93xx-spi",
+		.owner	= THIS_MODULE,
+	},
+	.remove		= __exit_p(ep93xx_spi_remove),
+};
+
+static int __init ep93xx_spi_init(void)
+{
+	return platform_driver_probe(&ep93xx_spi_driver, ep93xx_spi_probe);
+}
+module_init(ep93xx_spi_init);
+
+static void __exit ep93xx_spi_exit(void)
+{
+	platform_driver_unregister(&ep93xx_spi_driver);
+}
+module_exit(ep93xx_spi_exit);
+
+MODULE_DESCRIPTION("EP93xx SPI Controller driver");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-spi");
-- 
1.5.6.5


------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-20 15:11     ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-20 15:11 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).

Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
---
 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h |   32 +
 drivers/spi/Kconfig                            |   11 +
 drivers/spi/Makefile                           |    1 +
 drivers/spi/ep93xx_spi.c                       |  992 ++++++++++++++++++++++++
 4 files changed, 1036 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
 create mode 100644 drivers/spi/ep93xx_spi.c

diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
new file mode 100644
index 0000000..98935d8
--- /dev/null
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_spi.h
@@ -0,0 +1,32 @@
+#ifndef __ASM_MACH_EP93XX_SPI_H
+#define __ASM_MACH_EP93XX_SPI_H
+
+struct spi_device;
+
+/**
+ * struct ep93xx_spi_info - EP93xx specific SPI descriptor
+ * @num_chipselect: number of chip selects on this board, must be
+ *                  at least one
+ * @cs_control: chip select control function. Can be %NULL if not needed.
+ *
+ * This structure is passed from board support files to EP93xx SPI controller
+ * driver. It provides callback hook to control chip select lines that are
+ * allocated in board support files during the board initialization.
+ */
+struct ep93xx_spi_info {
+	int	num_chipselect;
+	/*
+	 * cs_control() - control board chipselect GPIO lines
+	 * @spi: SPI device whose chipselect is controlled
+	 * @value: value to set the chip select line to
+	 *
+	 * This function is used to control board specific chip select lines.
+	 * @value is either %0 or %1.
+	 *
+	 * This function is called from thread context and can sleep if
+	 * necessary.
+	 */
+	void	(*cs_control)(struct spi_device *spi, int value);
+};
+
+#endif /* __ASM_MACH_EP93XX_SPI_H */
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a191fa2..5852340 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -117,6 +117,17 @@ config SPI_DAVINCI
 	help
 	  SPI master controller for DaVinci and DA8xx SPI modules.
 
+config SPI_EP93XX
+	tristate "Cirrus Logic EP93xx SPI controller"
+	depends on ARCH_EP93XX
+	help
+	  This enables using the Cirrus EP93xx SPI controller in master
+	  mode. This driver supports EP9301, EP9302, EP9307, EP9312 and EP9315
+	  chips.
+
+	  To compile this driver as a module, choose M here. The module will be
+	  called ep93xx_spi.
+
 config SPI_GPIO
 	tristate "GPIO-based bitbanging SPI Master"
 	depends on GENERIC_GPIO
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d7d0f89..377f845 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_SPI_DAVINCI)		+= davinci_spi.o
 obj-$(CONFIG_SPI_DESIGNWARE)		+= dw_spi.o
 obj-$(CONFIG_SPI_DW_PCI)		+= dw_spi_pci.o
 obj-$(CONFIG_SPI_DW_MMIO)		+= dw_spi_mmio.o
+obj-$(CONFIG_SPI_EP93XX)		+= ep93xx_spi.o
 obj-$(CONFIG_SPI_GPIO)			+= spi_gpio.o
 obj-$(CONFIG_SPI_IMX)			+= spi_imx.o
 obj-$(CONFIG_SPI_LM70_LLP)		+= spi_lm70llp.o
diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
new file mode 100644
index 0000000..310032d
--- /dev/null
+++ b/drivers/spi/ep93xx_spi.c
@@ -0,0 +1,992 @@
+/*
+ * Driver for Cirrus Logic EP93xx SPI controller.
+ *
+ * Copyright (c) 2010 Mika Westerberg
+ *
+ * Explicit FIFO handling code was inspired by amba-pl022 driver.
+ *
+ * For more information about the SPI controller see documentation on Cirrus
+ * Logic web site:
+ *     http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/spi/spi.h>
+
+#include <mach/ep93xx_spi.h>
+
+#define SSPCR0			0x0000
+#define SSPCR0_MODE_SHIFT	6
+#define SSPCR0_SCR_SHIFT	8
+
+#define SSPCR1			0x0004
+#define SSPCR1_RIE		BIT(0)
+#define SSPCR1_TIE		BIT(1)
+#define SSPCR1_RORIE		BIT(2)
+#define SSPCR1_LBM		BIT(3)
+#define SSPCR1_SSE		BIT(4)
+#define SSPCR1_MS		BIT(5)
+#define SSPCR1_SOD		BIT(6)
+
+#define SSPDR			0x0008
+
+#define SSPSR			0x000c
+#define SSPSR_TFE		BIT(0)
+#define SSPSR_TNF		BIT(1)
+#define SSPSR_RNE		BIT(2)
+#define SSPSR_RFF		BIT(3)
+#define SSPSR_BSY		BIT(4)
+#define SSPCPSR			0x0010
+
+#define SSPIIR			0x0014
+#define SSPIIR_RIS		BIT(0)
+#define SSPIIR_TIS		BIT(1)
+#define SSPIIR_RORIS		BIT(2)
+#define SSPICR			SSPIIR
+
+/* timeout in milliseconds */
+#define SPI_TIMEOUT		5
+/* maximum depth of RX/TX FIFO */
+#define SPI_FIFO_SIZE		8
+
+/**
+ * struct ep93xx_spi - EP93xx SPI controller structure
+ * @lock: spinlock that protects concurrent accesses to fields @running,
+ *        @current_msg and @msg_queue
+ * @pdev: pointer to platform device
+ * @clk: clock for the controller
+ * @regs_base: pointer to ioremap()'d registers
+ * @irq: IRQ number used by the driver
+ * @min_rate: minimum clock rate (in Hz) supported by the controller
+ * @max_rate: maximum clock rate (in Hz) supported by the controller
+ * @running: is the queue running
+ * @msg_queue: queue for the messages
+ * @wq: workqueue used by the driver
+ * @msg_work: work that is queued for the driver
+ * @wait: wait here until given transfer is completed
+ * @current_msg: message that is currently processed (or %NULL if none)
+ * @spi_dev: pointer to device that was previously selected
+ * @tx: current byte in transfer to transmit
+ * @rx: current byte in transfer to receive
+ * @fifo_level: how full is FIFO (%0..%SPI_FIFO_SIZE - %1). Receiving one
+ *              frame decreases this level and sending one frame increases it.
+ * @cs_control: chip select control function
+ *
+ * This structure holds EP93xx SPI controller specific information. When
+ * @running is %true, driver accepts transfer requests from protocol drivers.
+ * @current_msg is used to hold pointer to the message that is currently
+ * processed. If @current_msg is %NULL, it means that no processing is going
+ * on.
+ *
+ * Most of the fields are only written once and they can be accessed without
+ * taking the @lock. Fields that are accessed concurrently are: @current_msg,
+ * @running and @msg_queue.
+ */
+struct ep93xx_spi {
+	spinlock_t			lock;
+	const struct platform_device	*pdev;
+	struct clk			*clk;
+	void __iomem			*regs_base;
+	int				irq;
+	unsigned long			min_rate;
+	unsigned long			max_rate;
+	bool				running;
+	struct workqueue_struct		*wq;
+	struct work_struct		msg_work;
+	struct completion		wait;
+	struct list_head		msg_queue;
+	struct spi_message		*current_msg;
+	size_t				tx;
+	size_t				rx;
+	size_t				fifo_level;
+	void				(*cs_control)(struct spi_device *, int);
+};
+
+/**
+ * struct ep93xx_spi_chip - SPI device hardware settings
+ * @spi: back pointer to the SPI device
+ * @rate: max rate in hz this chip supports
+ * @div_cpsr: cpsr (pre-scaler) divider
+ * @div_scr: scr divider
+ * @dss: bits per word (4 - 16 bits)
+ *
+ * This structure is used to store hardware register specific settings for each
+ * SPI device. Settings are written to hardware by function
+ * ep93xx_spi_chip_setup().
+ */
+struct ep93xx_spi_chip {
+	const struct spi_device	*spi;
+	unsigned long		rate;
+	u8			div_cpsr;
+	u8			div_scr;
+	u8			dss;
+};
+
+/* converts bits per word to CR0.DSS value */
+#define bits_per_word_to_dss(bpw)	((bpw) - 1)
+
+static inline void
+ep93xx_spi_write_u8(const struct ep93xx_spi *espi, u16 reg, u8 value)
+{
+	__raw_writeb(value, espi->regs_base + reg);
+}
+
+static inline u8
+ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
+{
+	return __raw_readb(spi->regs_base + reg);
+}
+
+static inline void
+ep93xx_spi_write_u16(const struct ep93xx_spi *espi, u16 reg, u16 value)
+{
+	__raw_writew(value, espi->regs_base + reg);
+}
+
+static inline u16
+ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
+{
+	return __raw_readw(spi->regs_base + reg);
+}
+
+/**
+ * ep93xx_spi_enable() - enables the SPI controller and clock
+ * @espi: ep93xx SPI controller struct
+ *
+ * This function enables the SPI controller and its clock. Returns %0 in case
+ * of success and negative error in case if failure.
+ */
+static int ep93xx_spi_enable(const struct ep93xx_spi *espi)
+{
+	u8 regval;
+	int err;
+
+	err = clk_enable(espi->clk);
+	if (err)
+		return err;
+
+	regval = ep93xx_spi_read_u8(espi, SSPCR1);
+	regval |= SSPCR1_SSE;
+	ep93xx_spi_write_u8(espi, SSPCR1, regval);
+
+	return 0;
+}
+
+/**
+ * ep93xx_spi_disable() - disables the SPI controller and clock
+ * @espi: ep93xx SPI controller struct
+ *
+ * Function disables SPI controller and its clock.
+ */
+static void ep93xx_spi_disable(const struct ep93xx_spi *espi)
+{
+	u8 regval;
+
+	regval = ep93xx_spi_read_u8(espi, SSPCR1);
+	regval &= ~SSPCR1_SSE;
+	ep93xx_spi_write_u8(espi, SSPCR1, regval);
+
+	clk_disable(espi->clk);
+}
+
+/**
+ * ep93xx_spi_enable_interrupts() - enables all SPI interrupts
+ * @espi: ep93xx SPI controller struct
+ *
+ * Enables all SPI interrupts: receive overrun (ROR), transmit, and receive.
+ */
+static inline void
+ep93xx_spi_enable_interrupts(const struct ep93xx_spi *espi)
+{
+	u8 regval;
+
+	regval = ep93xx_spi_read_u8(espi, SSPCR1);
+	regval |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
+	ep93xx_spi_write_u8(espi, SSPCR1, regval);
+}
+
+/**
+ * ep93xx_spi_disable_interrupts() - disables all SPI interrupts
+ * @espi: ep93xx SPI controller struct
+ *
+ * Disables all SPI interrupts.
+ */
+static inline void
+ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
+{
+	u8 regval;
+
+	regval = ep93xx_spi_read_u8(espi, SSPCR1);
+	regval &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
+	ep93xx_spi_write_u8(espi, SSPCR1, regval);
+}
+
+/**
+ * ep93xx_spi_calc_divisors() - calculates SPI clock divisors
+ * @espi: ep93xx SPI controller struct
+ * @chip: divisors are calculated for this chip
+ * @rate: desired SPI output clock rate
+ *
+ * Function calculates cpsr (clock pre-scaler) and scr divisors based on
+ * given @rate and places them to @chip->div_cpsr and @chip->div_scr. If,
+ * for some reason, divisors cannot be calculated nothing is stored and
+ * %-EINVAL is returned.
+ */
+static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
+				    struct ep93xx_spi_chip *chip,
+				    unsigned long rate)
+{
+	unsigned long spi_clk_rate = clk_get_rate(espi->clk);
+	int cpsr, scr;
+
+	/*
+	 * Make sure that max value is between values supported by the
+	 * controller. Note that minimum value is already checked in
+	 * ep93xx_spi_transfer().
+	 */
+	rate = clamp(rate, espi->min_rate, espi->max_rate);
+
+	/*
+	 * Calculate divisors so that we can get speed according the
+	 * following formula:
+	 *	rate = spi_clock_rate / (cpsr * (1 + scr))
+	 *
+	 * cpsr must be even number and starts from 2, scr can be any number
+	 * between 0 and 255.
+	 */
+	for (cpsr = 2; cpsr <= 254; cpsr += 2) {
+		for (scr = 0; scr <= 255; scr++) {
+			if ((spi_clk_rate / (cpsr * (scr + 1))) <= rate) {
+				chip->div_scr = (u8)scr;
+				chip->div_cpsr = (u8)cpsr;
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+/**
+ * ep93xx_spi_select_device() - select given SPI device
+ * @espi: ep93xx SPI controller struct
+ * @spi: SPI device to select
+ *
+ * Function asserts chipselect line as specified in @spi->chip_select in board
+ * specific manner.
+ *
+ * Note that this function is called from a thread context and can sleep.
+ */
+static inline void ep93xx_spi_select_device(const struct ep93xx_spi *espi,
+					    struct spi_device *spi)
+{
+	if (espi->cs_control)
+		espi->cs_control(spi, !!(spi->mode & SPI_CS_HIGH));
+}
+
+/**
+ * ep93xx_spi_deselect_device() - deselects given SPI device
+ * @espi: ep93xx SPI controller struct
+ * @spi: SPI device to deselect
+ *
+ * Function deasserts chipselect line as specified in @spi->chip_select in board
+ * specific manner.
+ *
+ * Note that this function is called from a thread context and can sleep.
+ */
+static inline void ep93xx_spi_deselect_device(const struct ep93xx_spi *espi,
+					      struct spi_device *spi)
+{
+	if (espi->cs_control)
+		espi->cs_control(spi, !(spi->mode & SPI_CS_HIGH));
+}
+
+/**
+ * ep93xx_spi_setup() - setup an SPI device
+ * @spi: SPI device to setup
+ *
+ * This function sets up SPI device mode, speed etc. Can be called multiple
+ * times for a single device. Returns %0 in case of success, negative error in
+ * case of failure. When this function returns success, the device is
+ * deselected.
+ */
+static int ep93xx_spi_setup(struct spi_device *spi)
+{
+	struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
+	struct ep93xx_spi_chip *chip;
+
+	if (spi->bits_per_word < 4 || spi->bits_per_word > 16) {
+		dev_err(&espi->pdev->dev, "invalid bits per word %d\n",
+			spi->bits_per_word);
+		return -EINVAL;
+	}
+
+	chip = spi_get_ctldata(spi);
+	if (!chip) {
+		chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+		if (!chip)
+			return -ENOMEM;
+
+		spi_set_ctldata(spi, chip);
+		chip->spi = spi;
+	}
+
+	if (spi->max_speed_hz != chip->rate) {
+		int err;
+
+		err = ep93xx_spi_calc_divisors(espi, chip, spi->max_speed_hz);
+		if (err != 0) {
+			spi_set_ctldata(spi, NULL);
+			kfree(chip);
+			return err;
+		}
+		chip->rate = spi->max_speed_hz;
+	}
+
+	chip->dss = bits_per_word_to_dss(spi->bits_per_word);
+
+	ep93xx_spi_deselect_device(espi, spi);
+	return 0;
+}
+
+/**
+ * ep93xx_spi_transfer() - queue message to be transferred
+ * @spi: target SPI device
+ * @msg: message to be transferred
+ *
+ * This function is called by SPI device drivers when they are going to transfer
+ * a new message. It simply puts the message in the queue and schedules
+ * workqueue to perform the actual transfer later on.
+ *
+ * Returns %0 on success and negative error in case of failure.
+ */
+static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+	struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
+	struct spi_transfer *t;
+	unsigned long flags;
+
+	if (!msg || !msg->complete)
+		return -EINVAL;
+
+	/* first validate each transfer */
+	list_for_each_entry(t, &msg->transfers, transfer_list) {
+		if (t->bits_per_word) {
+			if (t->bits_per_word < 4 || t->bits_per_word > 16)
+				return -EINVAL;
+		}
+		if (t->speed_hz && t->speed_hz < espi->min_rate)
+				return -EINVAL;
+	}
+
+	/*
+	 * Now that we own the message, let's initialize it so that it is
+	 * suitable for us. We use @msg->status to signal whether there was
+	 * error in transfer and @msg->state is used to hold pointer to the
+	 * current transfer (or %NULL if no active current transfer).
+	 */
+	msg->state = NULL;
+	msg->status = 0;
+	msg->actual_length = 0;
+
+	spin_lock_irqsave(&espi->lock, flags);
+	if (!espi->running) {
+		spin_unlock_irqrestore(&espi->lock, flags);
+		return -ESHUTDOWN;
+	}
+	list_add_tail(&msg->queue, &espi->msg_queue);
+	queue_work(espi->wq, &espi->msg_work);
+	spin_unlock_irqrestore(&espi->lock, flags);
+
+	return 0;
+}
+
+/**
+ * ep93xx_spi_cleanup() - cleans up master controller specific state
+ * @spi: SPI device to cleanup
+ *
+ * This function releases master controller specific state for given @spi
+ * device.
+ */
+static void ep93xx_spi_cleanup(struct spi_device *spi)
+{
+	struct ep93xx_spi_chip *chip;
+
+	chip = spi_get_ctldata(spi);
+	if (chip) {
+		spi_set_ctldata(spi, NULL);
+		kfree(chip);
+	}
+}
+
+/**
+ * ep93xx_spi_chip_setup() - configures hardware according to given @chip
+ * @espi: ep93xx SPI controller struct
+ * @chip: chip specific settings
+ *
+ * This function sets up the actual hardware registers with settings given in
+ * @chip. Note that no validation is done so make sure that callers validate
+ * settings before calling this.
+ */
+static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
+				  const struct ep93xx_spi_chip *chip)
+{
+	u16 cr0;
+
+	cr0 = chip->div_scr << SSPCR0_SCR_SHIFT;
+	cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT;
+	cr0 |= chip->dss;
+
+	dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
+		chip->spi->mode, chip->div_cpsr, chip->div_scr, chip->dss);
+	dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0);
+
+	ep93xx_spi_write_u8(espi, SSPCPSR, chip->div_cpsr);
+	ep93xx_spi_write_u16(espi, SSPCR0, cr0);
+}
+
+/**
+ * ep93xx_spi_process_transfer() - processes one SPI transfer
+ * @espi: ep93xx SPI controller struct
+ * @msg: current message
+ * @t: transfer to process
+ *
+ * This function processes one SPI transfer given in @t. Function waits until
+ * transfer is complete (may sleep) and updates @msg->status based on whether
+ * transfer was succesfully processed or not.
+ */
+static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
+					struct spi_message *msg,
+					struct spi_transfer *t)
+{
+	struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi);
+
+	msg->state = t;
+
+	/*
+	 * Handle any transfer specific settings if needed. We use
+	 * temporary chip settings here and restore original later when
+	 * the transfer is finished.
+	 */
+	if (t->speed_hz || t->bits_per_word) {
+		struct ep93xx_spi_chip tmp_chip = *chip;
+
+		if (t->speed_hz) {
+			int err;
+
+			err = ep93xx_spi_calc_divisors(espi, &tmp_chip,
+						       t->speed_hz);
+			if (err) {
+				dev_err(&espi->pdev->dev,
+					"failed to adjust speed\n");
+				msg->status = err;
+				return;
+			}
+		}
+
+		if (t->bits_per_word)
+			tmp_chip.dss = bits_per_word_to_dss(t->bits_per_word);
+
+		/*
+		 * Set up temporary new hw settings for this transfer.
+		 */
+		ep93xx_spi_chip_setup(espi, &tmp_chip);
+	}
+
+	espi->rx = 0;
+	espi->tx = 0;
+
+	/*
+	 * Now everything is set up for the current transfer. Enable interrupts
+	 * and wait for the transfer to complete.
+	 */
+	ep93xx_spi_enable_interrupts(espi);
+	wait_for_completion(&espi->wait);
+
+	/*
+	 * In case of error during transmit, we bail out from processing
+	 * the message.
+	 */
+	if (msg->status)
+		return;
+
+	/*
+	 * After this transfer is finished, perform any possible
+	 * post-transfer actions requested by the protocol driver.
+	 */
+	if (t->delay_usecs) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(usecs_to_jiffies(t->delay_usecs));
+	}
+	if (t->cs_change) {
+		/*
+		 * In case protocol driver is asking us to drop the
+		 * chipselect briefly, we let the scheduler to handle
+		 * any "delay" here.
+		 */
+		if (!list_is_last(&t->transfer_list, &msg->transfers)) {
+			ep93xx_spi_deselect_device(espi, msg->spi);
+			cond_resched();
+			ep93xx_spi_select_device(espi, msg->spi);
+		}
+	}
+
+	if (t->speed_hz || t->bits_per_word)
+		ep93xx_spi_chip_setup(espi, chip);
+}
+
+/*
+ * ep93xx_spi_process_message() - process one SPI message
+ * @espi: ep93xx SPI controller struct
+ * @msg: message to process
+ *
+ * This function processes a single SPI message. We go through all transfers in
+ * the message and pass them to ep93xx_spi_process_transfer(). Chipselect is
+ * asserted during the whole message (unless per transfer cs_change is set).
+ *
+ * @msg->status contains %0 in case of success or negative error code in case of
+ * failure.
+ */
+static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
+				       struct spi_message *msg)
+{
+	unsigned long timeout;
+	struct spi_transfer *t;
+	int err;
+
+	/*
+	 * Enable the SPI controller and its clock.
+	 */
+	err = ep93xx_spi_enable(espi);
+	if (err) {
+		dev_err(&espi->pdev->dev, "failed to enable SPI controller\n");
+		msg->status = err;
+		return;
+	}
+
+	/*
+	 * Just to be sure: flush any data from RX FIFO.
+	 */
+	timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT);
+	while (ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_RNE) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(&espi->pdev->dev,
+				 "timeout while flushing RX fifo\n");
+			msg->status = -ETIMEDOUT;
+			return;
+		}
+		ep93xx_spi_read_u16(espi, SSPDR);
+	}
+
+	/*
+	 * We explicitly handle FIFO level. This way we don't have to check TX
+	 * FIFO status using %SSPSR_TNF bit which may cause RX FIFO overruns.
+	 */
+	espi->fifo_level = 0;
+
+	/*
+	 * Update SPI controller registers according to spi device and assert
+	 * the chipselect.
+	 */
+	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
+	ep93xx_spi_select_device(espi, msg->spi);
+
+	list_for_each_entry(t, &msg->transfers, transfer_list) {
+		ep93xx_spi_process_transfer(espi, msg, t);
+		if (msg->status)
+			break;
+	}
+
+	/*
+	 * Now the whole message is transferred (or failed for some reason). We
+	 * deselect the device and disable the SPI controller.
+	 */
+	ep93xx_spi_deselect_device(espi, msg->spi);
+	ep93xx_spi_disable(espi);
+}
+
+#define work_to_espi(work) (container_of((work), struct ep93xx_spi, msg_work))
+
+/**
+ * ep93xx_spi_work() - EP93xx SPI workqueue worker function
+ * @work: work struct
+ *
+ * Workqueue worker function. This function is called when there are new
+ * SPI messages to be processed. Message is taken out from the queue and then
+ * passed to ep93xx_spi_process_message().
+ *
+ * After message is transferred, protocol driver is notified by calling
+ * @msg->complete(). In case of error, @msg->status is set to negative error
+ * number, otherwise it contains zero (and @msg->actual_length is updated).
+ */
+static void ep93xx_spi_work(struct work_struct *work)
+{
+	struct ep93xx_spi *espi = work_to_espi(work);
+	struct spi_message *msg;
+
+	spin_lock_irq(&espi->lock);
+	if (!espi->running || espi->current_msg ||
+		list_empty(&espi->msg_queue)) {
+		spin_unlock_irq(&espi->lock);
+		return;
+	}
+	msg = list_first_entry(&espi->msg_queue, struct spi_message, queue);
+	list_del_init(&msg->queue);
+	espi->current_msg = msg;
+	spin_unlock_irq(&espi->lock);
+
+	ep93xx_spi_process_message(espi, msg);
+
+	/*
+	 * Update the current message and re-schedule ourselves if there are
+	 * more messages in the queue.
+	 */
+	spin_lock_irq(&espi->lock);
+	espi->current_msg = NULL;
+	if (espi->running && !list_empty(&espi->msg_queue))
+		queue_work(espi->wq, &espi->msg_work);
+	spin_unlock_irq(&espi->lock);
+
+	/* notify the protocol driver that we are done with this message */
+	msg->complete(msg->context);
+}
+
+/**
+ * bits_per_word() - returns bits per word for current message
+ */
+static inline int bits_per_word(const struct ep93xx_spi *espi)
+{
+	struct spi_message *msg = espi->current_msg;
+	struct spi_transfer *t = msg->state;
+
+	return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
+}
+
+static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+	if (bits_per_word(espi) > 8) {
+		u16 tx_val = 0;
+
+		if (t->tx_buf)
+			tx_val = ((u16 *)t->tx_buf)[espi->tx];
+		ep93xx_spi_write_u16(espi, SSPDR, tx_val);
+		espi->tx += sizeof(tx_val);
+	} else {
+		u8 tx_val = 0;
+
+		if (t->tx_buf)
+			tx_val = ((u8 *)t->tx_buf)[espi->tx];
+		ep93xx_spi_write_u8(espi, SSPDR, tx_val);
+		espi->tx += sizeof(tx_val);
+	}
+}
+
+static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+	if (bits_per_word(espi) > 8) {
+		u16 rx_val;
+
+		rx_val = ep93xx_spi_read_u16(espi, SSPDR);
+		if (t->rx_buf)
+			((u16 *)t->rx_buf)[espi->rx] = rx_val;
+		espi->rx += sizeof(rx_val);
+	} else {
+		u8 rx_val;
+
+		rx_val = ep93xx_spi_read_u8(espi, SSPDR);
+		if (t->rx_buf)
+			((u8 *)t->rx_buf)[espi->rx] = rx_val;
+		espi->rx += sizeof(rx_val);
+	}
+}
+
+/**
+ * ep93xx_spi_read_write() - perform next RX/TX transfer
+ * @espi: ep93xx SPI controller struct
+ *
+ * This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
+ * called several times, the whole transfer will be completed. Returns %0 when
+ * current transfer was not yet completed otherwise length of the transfer
+ * (>%0). When this function is finished, RX FIFO should be empty and TX FIFO
+ * should be full.
+ */
+static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
+{
+	struct spi_message *msg = espi->current_msg;
+	struct spi_transfer *t = msg->state;
+
+	/* read as long as RX FIFO has frames in it */
+	while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
+		ep93xx_do_read(espi, t);
+		espi->fifo_level--;
+	}
+
+	/* write as long as TX FIFO has room */
+	while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
+		ep93xx_do_write(espi, t);
+		espi->fifo_level++;
+	}
+
+	if (espi->rx == t->len) {
+		msg->actual_length += t->len;
+		return t->len;
+	}
+
+	return 0;
+}
+
+/**
+ * ep93xx_spi_interrupt() - SPI interrupt handler
+ * @irq: IRQ number (not used)
+ * @dev_id: pointer to EP93xx controller struct
+ *
+ * This function handles TX/RX/ROR interrupts that come from the SPI controller.
+ * Returns %IRQ_HANDLED when interrupt was handled and %IRQ_NONE in case the
+ * @irq was not handled.
+ */
+static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
+{
+	struct ep93xx_spi *espi = dev_id;
+	u8 irq_status;
+
+	irq_status = ep93xx_spi_read_u8(espi, SSPIIR);
+
+	if (!(irq_status & (SSPIIR_RORIS | SSPIIR_TIS | SSPIIR_RIS)))
+		return IRQ_NONE; /* not for us */
+
+	/* clear the interrupt */
+	ep93xx_spi_write_u8(espi, SSPICR, 0);
+
+	/*
+	 * If we got ROR (receive overrun) interrupt we know that something is
+	 * wrong. Just abort the message.
+	 */
+	if (unlikely(irq_status & SSPIIR_RORIS)) {
+		dev_warn(&espi->pdev->dev,
+			 "receive overrun, aborting the message\n");
+		espi->current_msg->status = -EIO;
+	} else {
+		/*
+		 * Interrupt is either RX (RIS) or TX (TIS). For both cases we
+		 * simply execute next data transfer.
+		 */
+		if (!ep93xx_spi_read_write(espi)) {
+			/*
+			 * In normal case, there still is some processing left
+			 * for current transfer. Let's wait for the next
+			 * interrupt then.
+			 */
+			return IRQ_HANDLED;
+		}
+	}
+
+	/*
+	 * Current transfer is finished, either with error or with success. In
+	 * any case we disable interrupts and notify the worker to handle
+	 * any post-processing of the message.
+	 */
+	ep93xx_spi_disable_interrupts(espi);
+	complete(&espi->wait);
+	return IRQ_HANDLED;
+}
+
+static int __init ep93xx_spi_probe(struct platform_device *pdev)
+{
+	struct spi_master *master;
+	struct ep93xx_spi_info *info;
+	struct ep93xx_spi *espi;
+	struct resource *res;
+	int error;
+
+	info = pdev->dev.platform_data;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(*espi));
+	if (!master) {
+		dev_err(&pdev->dev, "failed to allocate spi master\n");
+		return -ENOMEM;
+	}
+
+	master->setup = ep93xx_spi_setup;
+	master->transfer = ep93xx_spi_transfer;
+	master->cleanup = ep93xx_spi_cleanup;
+	master->bus_num = 0;
+	master->num_chipselect = info->num_chipselect;
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
+	platform_set_drvdata(pdev, master);
+
+	espi = spi_master_get_devdata(master);
+	espi->cs_control = info->cs_control;
+
+	espi->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(espi->clk)) {
+		dev_err(&pdev->dev, "unable to get spi clock\n");
+		error = PTR_ERR(espi->clk);
+		goto fail_release_master;
+	}
+
+	spin_lock_init(&espi->lock);
+	init_completion(&espi->wait);
+
+	/*
+	 * Calculate maximum and minimum supported clock rates
+	 * for the controller.
+	 */
+	espi->max_rate = clk_get_rate(espi->clk) / 2;
+	espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
+	espi->pdev = pdev;
+
+	espi->irq = platform_get_irq(pdev, 0);
+	if (espi->irq < 0) {
+		error = -EBUSY;
+		dev_err(&pdev->dev, "failed to get irq resources\n");
+		goto fail_put_clock;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "unable to get iomem resource\n");
+		error = -ENODEV;
+		goto fail_put_clock;
+	}
+
+	res = request_mem_region(res->start, resource_size(res), pdev->name);
+	if (!res) {
+		dev_err(&pdev->dev, "unable to request iomem resources\n");
+		error = -EBUSY;
+		goto fail_put_clock;
+	}
+
+	espi->regs_base = ioremap(res->start, resource_size(res));
+	if (!espi->regs_base) {
+		dev_err(&pdev->dev, "failed to map resources\n");
+		error = -ENODEV;
+		goto fail_free_mem;
+	}
+
+	error = request_irq(espi->irq, ep93xx_spi_interrupt, 0,
+			    "ep93xx-spi", espi);
+	if (error) {
+		dev_err(&pdev->dev, "failed to request irq\n");
+		goto fail_unmap_regs;
+	}
+
+	espi->wq = create_singlethread_workqueue("ep93xx_spid");
+	if (!espi->wq) {
+		dev_err(&pdev->dev, "unable to create workqueue\n");
+		goto fail_free_irq;
+	}
+	INIT_WORK(&espi->msg_work, ep93xx_spi_work);
+	INIT_LIST_HEAD(&espi->msg_queue);
+	espi->running = true;
+
+	/* make sure that the hardware is disabled */
+	ep93xx_spi_write_u8(espi, SSPCR1, 0);
+
+	error =	spi_register_master(master);
+	if (error) {
+		dev_err(&pdev->dev, "failed to register SPI master\n");
+		goto fail_free_queue;
+	}
+
+	dev_info(&pdev->dev, "EP93xx SPI Controller at 0x%08lx irq %d\n",
+		 (unsigned long)res->start, espi->irq);
+
+	return 0;
+
+fail_free_queue:
+	destroy_workqueue(espi->wq);
+fail_free_irq:
+	free_irq(espi->irq, espi);
+fail_unmap_regs:
+	iounmap(espi->regs_base);
+fail_free_mem:
+	release_mem_region(res->start, resource_size(res));
+fail_put_clock:
+	clk_put(espi->clk);
+fail_release_master:
+	spi_master_put(master);
+	platform_set_drvdata(pdev, NULL);
+
+	return error;
+}
+
+static int __exit ep93xx_spi_remove(struct platform_device *pdev)
+{
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct ep93xx_spi *espi = spi_master_get_devdata(master);
+	struct resource *res;
+
+	spin_lock_irq(&espi->lock);
+	espi->running = false;
+	spin_unlock_irq(&espi->lock);
+
+	destroy_workqueue(espi->wq);
+
+	/*
+	 * Complete remaining messages with %-ESHUTDOWN status.
+	 */
+	spin_lock_irq(&espi->lock);
+	while (!list_empty(&espi->msg_queue)) {
+		struct spi_message *msg;
+
+		msg = list_first_entry(&espi->msg_queue,
+				       struct spi_message, queue);
+		list_del_init(&msg->queue);
+		msg->status = -ESHUTDOWN;
+		spin_unlock_irq(&espi->lock);
+		msg->complete(msg->context);
+		spin_lock_irq(&espi->lock);
+	}
+	spin_unlock_irq(&espi->lock);
+
+	free_irq(espi->irq, espi);
+	iounmap(espi->regs_base);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+	clk_put(espi->clk);
+	platform_set_drvdata(pdev, NULL);
+
+	spi_unregister_master(master);
+	return 0;
+}
+
+static struct platform_driver ep93xx_spi_driver = {
+	.driver		= {
+		.name	= "ep93xx-spi",
+		.owner	= THIS_MODULE,
+	},
+	.remove		= __exit_p(ep93xx_spi_remove),
+};
+
+static int __init ep93xx_spi_init(void)
+{
+	return platform_driver_probe(&ep93xx_spi_driver, ep93xx_spi_probe);
+}
+module_init(ep93xx_spi_init);
+
+static void __exit ep93xx_spi_exit(void)
+{
+	platform_driver_unregister(&ep93xx_spi_driver);
+}
+module_exit(ep93xx_spi_exit);
+
+MODULE_DESCRIPTION("EP93xx SPI Controller driver");
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-spi");
-- 
1.5.6.5

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

* [PATCH v4 2/2] ep93xx: SPI driver platform support code
  2010-04-20 15:11 ` Mika Westerberg
@ 2010-04-20 15:11     ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-20 15:11 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

This patch adds platform side support code for EP93xx SPI driver. This includes
clock, resources and muxing. There is a new function: ep93xx_register_spi() that
can be used by board support code to register new SPI devices for the board.

This patch depends on following ARM patch:
	5998/1 ep93xx: added chip revision reading function

Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>
---
 arch/arm/mach-ep93xx/clock.c                    |   14 +++++++
 arch/arm/mach-ep93xx/core.c                     |   48 +++++++++++++++++++++++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    2 +
 4 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 5f80092..5986fae 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -96,6 +96,10 @@ static struct clk clk_keypad = {
 	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
 	.set_rate	= set_keytchclk_rate,
 };
+static struct clk clk_spi = {
+	.parent		= &clk_xtali,
+	.rate		= EP93XX_EXT_CLK_RATE,
+};
 static struct clk clk_pwm = {
 	.parent		= &clk_xtali,
 	.rate		= EP93XX_EXT_CLK_RATE,
@@ -186,6 +190,7 @@ static struct clk_lookup clocks[] = {
 	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
 	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
 	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
+	INIT_CK("ep93xx-spi",		NULL,		&clk_spi),
 	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
 	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
 	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
@@ -473,6 +478,14 @@ static int __init ep93xx_clock_init(void)
 	/* Initialize the pll2 derived clocks */
 	clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
 
+	/*
+	 * EP93xx SSP clock rate was doubled in version E2. For more information
+	 * see:
+	 *     http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
+	 */
+	if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
+		clk_spi.rate /= 2;
+
 	pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
 		clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
 	pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
@@ -480,6 +493,7 @@ static int __init ep93xx_clock_init(void)
 		clk_p.rate / 1000000);
 
 	clkdev_add_table(clocks, ARRAY_SIZE(clocks));
+
 	return 0;
 }
 arch_initcall(ep93xx_clock_init);
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 90fb591..e237309 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -35,6 +35,7 @@
 #include <mach/hardware.h>
 #include <mach/fb.h>
 #include <mach/ep93xx_keypad.h>
+#include <mach/ep93xx_spi.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
@@ -363,6 +364,53 @@ void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr)
 	platform_device_register(&ep93xx_eth_device);
 }
 
+static struct ep93xx_spi_info ep93xx_spi_master_data;
+
+static struct resource ep93xx_spi_resources[] = {
+	{
+		.start	= EP93XX_SPI_PHYS_BASE,
+		.end	= EP93XX_SPI_PHYS_BASE + 0x18 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_EP93XX_SSP,
+		.end	= IRQ_EP93XX_SSP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ep93xx_spi_device = {
+	.name		= "ep93xx-spi",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &ep93xx_spi_master_data,
+	},
+	.num_resources	= ARRAY_SIZE(ep93xx_spi_resources),
+	.resource	= ep93xx_spi_resources,
+};
+
+/**
+ * ep93xx_register_spi() - registers spi platform device
+ * @info: ep93xx board specific spi master info (__initdata)
+ *
+ * This function registers platform device for the EP93xx SPI controller and
+ * also makes sure that SPI pins are muxed so that I2S is not using those
+ * pins. Caller should allocate necessary GPIO lines and register any SPI
+ * devices before calling this (see also spi_register_board_info()).
+ *
+ * Returns %0 in success and negative value in case of failure.
+ */
+int __init ep93xx_register_spi(struct ep93xx_spi_info *info)
+{
+	/*
+	 * When SPI is used, we need to make sure that I2S is muxed off from
+	 * SPI pins.
+	 */
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP);
+
+	ep93xx_spi_master_data = *info;
+	return platform_device_register(&ep93xx_spi_device);
+}
 
 /*************************************************************************
  * EP93xx i2c peripheral handling
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index 93e2ecc..b1e096f 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -106,6 +106,7 @@
 
 #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
 
+#define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
 #define EP93XX_SPI_BASE			EP93XX_APB_IOMEM(0x000a0000)
 
 #define EP93XX_IRDA_BASE		EP93XX_APB_IOMEM(0x000b0000)
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index c6dc14d..5816581 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -9,6 +9,7 @@ struct i2c_board_info;
 struct platform_device;
 struct ep93xxfb_mach_info;
 struct ep93xx_keypad_platform_data;
+struct ep93xx_spi_info;
 
 struct ep93xx_eth_data
 {
@@ -34,6 +35,7 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
 }
 
 void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
+int ep93xx_register_spi(struct ep93xx_spi_info *info);
 void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
 			 struct i2c_board_info *devices, int num);
 void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
-- 
1.5.6.5


------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev

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

* [PATCH v4 2/2] ep93xx: SPI driver platform support code
@ 2010-04-20 15:11     ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-20 15:11 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds platform side support code for EP93xx SPI driver. This includes
clock, resources and muxing. There is a new function: ep93xx_register_spi() that
can be used by board support code to register new SPI devices for the board.

This patch depends on following ARM patch:
	5998/1 ep93xx: added chip revision reading function

Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
---
 arch/arm/mach-ep93xx/clock.c                    |   14 +++++++
 arch/arm/mach-ep93xx/core.c                     |   48 +++++++++++++++++++++++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    2 +
 4 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 5f80092..5986fae 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -96,6 +96,10 @@ static struct clk clk_keypad = {
 	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
 	.set_rate	= set_keytchclk_rate,
 };
+static struct clk clk_spi = {
+	.parent		= &clk_xtali,
+	.rate		= EP93XX_EXT_CLK_RATE,
+};
 static struct clk clk_pwm = {
 	.parent		= &clk_xtali,
 	.rate		= EP93XX_EXT_CLK_RATE,
@@ -186,6 +190,7 @@ static struct clk_lookup clocks[] = {
 	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
 	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
 	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
+	INIT_CK("ep93xx-spi",		NULL,		&clk_spi),
 	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
 	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
 	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
@@ -473,6 +478,14 @@ static int __init ep93xx_clock_init(void)
 	/* Initialize the pll2 derived clocks */
 	clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
 
+	/*
+	 * EP93xx SSP clock rate was doubled in version E2. For more information
+	 * see:
+	 *     http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
+	 */
+	if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
+		clk_spi.rate /= 2;
+
 	pr_info("PLL1 running at %ld MHz, PLL2@%ld MHz\n",
 		clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
 	pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
@@ -480,6 +493,7 @@ static int __init ep93xx_clock_init(void)
 		clk_p.rate / 1000000);
 
 	clkdev_add_table(clocks, ARRAY_SIZE(clocks));
+
 	return 0;
 }
 arch_initcall(ep93xx_clock_init);
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 90fb591..e237309 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -35,6 +35,7 @@
 #include <mach/hardware.h>
 #include <mach/fb.h>
 #include <mach/ep93xx_keypad.h>
+#include <mach/ep93xx_spi.h>
 
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
@@ -363,6 +364,53 @@ void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr)
 	platform_device_register(&ep93xx_eth_device);
 }
 
+static struct ep93xx_spi_info ep93xx_spi_master_data;
+
+static struct resource ep93xx_spi_resources[] = {
+	{
+		.start	= EP93XX_SPI_PHYS_BASE,
+		.end	= EP93XX_SPI_PHYS_BASE + 0x18 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_EP93XX_SSP,
+		.end	= IRQ_EP93XX_SSP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ep93xx_spi_device = {
+	.name		= "ep93xx-spi",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &ep93xx_spi_master_data,
+	},
+	.num_resources	= ARRAY_SIZE(ep93xx_spi_resources),
+	.resource	= ep93xx_spi_resources,
+};
+
+/**
+ * ep93xx_register_spi() - registers spi platform device
+ * @info: ep93xx board specific spi master info (__initdata)
+ *
+ * This function registers platform device for the EP93xx SPI controller and
+ * also makes sure that SPI pins are muxed so that I2S is not using those
+ * pins. Caller should allocate necessary GPIO lines and register any SPI
+ * devices before calling this (see also spi_register_board_info()).
+ *
+ * Returns %0 in success and negative value in case of failure.
+ */
+int __init ep93xx_register_spi(struct ep93xx_spi_info *info)
+{
+	/*
+	 * When SPI is used, we need to make sure that I2S is muxed off from
+	 * SPI pins.
+	 */
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP);
+
+	ep93xx_spi_master_data = *info;
+	return platform_device_register(&ep93xx_spi_device);
+}
 
 /*************************************************************************
  * EP93xx i2c peripheral handling
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index 93e2ecc..b1e096f 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -106,6 +106,7 @@
 
 #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
 
+#define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
 #define EP93XX_SPI_BASE			EP93XX_APB_IOMEM(0x000a0000)
 
 #define EP93XX_IRDA_BASE		EP93XX_APB_IOMEM(0x000b0000)
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index c6dc14d..5816581 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -9,6 +9,7 @@ struct i2c_board_info;
 struct platform_device;
 struct ep93xxfb_mach_info;
 struct ep93xx_keypad_platform_data;
+struct ep93xx_spi_info;
 
 struct ep93xx_eth_data
 {
@@ -34,6 +35,7 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
 }
 
 void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
+int ep93xx_register_spi(struct ep93xx_spi_info *info);
 void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
 			 struct i2c_board_info *devices, int num);
 void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
-- 
1.5.6.5

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

* Re: [PATCH v4 2/2] ep93xx: SPI driver platform support code
  2010-04-20 15:11     ` Mika Westerberg
@ 2010-04-20 16:35         ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-20 16:35 UTC (permalink / raw)
  To: Mika Westerberg, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
>
> This patch adds platform side support code for EP93xx SPI driver. This includes
> clock, resources and muxing. There is a new function: ep93xx_register_spi() that
> can be used by board support code to register new SPI devices for the board.
>
> This patch depends on following ARM patch:
> 	5998/1 ep93xx: added chip revision reading function
>
> Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>

Mika,

This is looking really good.  A couple comments below.

> ---
>  arch/arm/mach-ep93xx/clock.c                    |   14 +++++++
>  arch/arm/mach-ep93xx/core.c                     |   48 +++++++++++++++++++++++
>  arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
>  arch/arm/mach-ep93xx/include/mach/platform.h    |    2 +
>  4 files changed, 65 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
> index 5f80092..5986fae 100644
> --- a/arch/arm/mach-ep93xx/clock.c
> +++ b/arch/arm/mach-ep93xx/clock.c
> @@ -96,6 +96,10 @@ static struct clk clk_keypad = {
>  	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
>  	.set_rate	= set_keytchclk_rate,
>  };
> +static struct clk clk_spi = {
> +	.parent		= &clk_xtali,
> +	.rate		= EP93XX_EXT_CLK_RATE,

Good.

> +};
>  static struct clk clk_pwm = {
>  	.parent		= &clk_xtali,
>  	.rate		= EP93XX_EXT_CLK_RATE,
> @@ -186,6 +190,7 @@ static struct clk_lookup clocks[] = {
>  	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
>  	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
>  	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
> +	INIT_CK("ep93xx-spi",		NULL,		&clk_spi),

Comment on this farther below...

>  	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
>  	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
>  	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
> @@ -473,6 +478,14 @@ static int __init ep93xx_clock_init(void)
>  	/* Initialize the pll2 derived clocks */
>  	clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
>  
> +	/*
> +	 * EP93xx SSP clock rate was doubled in version E2. For more information
> +	 * see:
> +	 *     http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
> +	 */
> +	if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
> +		clk_spi.rate /= 2;

Good.

> +
>  	pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
>  		clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
>  	pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
> @@ -480,6 +493,7 @@ static int __init ep93xx_clock_init(void)
>  		clk_p.rate / 1000000);
>  
>  	clkdev_add_table(clocks, ARRAY_SIZE(clocks));
> +
>  	return 0;
>  }
>  arch_initcall(ep93xx_clock_init);
> diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
> index 90fb591..e237309 100644
> --- a/arch/arm/mach-ep93xx/core.c
> +++ b/arch/arm/mach-ep93xx/core.c
> @@ -35,6 +35,7 @@
>  #include <mach/hardware.h>
>  #include <mach/fb.h>
>  #include <mach/ep93xx_keypad.h>
> +#include <mach/ep93xx_spi.h>
>  
>  #include <asm/mach/map.h>
>  #include <asm/mach/time.h>
> @@ -363,6 +364,53 @@ void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr)
>  	platform_device_register(&ep93xx_eth_device);
>  }
>  
> +static struct ep93xx_spi_info ep93xx_spi_master_data;
> +
> +static struct resource ep93xx_spi_resources[] = {
> +	{
> +		.start	= EP93XX_SPI_PHYS_BASE,
> +		.end	= EP93XX_SPI_PHYS_BASE + 0x18 - 1,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_EP93XX_SSP,
> +		.end	= IRQ_EP93XX_SSP,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct platform_device ep93xx_spi_device = {
> +	.name		= "ep93xx-spi",
> +	.id		= -1,

This field is normally copied to the 'master->bus_num' field in the spi driver.  In
the API a -1 bus_num indicates a dynamically assigned bus ID.  It would probably be
cleaner to set the id here to 0 and change the line in the driver from:

+	master->bus_num = 0;

To

+	master->bus_num = pdev->id;

This will change the dev_id for the spi clock to 'ep93xx-spi.0' so the INIT_CK above
will need to be changed also.

> +	.dev		= {
> +		.platform_data = &ep93xx_spi_master_data,
> +	},
> +	.num_resources	= ARRAY_SIZE(ep93xx_spi_resources),
> +	.resource	= ep93xx_spi_resources,
> +};
> +
> +/**
> + * ep93xx_register_spi() - registers spi platform device
> + * @info: ep93xx board specific spi master info (__initdata)
> + *
> + * This function registers platform device for the EP93xx SPI controller and
> + * also makes sure that SPI pins are muxed so that I2S is not using those
> + * pins. Caller should allocate necessary GPIO lines and register any SPI
> + * devices before calling this (see also spi_register_board_info()).

It will be a bit cleaner to just pass the spi_board_info to this function and
do the spi_register_board_info here.  Look at the ep93xx_register_i2c function.

> + *
> + * Returns %0 in success and negative value in case of failure.
> + */
> +int __init ep93xx_register_spi(struct ep93xx_spi_info *info)

I'm not sure if the return value is necessary since this is all during init.
None of the other registration routines bother checking the platform_device_register
return value.  You can probably just drop it here and make this a 'void'

> +{
> +	/*
> +	 * When SPI is used, we need to make sure that I2S is muxed off from
> +	 * SPI pins.
> +	 */
> +	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP);
> +
> +	ep93xx_spi_master_data = *info;
> +	return platform_device_register(&ep93xx_spi_device);
> +}
>  
>  /*************************************************************************
>   * EP93xx i2c peripheral handling
> diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> index 93e2ecc..b1e096f 100644
> --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> @@ -106,6 +106,7 @@
>  
>  #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
>  
> +#define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
>  #define EP93XX_SPI_BASE			EP93XX_APB_IOMEM(0x000a0000)
>  
>  #define EP93XX_IRDA_BASE		EP93XX_APB_IOMEM(0x000b0000)
> diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
> index c6dc14d..5816581 100644
> --- a/arch/arm/mach-ep93xx/include/mach/platform.h
> +++ b/arch/arm/mach-ep93xx/include/mach/platform.h
> @@ -9,6 +9,7 @@ struct i2c_board_info;
>  struct platform_device;
>  struct ep93xxfb_mach_info;
>  struct ep93xx_keypad_platform_data;
> +struct ep93xx_spi_info;
>  
>  struct ep93xx_eth_data
>  {
> @@ -34,6 +35,7 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
>  }
>  
>  void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
> +int ep93xx_register_spi(struct ep93xx_spi_info *info);
>  void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
>  			 struct i2c_board_info *devices, int num);
>  void ep93xx_register_fb(struct ep93xxfb_mach_info *data);

------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev

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

* [PATCH v4 2/2] ep93xx: SPI driver platform support code
@ 2010-04-20 16:35         ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-20 16:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
>
> This patch adds platform side support code for EP93xx SPI driver. This includes
> clock, resources and muxing. There is a new function: ep93xx_register_spi() that
> can be used by board support code to register new SPI devices for the board.
>
> This patch depends on following ARM patch:
> 	5998/1 ep93xx: added chip revision reading function
>
> Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>

Mika,

This is looking really good.  A couple comments below.

> ---
>  arch/arm/mach-ep93xx/clock.c                    |   14 +++++++
>  arch/arm/mach-ep93xx/core.c                     |   48 +++++++++++++++++++++++
>  arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    1 +
>  arch/arm/mach-ep93xx/include/mach/platform.h    |    2 +
>  4 files changed, 65 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
> index 5f80092..5986fae 100644
> --- a/arch/arm/mach-ep93xx/clock.c
> +++ b/arch/arm/mach-ep93xx/clock.c
> @@ -96,6 +96,10 @@ static struct clk clk_keypad = {
>  	.enable_mask	= EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
>  	.set_rate	= set_keytchclk_rate,
>  };
> +static struct clk clk_spi = {
> +	.parent		= &clk_xtali,
> +	.rate		= EP93XX_EXT_CLK_RATE,

Good.

> +};
>  static struct clk clk_pwm = {
>  	.parent		= &clk_xtali,
>  	.rate		= EP93XX_EXT_CLK_RATE,
> @@ -186,6 +190,7 @@ static struct clk_lookup clocks[] = {
>  	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
>  	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
>  	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
> +	INIT_CK("ep93xx-spi",		NULL,		&clk_spi),

Comment on this farther below...

>  	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
>  	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
>  	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
> @@ -473,6 +478,14 @@ static int __init ep93xx_clock_init(void)
>  	/* Initialize the pll2 derived clocks */
>  	clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
>  
> +	/*
> +	 * EP93xx SSP clock rate was doubled in version E2. For more information
> +	 * see:
> +	 *     http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
> +	 */
> +	if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
> +		clk_spi.rate /= 2;

Good.

> +
>  	pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
>  		clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
>  	pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
> @@ -480,6 +493,7 @@ static int __init ep93xx_clock_init(void)
>  		clk_p.rate / 1000000);
>  
>  	clkdev_add_table(clocks, ARRAY_SIZE(clocks));
> +
>  	return 0;
>  }
>  arch_initcall(ep93xx_clock_init);
> diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
> index 90fb591..e237309 100644
> --- a/arch/arm/mach-ep93xx/core.c
> +++ b/arch/arm/mach-ep93xx/core.c
> @@ -35,6 +35,7 @@
>  #include <mach/hardware.h>
>  #include <mach/fb.h>
>  #include <mach/ep93xx_keypad.h>
> +#include <mach/ep93xx_spi.h>
>  
>  #include <asm/mach/map.h>
>  #include <asm/mach/time.h>
> @@ -363,6 +364,53 @@ void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr)
>  	platform_device_register(&ep93xx_eth_device);
>  }
>  
> +static struct ep93xx_spi_info ep93xx_spi_master_data;
> +
> +static struct resource ep93xx_spi_resources[] = {
> +	{
> +		.start	= EP93XX_SPI_PHYS_BASE,
> +		.end	= EP93XX_SPI_PHYS_BASE + 0x18 - 1,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +	{
> +		.start	= IRQ_EP93XX_SSP,
> +		.end	= IRQ_EP93XX_SSP,
> +		.flags	= IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct platform_device ep93xx_spi_device = {
> +	.name		= "ep93xx-spi",
> +	.id		= -1,

This field is normally copied to the 'master->bus_num' field in the spi driver.  In
the API a -1 bus_num indicates a dynamically assigned bus ID.  It would probably be
cleaner to set the id here to 0 and change the line in the driver from:

+	master->bus_num = 0;

To

+	master->bus_num = pdev->id;

This will change the dev_id for the spi clock to 'ep93xx-spi.0' so the INIT_CK above
will need to be changed also.

> +	.dev		= {
> +		.platform_data = &ep93xx_spi_master_data,
> +	},
> +	.num_resources	= ARRAY_SIZE(ep93xx_spi_resources),
> +	.resource	= ep93xx_spi_resources,
> +};
> +
> +/**
> + * ep93xx_register_spi() - registers spi platform device
> + * @info: ep93xx board specific spi master info (__initdata)
> + *
> + * This function registers platform device for the EP93xx SPI controller and
> + * also makes sure that SPI pins are muxed so that I2S is not using those
> + * pins. Caller should allocate necessary GPIO lines and register any SPI
> + * devices before calling this (see also spi_register_board_info()).

It will be a bit cleaner to just pass the spi_board_info to this function and
do the spi_register_board_info here.  Look at the ep93xx_register_i2c function.

> + *
> + * Returns %0 in success and negative value in case of failure.
> + */
> +int __init ep93xx_register_spi(struct ep93xx_spi_info *info)

I'm not sure if the return value is necessary since this is all during init.
None of the other registration routines bother checking the platform_device_register
return value.  You can probably just drop it here and make this a 'void'

> +{
> +	/*
> +	 * When SPI is used, we need to make sure that I2S is muxed off from
> +	 * SPI pins.
> +	 */
> +	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP);
> +
> +	ep93xx_spi_master_data = *info;
> +	return platform_device_register(&ep93xx_spi_device);
> +}
>  
>  /*************************************************************************
>   * EP93xx i2c peripheral handling
> diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> index 93e2ecc..b1e096f 100644
> --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> @@ -106,6 +106,7 @@
>  
>  #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
>  
> +#define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)
>  #define EP93XX_SPI_BASE			EP93XX_APB_IOMEM(0x000a0000)
>  
>  #define EP93XX_IRDA_BASE		EP93XX_APB_IOMEM(0x000b0000)
> diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
> index c6dc14d..5816581 100644
> --- a/arch/arm/mach-ep93xx/include/mach/platform.h
> +++ b/arch/arm/mach-ep93xx/include/mach/platform.h
> @@ -9,6 +9,7 @@ struct i2c_board_info;
>  struct platform_device;
>  struct ep93xxfb_mach_info;
>  struct ep93xx_keypad_platform_data;
> +struct ep93xx_spi_info;
>  
>  struct ep93xx_eth_data
>  {
> @@ -34,6 +35,7 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
>  }
>  
>  void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
> +int ep93xx_register_spi(struct ep93xx_spi_info *info);
>  void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
>  			 struct i2c_board_info *devices, int num);
>  void ep93xx_register_fb(struct ep93xxfb_mach_info *data);

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-20 15:11     ` Mika Westerberg
@ 2010-04-20 17:24         ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-20 17:24 UTC (permalink / raw)
  To: Mika Westerberg, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
> 
> Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>

Mika,

I'm still looking this over but I have one quick comment.

> +/**
> + * ep93xx_spi_select_device() - select given SPI device
> + * @espi: ep93xx SPI controller struct
> + * @spi: SPI device to select
> + *
> + * Function asserts chipselect line as specified in @spi->chip_select in board
> + * specific manner.
> + *
> + * Note that this function is called from a thread context and can sleep.
> + */
> +static inline void ep93xx_spi_select_device(const struct ep93xx_spi *espi,
> +					    struct spi_device *spi)
> +{
> +	if (espi->cs_control)
> +		espi->cs_control(spi, !!(spi->mode & SPI_CS_HIGH));
> +}
> +
> +/**
> + * ep93xx_spi_deselect_device() - deselects given SPI device
> + * @espi: ep93xx SPI controller struct
> + * @spi: SPI device to deselect
> + *
> + * Function deasserts chipselect line as specified in @spi->chip_select in board
> + * specific manner.
> + *
> + * Note that this function is called from a thread context and can sleep.
> + */
> +static inline void ep93xx_spi_deselect_device(const struct ep93xx_spi *espi,
> +					      struct spi_device *spi)
> +{
> +	if (espi->cs_control)
> +		espi->cs_control(spi, !(spi->mode & SPI_CS_HIGH));
> +}

These two functions can be combined.

/**
 * ep93xx_spi_chip_select() - select/deselect a given SPI device
 * @espi: ep93xx SPI controller struct
 * @spi: SPI device to select
 * @assert: flag to assert the chip select line
 *
 * Note that this function is called from a thread context and can sleep.
 */
static void ep93xx_spi_chip_select(const struct ep93xx_spi *espi,
					     struct spi_device *spi, int assert)
{
	int value = (spi->mode & SPI_CS_HIGH) ? !!assert : !assert;

	if (espi->cs_control)
		espi->cs_control(spi, value);
}

Then just do:

ep93xx_spi_select_device(espi, msg->spi, 1);	/* assert the spi chip select */

ep93xx_spi_select_device(espi, msg->spi, 0);	/* deassert the spi chip select */

Regards,
Hartley
------------------------------------------------------------------------------
Download Intel&#174; Parallel Studio Eval
Try the new software tools for yourself. Speed compiling, find bugs
proactively, and fine-tune applications for parallel performance.
See why Intel Parallel Studio got high marks during beta.
http://p.sf.net/sfu/intel-sw-dev

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-20 17:24         ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-20 17:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
> 
> Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>

Mika,

I'm still looking this over but I have one quick comment.

> +/**
> + * ep93xx_spi_select_device() - select given SPI device
> + * @espi: ep93xx SPI controller struct
> + * @spi: SPI device to select
> + *
> + * Function asserts chipselect line as specified in @spi->chip_select in board
> + * specific manner.
> + *
> + * Note that this function is called from a thread context and can sleep.
> + */
> +static inline void ep93xx_spi_select_device(const struct ep93xx_spi *espi,
> +					    struct spi_device *spi)
> +{
> +	if (espi->cs_control)
> +		espi->cs_control(spi, !!(spi->mode & SPI_CS_HIGH));
> +}
> +
> +/**
> + * ep93xx_spi_deselect_device() - deselects given SPI device
> + * @espi: ep93xx SPI controller struct
> + * @spi: SPI device to deselect
> + *
> + * Function deasserts chipselect line as specified in @spi->chip_select in board
> + * specific manner.
> + *
> + * Note that this function is called from a thread context and can sleep.
> + */
> +static inline void ep93xx_spi_deselect_device(const struct ep93xx_spi *espi,
> +					      struct spi_device *spi)
> +{
> +	if (espi->cs_control)
> +		espi->cs_control(spi, !(spi->mode & SPI_CS_HIGH));
> +}

These two functions can be combined.

/**
 * ep93xx_spi_chip_select() - select/deselect a given SPI device
 * @espi: ep93xx SPI controller struct
 * @spi: SPI device to select
 * @assert: flag to assert the chip select line
 *
 * Note that this function is called from a thread context and can sleep.
 */
static void ep93xx_spi_chip_select(const struct ep93xx_spi *espi,
					     struct spi_device *spi, int assert)
{
	int value = (spi->mode & SPI_CS_HIGH) ? !!assert : !assert;

	if (espi->cs_control)
		espi->cs_control(spi, value);
}

Then just do:

ep93xx_spi_select_device(espi, msg->spi, 1);	/* assert the spi chip select */

ep93xx_spi_select_device(espi, msg->spi, 0);	/* deassert the spi chip select */

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-20 15:11     ` Mika Westerberg
@ 2010-04-20 22:16         ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-20 22:16 UTC (permalink / raw)
  To: Mika Westerberg, spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
>
> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
> 
> Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>

Mika,

I discovered one gotcha with this driver.  Bear with me through this...

1. ep93xx_spi_process_message is called by the workqueue worker function to handle
   a spi_message queued in by the ep93xx_spi_transfer function.  Before starting
   the actual transfer the chip select to the device is asserted.
2. ep93xx_spi_process_transfer processes each transfer in the spi_message, one at a
   time, and does a wait_for_completion on each transfer.
3. When the entire spi_message has been transferred the chip select to the device
   is deasserted.

The problem is if a hardware design uses the SFRM1 pin as part of the chip select
logic.  The EP93xx User's Guide states that "the SFRMOUT signal behaves as a slave
Select" in Motorola SPI mode.  This signal behaves differently depending on the
SPI_MODE_* used.

Modes 0 and 2:
  SFRMOUT is forced HIGH during idle periods.
  Start of transmission, SFRMOUT is driven LOW.
  Single word transmission, SFRMOUT is returned to its idle HIGH state one
    SCLKOUT period after the last bit has been captured.
  Back-to-back transmissions, SFRMOUT signal is pulsed HIGH between each
    data word transfer.  On completion the SFRMOUT pin returns to its idle
    HIGH state one SCLKOUT period after the last bit has been captured.

Modes 1 and 3:
  SFRMOUT is forced HIGH during idle periods.
  Start of transmission, SFRMOUT is driven LOW.
  Single word transmission, SFRMOUT is returned to its idle HIGH state one
    SCLKOUT period after the last bit has been captured.
  Back-to-back transmissions, SFRMOUT signal is held LOW between each
    data word transfer.  On completion the SFRMOUT pin returns to its idle
    HIGH state one SCLKOUT period after the last bit has been captured.

So, since each transfer does a wait_for_completion, all the data is transmitted
which causes the SFRMOUT pin to go HIGH between each transfer in the message.

For devices like the sst25lf040a SPI Flash on the EDB93xx boards this causes a
problem.  To read data from that device you need to send a two part message.  The
first part is a write transfer with the one byte command and three byte address.
This is then followed by a read transfer to get the data.  But since the SFRMOUT
pin goes high this ends the command.

The driver Ryan and I worked on actually does work with the sst25lf040a on the
EDB93xx boards.  But now that I know what the issue is, it was actually a race
condition.  Sometimes it worked and sometimes it didn't...

I would think the Sim.One board (Martin?) would have the same issue with the mmc
card since that design uses the SFRMOUT pin directly for the chip select.

Is there anyway to keep the transfers going in a muiltipart message?

Regards,
Hartley
------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-20 22:16         ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-20 22:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
>
> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
> 
> Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>

Mika,

I discovered one gotcha with this driver.  Bear with me through this...

1. ep93xx_spi_process_message is called by the workqueue worker function to handle
   a spi_message queued in by the ep93xx_spi_transfer function.  Before starting
   the actual transfer the chip select to the device is asserted.
2. ep93xx_spi_process_transfer processes each transfer in the spi_message, one at a
   time, and does a wait_for_completion on each transfer.
3. When the entire spi_message has been transferred the chip select to the device
   is deasserted.

The problem is if a hardware design uses the SFRM1 pin as part of the chip select
logic.  The EP93xx User's Guide states that "the SFRMOUT signal behaves as a slave
Select" in Motorola SPI mode.  This signal behaves differently depending on the
SPI_MODE_* used.

Modes 0 and 2:
  SFRMOUT is forced HIGH during idle periods.
  Start of transmission, SFRMOUT is driven LOW.
  Single word transmission, SFRMOUT is returned to its idle HIGH state one
    SCLKOUT period after the last bit has been captured.
  Back-to-back transmissions, SFRMOUT signal is pulsed HIGH between each
    data word transfer.  On completion the SFRMOUT pin returns to its idle
    HIGH state one SCLKOUT period after the last bit has been captured.

Modes 1 and 3:
  SFRMOUT is forced HIGH during idle periods.
  Start of transmission, SFRMOUT is driven LOW.
  Single word transmission, SFRMOUT is returned to its idle HIGH state one
    SCLKOUT period after the last bit has been captured.
  Back-to-back transmissions, SFRMOUT signal is held LOW between each
    data word transfer.  On completion the SFRMOUT pin returns to its idle
    HIGH state one SCLKOUT period after the last bit has been captured.

So, since each transfer does a wait_for_completion, all the data is transmitted
which causes the SFRMOUT pin to go HIGH between each transfer in the message.

For devices like the sst25lf040a SPI Flash on the EDB93xx boards this causes a
problem.  To read data from that device you need to send a two part message.  The
first part is a write transfer with the one byte command and three byte address.
This is then followed by a read transfer to get the data.  But since the SFRMOUT
pin goes high this ends the command.

The driver Ryan and I worked on actually does work with the sst25lf040a on the
EDB93xx boards.  But now that I know what the issue is, it was actually a race
condition.  Sometimes it worked and sometimes it didn't...

I would think the Sim.One board (Martin?) would have the same issue with the mmc
card since that design uses the SFRMOUT pin directly for the chip select.

Is there anyway to keep the transfers going in a muiltipart message?

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-20 22:16         ` H Hartley Sweeten
@ 2010-04-20 23:54             ` Martin Guy
  -1 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-20 23:54 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 4/20/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
> On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
> > This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
>  > in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
>
>  I discovered one gotcha with this driver.  Bear with me through this...
>
>  1. ep93xx_spi_process_message is called by the workqueue worker function to handle
>    a spi_message queued in by the ep93xx_spi_transfer function.  Before starting
>    the actual transfer the chip select to the device is asserted.
>  2. ep93xx_spi_process_transfer processes each transfer in the spi_message, one at a
>    time, and does a wait_for_completion on each transfer.
>  3. When the entire spi_message has been transferred the chip select to the device
>    is deasserted.
>
>  The problem is if a hardware design uses the SFRM1 pin as part of the chip select
>  logic.  The EP93xx User's Guide states that "the SFRMOUT signal behaves as a slave
>  Select" in Motorola SPI mode.  This signal behaves differently depending on the
>  SPI_MODE_* used.
>
>  Modes 0 and 2:
>   SFRMOUT is forced HIGH during idle periods.
>   Start of transmission, SFRMOUT is driven LOW.
>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>     SCLKOUT period after the last bit has been captured.
>   Back-to-back transmissions, SFRMOUT signal is pulsed HIGH between each
>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>     HIGH state one SCLKOUT period after the last bit has been captured.
>
>  Modes 1 and 3:
>   SFRMOUT is forced HIGH during idle periods.
>   Start of transmission, SFRMOUT is driven LOW.
>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>     SCLKOUT period after the last bit has been captured.
>   Back-to-back transmissions, SFRMOUT signal is held LOW between each
>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>     HIGH state one SCLKOUT period after the last bit has been captured.
>
>  So, since each transfer does a wait_for_completion, all the data is transmitted
>  which causes the SFRMOUT pin to go HIGH between each transfer in the message.
>
>  For devices like the sst25lf040a SPI Flash on the EDB93xx boards this causes a
>  problem.  To read data from that device you need to send a two part message.  The
>  first part is a write transfer with the one byte command and three byte address.
>  This is then followed by a read transfer to get the data.  But since the SFRMOUT
>  pin goes high this ends the command.
>
>  The driver Ryan and I worked on actually does work with the sst25lf040a on the
>  EDB93xx boards.  But now that I know what the issue is, it was actually a race
>  condition.  Sometimes it worked and sometimes it didn't...
>
>  I would think the Sim.One board (Martin?) would have the same issue with the mmc
>  card since that design uses the SFRMOUT pin directly for the chip select.
>
>  Is there anyway to keep the transfers going in a muiltipart message?

I just changed the SPI mode selection, which is in the board
definition file, from Mode 0 to Mode 3 (the two modes that sample data
on the rising clock edge, as required by MMC/SD). It dramatically
increases linear block read throughput:
MMC: from 307kB/sec to 353kB/sec
SD: from 317 to 365
SD MLC: from 327 to 378
with 82000 interrupts per second and 60% cpu usage

presumably because the poor card isn't being deselected once every byte.

   M

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-20 23:54             ` Martin Guy
  0 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-20 23:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 4/20/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
> On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
> > This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
>  > in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
>
>  I discovered one gotcha with this driver.  Bear with me through this...
>
>  1. ep93xx_spi_process_message is called by the workqueue worker function to handle
>    a spi_message queued in by the ep93xx_spi_transfer function.  Before starting
>    the actual transfer the chip select to the device is asserted.
>  2. ep93xx_spi_process_transfer processes each transfer in the spi_message, one at a
>    time, and does a wait_for_completion on each transfer.
>  3. When the entire spi_message has been transferred the chip select to the device
>    is deasserted.
>
>  The problem is if a hardware design uses the SFRM1 pin as part of the chip select
>  logic.  The EP93xx User's Guide states that "the SFRMOUT signal behaves as a slave
>  Select" in Motorola SPI mode.  This signal behaves differently depending on the
>  SPI_MODE_* used.
>
>  Modes 0 and 2:
>   SFRMOUT is forced HIGH during idle periods.
>   Start of transmission, SFRMOUT is driven LOW.
>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>     SCLKOUT period after the last bit has been captured.
>   Back-to-back transmissions, SFRMOUT signal is pulsed HIGH between each
>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>     HIGH state one SCLKOUT period after the last bit has been captured.
>
>  Modes 1 and 3:
>   SFRMOUT is forced HIGH during idle periods.
>   Start of transmission, SFRMOUT is driven LOW.
>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>     SCLKOUT period after the last bit has been captured.
>   Back-to-back transmissions, SFRMOUT signal is held LOW between each
>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>     HIGH state one SCLKOUT period after the last bit has been captured.
>
>  So, since each transfer does a wait_for_completion, all the data is transmitted
>  which causes the SFRMOUT pin to go HIGH between each transfer in the message.
>
>  For devices like the sst25lf040a SPI Flash on the EDB93xx boards this causes a
>  problem.  To read data from that device you need to send a two part message.  The
>  first part is a write transfer with the one byte command and three byte address.
>  This is then followed by a read transfer to get the data.  But since the SFRMOUT
>  pin goes high this ends the command.
>
>  The driver Ryan and I worked on actually does work with the sst25lf040a on the
>  EDB93xx boards.  But now that I know what the issue is, it was actually a race
>  condition.  Sometimes it worked and sometimes it didn't...
>
>  I would think the Sim.One board (Martin?) would have the same issue with the mmc
>  card since that design uses the SFRMOUT pin directly for the chip select.
>
>  Is there anyway to keep the transfers going in a muiltipart message?

I just changed the SPI mode selection, which is in the board
definition file, from Mode 0 to Mode 3 (the two modes that sample data
on the rising clock edge, as required by MMC/SD). It dramatically
increases linear block read throughput:
MMC: from 307kB/sec to 353kB/sec
SD: from 317 to 365
SD MLC: from 327 to 378
with 82000 interrupts per second and 60% cpu usage

presumably because the poor card isn't being deselected once every byte.

   M

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-20 23:54             ` Martin Guy
@ 2010-04-21  0:11                 ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21  0:11 UTC (permalink / raw)
  To: Martin Guy
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tuesday, April 20, 2010 4:55 PM, Martin Guy wrote:
> On 4/20/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
>> On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
>>> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
>>> in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
>>
>> I discovered one gotcha with this driver.  Bear with me through this...
>>
>> 1. ep93xx_spi_process_message is called by the workqueue worker function to handle
>>    a spi_message queued in by the ep93xx_spi_transfer function.  Before starting
>>    the actual transfer the chip select to the device is asserted.
>> 2. ep93xx_spi_process_transfer processes each transfer in the spi_message, one at a
>>    time, and does a wait_for_completion on each transfer.
>> 3. When the entire spi_message has been transferred the chip select to the device
>>    is deasserted.
>>
>> The problem is if a hardware design uses the SFRM1 pin as part of the chip select
>> logic.  The EP93xx User's Guide states that "the SFRMOUT signal behaves as a slave
>> Select" in Motorola SPI mode.  This signal behaves differently depending on the
>> SPI_MODE_* used.
>>
>> Modes 0 and 2:
>>  SFRMOUT is forced HIGH during idle periods.
>>  Start of transmission, SFRMOUT is driven LOW.
>>  Single word transmission, SFRMOUT is returned to its idle HIGH state one
>>    SCLKOUT period after the last bit has been captured.
>>  Back-to-back transmissions, SFRMOUT signal is pulsed HIGH between each
>>    data word transfer.  On completion the SFRMOUT pin returns to its idle
>>    HIGH state one SCLKOUT period after the last bit has been captured.
>>
>> Modes 1 and 3:
>>  SFRMOUT is forced HIGH during idle periods.
>>  Start of transmission, SFRMOUT is driven LOW.
>>  Single word transmission, SFRMOUT is returned to its idle HIGH state one
>>    SCLKOUT period after the last bit has been captured.
>>  Back-to-back transmissions, SFRMOUT signal is held LOW between each
>>    data word transfer.  On completion the SFRMOUT pin returns to its idle
>>    HIGH state one SCLKOUT period after the last bit has been captured.
>>
>> So, since each transfer does a wait_for_completion, all the data is transmitted
>> which causes the SFRMOUT pin to go HIGH between each transfer in the message.
>>
>> For devices like the sst25lf040a SPI Flash on the EDB93xx boards this causes a
>> problem.  To read data from that device you need to send a two part message.  The
>> first part is a write transfer with the one byte command and three byte address.
>> This is then followed by a read transfer to get the data.  But since the SFRMOUT
>> pin goes high this ends the command.
>>
>> The driver Ryan and I worked on actually does work with the sst25lf040a on the
>> EDB93xx boards.  But now that I know what the issue is, it was actually a race
>> condition.  Sometimes it worked and sometimes it didn't...
>>
>> I would think the Sim.One board (Martin?) would have the same issue with the mmc
>> card since that design uses the SFRMOUT pin directly for the chip select.
>>
>> Is there anyway to keep the transfers going in a muiltipart message?
>
> I just changed the SPI mode selection, which is in the board
> definition file, from Mode 0 to Mode 3 (the two modes that sample data
> on the rising clock edge, as required by MMC/SD). It dramatically
> increases linear block read throughput:
> MMC: from 307kB/sec to 353kB/sec
> SD: from 317 to 365
> SD MLC: from 327 to 378
> with 82000 interrupts per second and 60% cpu usage
>
> presumably because the poor card isn't being deselected once every byte.

Yes, Mode 3 should perform better since the protocol is not enforcing the
chip select deassertion between every byte.

You should still be getting a chip select deassertion between every transfer
in a multipart message since the Sim.One uses the SFRM1 line for the chip select.
I haven't actually looked through the mmc_spi driver to see if this happens.

Is there any possibility you could look at the actual bus with a logic analyzer?

My concern with the comments above is that currently this driver will not work
on the EDB93xx boards with the SPI Flash device.  I did hack one of my boards
to remove the SFRM1 signal from the chip select and it does "fix" the problem.
But, that's kind of an ugly solution for most users.

Regards,
Hartley

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21  0:11                 ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21  0:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, April 20, 2010 4:55 PM, Martin Guy wrote:
> On 4/20/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
>> On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
>>> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
>>> in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
>>
>> I discovered one gotcha with this driver.  Bear with me through this...
>>
>> 1. ep93xx_spi_process_message is called by the workqueue worker function to handle
>>    a spi_message queued in by the ep93xx_spi_transfer function.  Before starting
>>    the actual transfer the chip select to the device is asserted.
>> 2. ep93xx_spi_process_transfer processes each transfer in the spi_message, one at a
>>    time, and does a wait_for_completion on each transfer.
>> 3. When the entire spi_message has been transferred the chip select to the device
>>    is deasserted.
>>
>> The problem is if a hardware design uses the SFRM1 pin as part of the chip select
>> logic.  The EP93xx User's Guide states that "the SFRMOUT signal behaves as a slave
>> Select" in Motorola SPI mode.  This signal behaves differently depending on the
>> SPI_MODE_* used.
>>
>> Modes 0 and 2:
>>  SFRMOUT is forced HIGH during idle periods.
>>  Start of transmission, SFRMOUT is driven LOW.
>>  Single word transmission, SFRMOUT is returned to its idle HIGH state one
>>    SCLKOUT period after the last bit has been captured.
>>  Back-to-back transmissions, SFRMOUT signal is pulsed HIGH between each
>>    data word transfer.  On completion the SFRMOUT pin returns to its idle
>>    HIGH state one SCLKOUT period after the last bit has been captured.
>>
>> Modes 1 and 3:
>>  SFRMOUT is forced HIGH during idle periods.
>>  Start of transmission, SFRMOUT is driven LOW.
>>  Single word transmission, SFRMOUT is returned to its idle HIGH state one
>>    SCLKOUT period after the last bit has been captured.
>>  Back-to-back transmissions, SFRMOUT signal is held LOW between each
>>    data word transfer.  On completion the SFRMOUT pin returns to its idle
>>    HIGH state one SCLKOUT period after the last bit has been captured.
>>
>> So, since each transfer does a wait_for_completion, all the data is transmitted
>> which causes the SFRMOUT pin to go HIGH between each transfer in the message.
>>
>> For devices like the sst25lf040a SPI Flash on the EDB93xx boards this causes a
>> problem.  To read data from that device you need to send a two part message.  The
>> first part is a write transfer with the one byte command and three byte address.
>> This is then followed by a read transfer to get the data.  But since the SFRMOUT
>> pin goes high this ends the command.
>>
>> The driver Ryan and I worked on actually does work with the sst25lf040a on the
>> EDB93xx boards.  But now that I know what the issue is, it was actually a race
>> condition.  Sometimes it worked and sometimes it didn't...
>>
>> I would think the Sim.One board (Martin?) would have the same issue with the mmc
>> card since that design uses the SFRMOUT pin directly for the chip select.
>>
>> Is there anyway to keep the transfers going in a muiltipart message?
>
> I just changed the SPI mode selection, which is in the board
> definition file, from Mode 0 to Mode 3 (the two modes that sample data
> on the rising clock edge, as required by MMC/SD). It dramatically
> increases linear block read throughput:
> MMC: from 307kB/sec to 353kB/sec
> SD: from 317 to 365
> SD MLC: from 327 to 378
> with 82000 interrupts per second and 60% cpu usage
>
> presumably because the poor card isn't being deselected once every byte.

Yes, Mode 3 should perform better since the protocol is not enforcing the
chip select deassertion between every byte.

You should still be getting a chip select deassertion between every transfer
in a multipart message since the Sim.One uses the SFRM1 line for the chip select.
I haven't actually looked through the mmc_spi driver to see if this happens.

Is there any possibility you could look at the actual bus with a logic analyzer?

My concern with the comments above is that currently this driver will not work
on the EDB93xx boards with the SPI Flash device.  I did hack one of my boards
to remove the SFRM1 signal from the chip select and it does "fix" the problem.
But, that's kind of an ugly solution for most users.

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21  0:11                 ` H Hartley Sweeten
@ 2010-04-21  0:43                     ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21  0:43 UTC (permalink / raw)
  To: H Hartley Sweeten, Martin Guy
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tuesday, April 20, 2010 5:11 PM, H Hartley Sweeten wrote:
> On Tuesday, April 20, 2010 4:55 PM, Martin Guy wrote:
>> On 4/20/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:

[snip]

>>> Is there anyway to keep the transfers going in a muiltipart message?
>>
>> I just changed the SPI mode selection, which is in the board
>> definition file, from Mode 0 to Mode 3 (the two modes that sample data
>> on the rising clock edge, as required by MMC/SD). It dramatically
>> increases linear block read throughput:
>> MMC: from 307kB/sec to 353kB/sec
>> SD: from 317 to 365
>> SD MLC: from 327 to 378
>> with 82000 interrupts per second and 60% cpu usage
>>
>> presumably because the poor card isn't being deselected once every byte.
>
> Yes, Mode 3 should perform better since the protocol is not enforcing the
> chip select deassertion between every byte.
>
> You should still be getting a chip select deassertion between every transfer
> in a multipart message since the Sim.One uses the SFRM1 line for the chip select.
> I haven't actually looked through the mmc_spi driver to see if this happens.
>
> Is there any possibility you could look at the actual bus with a logic analyzer?
>
> My concern with the comments above is that currently this driver will not work
> on the EDB93xx boards with the SPI Flash device.  I did hack one of my boards
> to remove the SFRM1 signal from the chip select and it does "fix" the problem.
> But, that's kind of an ugly solution for most users.

Just for the record.  Here are the (approximate) logic analyzer timings for the
Read-ID command to the SPI Flash (Mode 3, 20MHz max speed):

     Assertion of GPIO chip select: 0us
Assertion of SFRM1 (start of xfer): +22.5us
       4 byte Read-ID command xfer: +4.5us
    SFRM1 deasserts at end of xfer
Assertion of SFRM1 (start of xfer): +26.45us
      2 byte ManID/DevID read xfer: +2.25us
    SFRM1 deasserts at end of xfer
   Deassertion of GPIO chip select: +10.25us

So the entire 4+2 byte message took 65.95us, of which the actual data was only
6.75us.  The "dead-time" between the two spi transfers was 40.1% of the total
xfer time.

Regards,
Hartley


------------------------------------------------------------------------------

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

* [spi-devel-general] [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21  0:43                     ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21  0:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, April 20, 2010 5:11 PM, H Hartley Sweeten wrote:
> On Tuesday, April 20, 2010 4:55 PM, Martin Guy wrote:
>> On 4/20/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:

[snip]

>>> Is there anyway to keep the transfers going in a muiltipart message?
>>
>> I just changed the SPI mode selection, which is in the board
>> definition file, from Mode 0 to Mode 3 (the two modes that sample data
>> on the rising clock edge, as required by MMC/SD). It dramatically
>> increases linear block read throughput:
>> MMC: from 307kB/sec to 353kB/sec
>> SD: from 317 to 365
>> SD MLC: from 327 to 378
>> with 82000 interrupts per second and 60% cpu usage
>>
>> presumably because the poor card isn't being deselected once every byte.
>
> Yes, Mode 3 should perform better since the protocol is not enforcing the
> chip select deassertion between every byte.
>
> You should still be getting a chip select deassertion between every transfer
> in a multipart message since the Sim.One uses the SFRM1 line for the chip select.
> I haven't actually looked through the mmc_spi driver to see if this happens.
>
> Is there any possibility you could look at the actual bus with a logic analyzer?
>
> My concern with the comments above is that currently this driver will not work
> on the EDB93xx boards with the SPI Flash device.  I did hack one of my boards
> to remove the SFRM1 signal from the chip select and it does "fix" the problem.
> But, that's kind of an ugly solution for most users.

Just for the record.  Here are the (approximate) logic analyzer timings for the
Read-ID command to the SPI Flash (Mode 3, 20MHz max speed):

     Assertion of GPIO chip select: 0us
Assertion of SFRM1 (start of xfer): +22.5us
       4 byte Read-ID command xfer: +4.5us
    SFRM1 deasserts at end of xfer
Assertion of SFRM1 (start of xfer): +26.45us
      2 byte ManID/DevID read xfer: +2.25us
    SFRM1 deasserts at end of xfer
   Deassertion of GPIO chip select: +10.25us

So the entire 4+2 byte message took 65.95us, of which the actual data was only
6.75us.  The "dead-time" between the two spi transfers was 40.1% of the total
xfer time.

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21  0:11                 ` H Hartley Sweeten
@ 2010-04-21  1:10                     ` Martin Guy
  -1 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-21  1:10 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 4/21/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
> On Tuesday, April 20, 2010 4:55 PM, Martin Guy wrote:
>  > On 4/20/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
>  >> So, since each transfer does a wait_for_completion, all the data is transmitted
>  >> which causes the SFRMOUT pin to go HIGH between each transfer in the message.
>  >> ...
>  >> I would think the Sim.One board (Martin?) would have the same issue with the mmc
>  >> card since that design uses the SFRMOUT pin directly for the chip select.
>  >>
>  >> Is there anyway to keep the transfers going in a muiltipart message?
>
>  You should still be getting a chip select deassertion between every transfer
>  in a multipart message since the Sim.One uses the SFRM1 line for the chip select.
>  I haven't actually looked through the mmc_spi driver to see if this happens.

OK, can I see if understand what you're saying, that
ep93xx_spi_process_message() calls ep93xx_spi_process_transfer()
multiple times using:

        list_for_each_entry(t, &msg->transfers, transfer_list) {
                ep93xx_spi_process_transfer(espi, msg, t);
 ...
and process_transfer() waits for each message block to be completely
transmitted and received, so a transaction that consists of several
messages will (or may) cause the device to be deselected between parts
of the same message, which may cause a failure.

I have noticed on card insertion, the last line of:

mmc0: problem reading switch capabilities, performance might suffer.
mmc0: host does not support reading read-only switch. assuming write-enable.
mmc0: new SD card on SPI
mmcblk0: mmc0:0000 SD    952 MiB
 mmcblk0: p1 p2 p4
mmcblk0: retrying using single block read

and the SDHC cards I have don't work at all, spewing tons of:
mmcblk0: error -38 sending status comand
mmcblk0: error -38 sending read/write command, response 0x4, card status 0xff04
end_request: I/O error, dev mmcblk0, sector 7744509

>  Is there any possibility you could look at the actual bus with a logic analyzer?
Not easily, but it seems a likely cause.
To prevent card deselection mid-message I think we would need to
handle multi-transfer messages by making the start of transfers 2..N
continuous with the end of transfers 1..N-1 instead of draining the
reply from each one before starting the next.

Am I on the right track?

    M

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21  1:10                     ` Martin Guy
  0 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-21  1:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 4/21/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
> On Tuesday, April 20, 2010 4:55 PM, Martin Guy wrote:
>  > On 4/20/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
>  >> So, since each transfer does a wait_for_completion, all the data is transmitted
>  >> which causes the SFRMOUT pin to go HIGH between each transfer in the message.
>  >> ...
>  >> I would think the Sim.One board (Martin?) would have the same issue with the mmc
>  >> card since that design uses the SFRMOUT pin directly for the chip select.
>  >>
>  >> Is there anyway to keep the transfers going in a muiltipart message?
>
>  You should still be getting a chip select deassertion between every transfer
>  in a multipart message since the Sim.One uses the SFRM1 line for the chip select.
>  I haven't actually looked through the mmc_spi driver to see if this happens.

OK, can I see if understand what you're saying, that
ep93xx_spi_process_message() calls ep93xx_spi_process_transfer()
multiple times using:

        list_for_each_entry(t, &msg->transfers, transfer_list) {
                ep93xx_spi_process_transfer(espi, msg, t);
 ...
and process_transfer() waits for each message block to be completely
transmitted and received, so a transaction that consists of several
messages will (or may) cause the device to be deselected between parts
of the same message, which may cause a failure.

I have noticed on card insertion, the last line of:

mmc0: problem reading switch capabilities, performance might suffer.
mmc0: host does not support reading read-only switch. assuming write-enable.
mmc0: new SD card on SPI
mmcblk0: mmc0:0000 SD    952 MiB
 mmcblk0: p1 p2 p4
mmcblk0: retrying using single block read

and the SDHC cards I have don't work at all, spewing tons of:
mmcblk0: error -38 sending status comand
mmcblk0: error -38 sending read/write command, response 0x4, card status 0xff04
end_request: I/O error, dev mmcblk0, sector 7744509

>  Is there any possibility you could look at the actual bus with a logic analyzer?
Not easily, but it seems a likely cause.
To prevent card deselection mid-message I think we would need to
handle multi-transfer messages by making the start of transfers 2..N
continuous with the end of transfers 1..N-1 instead of draining the
reply from each one before starting the next.

Am I on the right track?

    M

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21  1:10                     ` Martin Guy
@ 2010-04-21  1:52                         ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21  1:52 UTC (permalink / raw)
  To: Martin Guy
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tuesday, April 20, 2010 6:10 PM, Martin Guy wrote:
> On 4/21/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
>> On Tuesday, April 20, 2010 4:55 PM, Martin Guy wrote:
>>> On 4/20/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
>>>> So, since each transfer does a wait_for_completion, all the data is transmitted
>>>> which causes the SFRMOUT pin to go HIGH between each transfer in the message.
>>>> ...
>>>> I would think the Sim.One board (Martin?) would have the same issue with the mmc
>>>> card since that design uses the SFRMOUT pin directly for the chip select.
>>>>
>>>> Is there anyway to keep the transfers going in a muiltipart message?
>>
>>  You should still be getting a chip select deassertion between every transfer
>>  in a multipart message since the Sim.One uses the SFRM1 line for the chip select.
>>  I haven't actually looked through the mmc_spi driver to see if this happens.
>
> OK, can I see if understand what you're saying, that
> ep93xx_spi_process_message() calls ep93xx_spi_process_transfer()
> multiple times using:
>
>        list_for_each_entry(t, &msg->transfers, transfer_list) {
>                ep93xx_spi_process_transfer(espi, msg, t);
> ...
> and process_transfer() waits for each message block to be completely
> transmitted and received, so a transaction that consists of several
> messages will (or may) cause the device to be deselected between parts
> of the same message, which may cause a failure.

Exactly.

> I have noticed on card insertion, the last line of:
> 
> mmc0: problem reading switch capabilities, performance might suffer.
> mmc0: host does not support reading read-only switch. assuming write-enable.
> mmc0: new SD card on SPI
> mmcblk0: mmc0:0000 SD    952 MiB
>  mmcblk0: p1 p2 p4
> mmcblk0: retrying using single block read

That message might be related to the SFRM1 line being deasserted.

You could try cutting the trace going to pin 1 (CS pin) of the mmc socket and
jumpering it to one of the EGPIO pins on JP15 (the LCD header) or JP16 (the
keypad header).  You will of course need to modify your platform init to use
the new chip select line.

> and the SDHC cards I have don't work at all, spewing tons of:
> mmcblk0: error -38 sending status comand
> mmcblk0: error -38 sending read/write command, response 0x4, card status 0xff04
> end_request: I/O error, dev mmcblk0, sector 7744509

I haven't seen those error messages before.  Of course I don't have any SDHC
cards... ;-)

>>  Is there any possibility you could look at the actual bus with a logic analyzer?
> Not easily, but it seems a likely cause.
> To prevent card deselection mid-message I think we would need to
> handle multi-transfer messages by making the start of transfers 2..N
> continuous with the end of transfers 1..N-1 instead of draining the
> reply from each one before starting the next.
> 
> Am I on the right track?

Yes.  I'm just not sure how to implement this.

Regards,
Hartley
------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21  1:52                         ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21  1:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, April 20, 2010 6:10 PM, Martin Guy wrote:
> On 4/21/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
>> On Tuesday, April 20, 2010 4:55 PM, Martin Guy wrote:
>>> On 4/20/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
>>>> So, since each transfer does a wait_for_completion, all the data is transmitted
>>>> which causes the SFRMOUT pin to go HIGH between each transfer in the message.
>>>> ...
>>>> I would think the Sim.One board (Martin?) would have the same issue with the mmc
>>>> card since that design uses the SFRMOUT pin directly for the chip select.
>>>>
>>>> Is there anyway to keep the transfers going in a muiltipart message?
>>
>>  You should still be getting a chip select deassertion between every transfer
>>  in a multipart message since the Sim.One uses the SFRM1 line for the chip select.
>>  I haven't actually looked through the mmc_spi driver to see if this happens.
>
> OK, can I see if understand what you're saying, that
> ep93xx_spi_process_message() calls ep93xx_spi_process_transfer()
> multiple times using:
>
>        list_for_each_entry(t, &msg->transfers, transfer_list) {
>                ep93xx_spi_process_transfer(espi, msg, t);
> ...
> and process_transfer() waits for each message block to be completely
> transmitted and received, so a transaction that consists of several
> messages will (or may) cause the device to be deselected between parts
> of the same message, which may cause a failure.

Exactly.

> I have noticed on card insertion, the last line of:
> 
> mmc0: problem reading switch capabilities, performance might suffer.
> mmc0: host does not support reading read-only switch. assuming write-enable.
> mmc0: new SD card on SPI
> mmcblk0: mmc0:0000 SD    952 MiB
>  mmcblk0: p1 p2 p4
> mmcblk0: retrying using single block read

That message might be related to the SFRM1 line being deasserted.

You could try cutting the trace going to pin 1 (CS pin) of the mmc socket and
jumpering it to one of the EGPIO pins on JP15 (the LCD header) or JP16 (the
keypad header).  You will of course need to modify your platform init to use
the new chip select line.

> and the SDHC cards I have don't work at all, spewing tons of:
> mmcblk0: error -38 sending status comand
> mmcblk0: error -38 sending read/write command, response 0x4, card status 0xff04
> end_request: I/O error, dev mmcblk0, sector 7744509

I haven't seen those error messages before.  Of course I don't have any SDHC
cards... ;-)

>>  Is there any possibility you could look at the actual bus with a logic analyzer?
> Not easily, but it seems a likely cause.
> To prevent card deselection mid-message I think we would need to
> handle multi-transfer messages by making the start of transfers 2..N
> continuous with the end of transfers 1..N-1 instead of draining the
> reply from each one before starting the next.
> 
> Am I on the right track?

Yes.  I'm just not sure how to implement this.

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-20 22:16         ` H Hartley Sweeten
@ 2010-04-21  6:37           ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-21  6:37 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: grant.likely, spi-devel-general, martinwguy, ryan, linux-arm-kernel

On Tue, Apr 20, 2010 at 05:16:10PM -0500, H Hartley Sweeten wrote:
> On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
> >
> > This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> > in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
> > 
> > Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
> 
> Mika,
> 
> I discovered one gotcha with this driver.  Bear with me through this...
> 
> 1. ep93xx_spi_process_message is called by the workqueue worker function to handle
>    a spi_message queued in by the ep93xx_spi_transfer function.  Before starting
>    the actual transfer the chip select to the device is asserted.
> 2. ep93xx_spi_process_transfer processes each transfer in the spi_message, one at a
>    time, and does a wait_for_completion on each transfer.
> 3. When the entire spi_message has been transferred the chip select to the device
>    is deasserted.

Yes. There is possibility that last transfer ->cs_change is set which can be used
by SPI controller drivers to keep the chip selected in case next message is going
to the same device.

However, I haven't implemented that as it is optional (but trivial to add afterwards).

> The problem is if a hardware design uses the SFRM1 pin as part of the chip select
> logic.  The EP93xx User's Guide states that "the SFRMOUT signal behaves as a slave
> Select" in Motorola SPI mode.  This signal behaves differently depending on the
> SPI_MODE_* used.
> 
> Modes 0 and 2:
>   SFRMOUT is forced HIGH during idle periods.
>   Start of transmission, SFRMOUT is driven LOW.
>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>     SCLKOUT period after the last bit has been captured.
>   Back-to-back transmissions, SFRMOUT signal is pulsed HIGH between each
>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>     HIGH state one SCLKOUT period after the last bit has been captured.
> 
> Modes 1 and 3:
>   SFRMOUT is forced HIGH during idle periods.
>   Start of transmission, SFRMOUT is driven LOW.
>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>     SCLKOUT period after the last bit has been captured.
>   Back-to-back transmissions, SFRMOUT signal is held LOW between each
>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>     HIGH state one SCLKOUT period after the last bit has been captured.
> 
> So, since each transfer does a wait_for_completion, all the data is transmitted
> which causes the SFRMOUT pin to go HIGH between each transfer in the message.

Yes, unfortunately. SFRMOUT cannot be software controlled so it is
not suitable for general purpose chipselect. This was the sole
purpose of using GPIO lines for chipselects.

> For devices like the sst25lf040a SPI Flash on the EDB93xx boards this causes a
> problem.  To read data from that device you need to send a two part message.  The
> first part is a write transfer with the one byte command and three byte address.
> This is then followed by a read transfer to get the data.  But since the SFRMOUT
> pin goes high this ends the command.
> 
> The driver Ryan and I worked on actually does work with the sst25lf040a on the
> EDB93xx boards.  But now that I know what the issue is, it was actually a race
> condition.  Sometimes it worked and sometimes it didn't...
> 
> I would think the Sim.One board (Martin?) would have the same issue with the mmc
> card since that design uses the SFRMOUT pin directly for the chip select.
> 
> Is there anyway to keep the transfers going in a muiltipart message?

I'm not exactly sure but "polling" mode sounds something that could
work around that. It just need to be sure that it transmits
continuously to keep the SFRMOUT asserted.

You could try v3 of the driver with:
	# modprobe ep93xx-spi transfer_method=0

and see if it works there.

An alternative would be that interrupt handler schedules tasklet which then
takes next transfer immediately once current transfer is finished.

Thanks,
MW

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21  6:37           ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-21  6:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 20, 2010 at 05:16:10PM -0500, H Hartley Sweeten wrote:
> On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
> >
> > This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> > in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
> > 
> > Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
> 
> Mika,
> 
> I discovered one gotcha with this driver.  Bear with me through this...
> 
> 1. ep93xx_spi_process_message is called by the workqueue worker function to handle
>    a spi_message queued in by the ep93xx_spi_transfer function.  Before starting
>    the actual transfer the chip select to the device is asserted.
> 2. ep93xx_spi_process_transfer processes each transfer in the spi_message, one at a
>    time, and does a wait_for_completion on each transfer.
> 3. When the entire spi_message has been transferred the chip select to the device
>    is deasserted.

Yes. There is possibility that last transfer ->cs_change is set which can be used
by SPI controller drivers to keep the chip selected in case next message is going
to the same device.

However, I haven't implemented that as it is optional (but trivial to add afterwards).

> The problem is if a hardware design uses the SFRM1 pin as part of the chip select
> logic.  The EP93xx User's Guide states that "the SFRMOUT signal behaves as a slave
> Select" in Motorola SPI mode.  This signal behaves differently depending on the
> SPI_MODE_* used.
> 
> Modes 0 and 2:
>   SFRMOUT is forced HIGH during idle periods.
>   Start of transmission, SFRMOUT is driven LOW.
>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>     SCLKOUT period after the last bit has been captured.
>   Back-to-back transmissions, SFRMOUT signal is pulsed HIGH between each
>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>     HIGH state one SCLKOUT period after the last bit has been captured.
> 
> Modes 1 and 3:
>   SFRMOUT is forced HIGH during idle periods.
>   Start of transmission, SFRMOUT is driven LOW.
>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>     SCLKOUT period after the last bit has been captured.
>   Back-to-back transmissions, SFRMOUT signal is held LOW between each
>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>     HIGH state one SCLKOUT period after the last bit has been captured.
> 
> So, since each transfer does a wait_for_completion, all the data is transmitted
> which causes the SFRMOUT pin to go HIGH between each transfer in the message.

Yes, unfortunately. SFRMOUT cannot be software controlled so it is
not suitable for general purpose chipselect. This was the sole
purpose of using GPIO lines for chipselects.

> For devices like the sst25lf040a SPI Flash on the EDB93xx boards this causes a
> problem.  To read data from that device you need to send a two part message.  The
> first part is a write transfer with the one byte command and three byte address.
> This is then followed by a read transfer to get the data.  But since the SFRMOUT
> pin goes high this ends the command.
> 
> The driver Ryan and I worked on actually does work with the sst25lf040a on the
> EDB93xx boards.  But now that I know what the issue is, it was actually a race
> condition.  Sometimes it worked and sometimes it didn't...
> 
> I would think the Sim.One board (Martin?) would have the same issue with the mmc
> card since that design uses the SFRMOUT pin directly for the chip select.
> 
> Is there anyway to keep the transfers going in a muiltipart message?

I'm not exactly sure but "polling" mode sounds something that could
work around that. It just need to be sure that it transmits
continuously to keep the SFRMOUT asserted.

You could try v3 of the driver with:
	# modprobe ep93xx-spi transfer_method=0

and see if it works there.

An alternative would be that interrupt handler schedules tasklet which then
takes next transfer immediately once current transfer is finished.

Thanks,
MW

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21  1:52                         ` H Hartley Sweeten
@ 2010-04-21  7:00                             ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-21  7:00 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tue, Apr 20, 2010 at 08:52:26PM -0500, H Hartley Sweeten wrote:
> On Tuesday, April 20, 2010 6:10 PM, Martin Guy wrote:
> > I have noticed on card insertion, the last line of:
> > 
> > mmc0: problem reading switch capabilities, performance might suffer.
> > mmc0: host does not support reading read-only switch. assuming write-enable.
> > mmc0: new SD card on SPI
> > mmcblk0: mmc0:0000 SD    952 MiB
> >  mmcblk0: p1 p2 p4
> > mmcblk0: retrying using single block read
> 
> That message might be related to the SFRM1 line being deasserted.

This message comes, depending on the card you are using.

It is easily reproduced with following command:

	# fdisk -l

Problem there seems to be that fdisk (and also part of block layer that reads
partition table) seeks to the end of the disk and reads last block. I remember
reading some mail thread about the matter and it could be that some cards
do read-ahead which causes the response message to return failure (address error
as a response to STOP message which is completely bogus).

You can enable MMC debugging and see if this is the case with your card also.

I actually debugged this further some time ago and after failure if card status
register is read, there is no failure at all (card is in correct state).

> You could try cutting the trace going to pin 1 (CS pin) of the mmc socket and
> jumpering it to one of the EGPIO pins on JP15 (the LCD header) or JP16 (the
> keypad header).  You will of course need to modify your platform init to use
> the new chip select line.
> 
> > and the SDHC cards I have don't work at all, spewing tons of:
> > mmcblk0: error -38 sending status comand
> > mmcblk0: error -38 sending read/write command, response 0x4, card status 0xff04
> > end_request: I/O error, dev mmcblk0, sector 7744509
> 
> I haven't seen those error messages before.  Of course I don't have any SDHC
> cards... ;-)

With my TS-7260 board, SDHC cards work (but it uses GPIO lines).

MW

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21  7:00                             ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-21  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 20, 2010 at 08:52:26PM -0500, H Hartley Sweeten wrote:
> On Tuesday, April 20, 2010 6:10 PM, Martin Guy wrote:
> > I have noticed on card insertion, the last line of:
> > 
> > mmc0: problem reading switch capabilities, performance might suffer.
> > mmc0: host does not support reading read-only switch. assuming write-enable.
> > mmc0: new SD card on SPI
> > mmcblk0: mmc0:0000 SD    952 MiB
> >  mmcblk0: p1 p2 p4
> > mmcblk0: retrying using single block read
> 
> That message might be related to the SFRM1 line being deasserted.

This message comes, depending on the card you are using.

It is easily reproduced with following command:

	# fdisk -l

Problem there seems to be that fdisk (and also part of block layer that reads
partition table) seeks to the end of the disk and reads last block. I remember
reading some mail thread about the matter and it could be that some cards
do read-ahead which causes the response message to return failure (address error
as a response to STOP message which is completely bogus).

You can enable MMC debugging and see if this is the case with your card also.

I actually debugged this further some time ago and after failure if card status
register is read, there is no failure at all (card is in correct state).

> You could try cutting the trace going to pin 1 (CS pin) of the mmc socket and
> jumpering it to one of the EGPIO pins on JP15 (the LCD header) or JP16 (the
> keypad header).  You will of course need to modify your platform init to use
> the new chip select line.
> 
> > and the SDHC cards I have don't work at all, spewing tons of:
> > mmcblk0: error -38 sending status comand
> > mmcblk0: error -38 sending read/write command, response 0x4, card status 0xff04
> > end_request: I/O error, dev mmcblk0, sector 7744509
> 
> I haven't seen those error messages before.  Of course I don't have any SDHC
> cards... ;-)

With my TS-7260 board, SDHC cards work (but it uses GPIO lines).

MW

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-20 17:24         ` H Hartley Sweeten
@ 2010-04-21  7:16             ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-21  7:16 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tue, Apr 20, 2010 at 12:24:26PM -0500, H Hartley Sweeten wrote:
> On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
> > This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> > in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
> > 
> > Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>
> 
> Mika,
> 
> I'm still looking this over but I have one quick comment.
> 
> > +/**
> > + * ep93xx_spi_select_device() - select given SPI device
> > + * @espi: ep93xx SPI controller struct
> > + * @spi: SPI device to select
> > + *
> > + * Function asserts chipselect line as specified in @spi->chip_select in board
> > + * specific manner.
> > + *
> > + * Note that this function is called from a thread context and can sleep.
> > + */
> > +static inline void ep93xx_spi_select_device(const struct ep93xx_spi *espi,
> > +					    struct spi_device *spi)
> > +{
> > +	if (espi->cs_control)
> > +		espi->cs_control(spi, !!(spi->mode & SPI_CS_HIGH));
> > +}
> > +
> > +/**
> > + * ep93xx_spi_deselect_device() - deselects given SPI device
> > + * @espi: ep93xx SPI controller struct
> > + * @spi: SPI device to deselect
> > + *
> > + * Function deasserts chipselect line as specified in @spi->chip_select in board
> > + * specific manner.
> > + *
> > + * Note that this function is called from a thread context and can sleep.
> > + */
> > +static inline void ep93xx_spi_deselect_device(const struct ep93xx_spi *espi,
> > +					      struct spi_device *spi)
> > +{
> > +	if (espi->cs_control)
> > +		espi->cs_control(spi, !(spi->mode & SPI_CS_HIGH));
> > +}
> 
> These two functions can be combined.
> 
> /**
>  * ep93xx_spi_chip_select() - select/deselect a given SPI device
>  * @espi: ep93xx SPI controller struct
>  * @spi: SPI device to select
>  * @assert: flag to assert the chip select line
>  *
>  * Note that this function is called from a thread context and can sleep.
>  */
> static void ep93xx_spi_chip_select(const struct ep93xx_spi *espi,
> 					     struct spi_device *spi, int assert)
> {
> 	int value = (spi->mode & SPI_CS_HIGH) ? !!assert : !assert;
> 
> 	if (espi->cs_control)
> 		espi->cs_control(spi, value);
> }
> 
> Then just do:
> 
> ep93xx_spi_select_device(espi, msg->spi, 1);	/* assert the spi chip select */
> 
> ep93xx_spi_select_device(espi, msg->spi, 0);	/* deassert the spi chip select */


I think it is more readable to do:

	ep93xx_spi_select_device(espi, msg->spi);

and

	ep93xx_spi_deselect_device(espi, msg->spi);

It can be seen from the function names what we are doing.

Thanks,
MW

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21  7:16             ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-21  7:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 20, 2010 at 12:24:26PM -0500, H Hartley Sweeten wrote:
> On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
> > This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
> > in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
> > 
> > Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
> 
> Mika,
> 
> I'm still looking this over but I have one quick comment.
> 
> > +/**
> > + * ep93xx_spi_select_device() - select given SPI device
> > + * @espi: ep93xx SPI controller struct
> > + * @spi: SPI device to select
> > + *
> > + * Function asserts chipselect line as specified in @spi->chip_select in board
> > + * specific manner.
> > + *
> > + * Note that this function is called from a thread context and can sleep.
> > + */
> > +static inline void ep93xx_spi_select_device(const struct ep93xx_spi *espi,
> > +					    struct spi_device *spi)
> > +{
> > +	if (espi->cs_control)
> > +		espi->cs_control(spi, !!(spi->mode & SPI_CS_HIGH));
> > +}
> > +
> > +/**
> > + * ep93xx_spi_deselect_device() - deselects given SPI device
> > + * @espi: ep93xx SPI controller struct
> > + * @spi: SPI device to deselect
> > + *
> > + * Function deasserts chipselect line as specified in @spi->chip_select in board
> > + * specific manner.
> > + *
> > + * Note that this function is called from a thread context and can sleep.
> > + */
> > +static inline void ep93xx_spi_deselect_device(const struct ep93xx_spi *espi,
> > +					      struct spi_device *spi)
> > +{
> > +	if (espi->cs_control)
> > +		espi->cs_control(spi, !(spi->mode & SPI_CS_HIGH));
> > +}
> 
> These two functions can be combined.
> 
> /**
>  * ep93xx_spi_chip_select() - select/deselect a given SPI device
>  * @espi: ep93xx SPI controller struct
>  * @spi: SPI device to select
>  * @assert: flag to assert the chip select line
>  *
>  * Note that this function is called from a thread context and can sleep.
>  */
> static void ep93xx_spi_chip_select(const struct ep93xx_spi *espi,
> 					     struct spi_device *spi, int assert)
> {
> 	int value = (spi->mode & SPI_CS_HIGH) ? !!assert : !assert;
> 
> 	if (espi->cs_control)
> 		espi->cs_control(spi, value);
> }
> 
> Then just do:
> 
> ep93xx_spi_select_device(espi, msg->spi, 1);	/* assert the spi chip select */
> 
> ep93xx_spi_select_device(espi, msg->spi, 0);	/* deassert the spi chip select */


I think it is more readable to do:

	ep93xx_spi_select_device(espi, msg->spi);

and

	ep93xx_spi_deselect_device(espi, msg->spi);

It can be seen from the function names what we are doing.

Thanks,
MW

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21  1:52                         ` H Hartley Sweeten
@ 2010-04-21 10:46                             ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-21 10:46 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tue, Apr 20, 2010 at 08:52:26PM -0500, H Hartley Sweeten wrote:
> On Tuesday, April 20, 2010 6:10 PM, Martin Guy wrote:
> > Not easily, but it seems a likely cause.
> > To prevent card deselection mid-message I think we would need to
> > handle multi-transfer messages by making the start of transfers 2..N
> > continuous with the end of transfers 1..N-1 instead of draining the
> > reply from each one before starting the next.
> > 
> > Am I on the right track?
> 
> Yes.  I'm just not sure how to implement this.

I made a hack that allows transfer handler to continue to the next transfer directly
if there is no special per transfer settings in the message. Could you try that out
and report whether SFRMOUT works better with it?

Note that this is just to make sure that we are on the right track.

Patch is against v4 of the driver.

Thanks,
MW

diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
index 310032d..11dcdd1 100644
--- a/drivers/spi/ep93xx_spi.c
+++ b/drivers/spi/ep93xx_spi.c
@@ -106,6 +106,8 @@ struct ep93xx_spi {
 	unsigned long			min_rate;
 	unsigned long			max_rate;
 	bool				running;
+	bool				can_continue;
+	struct spi_transfer 		*last_transfer;
 	struct workqueue_struct		*wq;
 	struct work_struct		msg_work;
 	struct completion		wait;
@@ -380,6 +382,7 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 	struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
 	struct spi_transfer *t;
 	unsigned long flags;
+	bool can_continue = true;
 
 	if (!msg || !msg->complete)
 		return -EINVAL;
@@ -387,11 +390,21 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 	/* first validate each transfer */
 	list_for_each_entry(t, &msg->transfers, transfer_list) {
 		if (t->bits_per_word) {
+			can_continue = false;
 			if (t->bits_per_word < 4 || t->bits_per_word > 16)
 				return -EINVAL;
 		}
-		if (t->speed_hz && t->speed_hz < espi->min_rate)
+		if (t->speed_hz) {
+			can_continue = false;
+			if (t->speed_hz < espi->min_rate)
 				return -EINVAL;
+		}
+		if (t->cs_change &&
+			!list_is_last(&t->transfer_list, &msg->transfers)) {
+			can_continue = false;
+		}
+		if (t->delay_usecs)
+			can_continue = false;
 	}
 
 	/*
@@ -400,7 +413,7 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 	 * error in transfer and @msg->state is used to hold pointer to the
 	 * current transfer (or %NULL if no active current transfer).
 	 */
-	msg->state = NULL;
+	msg->state = (void *)can_continue;
 	msg->status = 0;
 	msg->actual_length = 0;
 
@@ -606,10 +619,33 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
 	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
 	ep93xx_spi_select_device(espi, msg->spi);
 
-	list_for_each_entry(t, &msg->transfers, transfer_list) {
-		ep93xx_spi_process_transfer(espi, msg, t);
-		if (msg->status)
-			break;
+	if (msg->state) {
+		espi->can_continue = true;
+		espi->last_transfer = list_entry(msg->transfers.prev, struct spi_transfer,
+						 transfer_list);
+	} else {
+		espi->can_continue = false;
+		espi->last_transfer = NULL;
+	}
+
+	/*
+	 * In case there is no transfer specific settings in this message we
+	 * can transfer the whole message with interrupts. Otherwise we need
+	 * to perform transfer specific stuff in thread context.
+	 */
+	if (espi->can_continue) {
+		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
+					      transfer_list);
+		espi->rx = 0;
+		espi->tx = 0;
+		ep93xx_spi_enable_interrupts(espi);
+		wait_for_completion(&espi->wait);
+	} else {
+		list_for_each_entry(t, &msg->transfers, transfer_list) {
+			ep93xx_spi_process_transfer(espi, msg, t);
+			if (msg->status)
+				break;
+		}
 	}
 
 	/*
@@ -792,6 +828,24 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
 			 * interrupt then.
 			 */
 			return IRQ_HANDLED;
+		} else {
+			/*
+			 * If we can continue directly to the next transfer, do
+			 * that now.
+			 */
+			if (espi->can_continue) {
+				struct spi_message *msg = espi->current_msg;
+				struct spi_transfer *t = msg->state;
+
+				if (t != espi->last_transfer) {
+					msg->state = list_entry(t->transfer_list.next, struct spi_transfer,
+								transfer_list);
+					espi->rx = 0;
+					espi->tx = 0;
+					return IRQ_HANDLED;
+				}
+			}
+			/* otherwise we are ready */
 		}
 	}
 

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21 10:46                             ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-21 10:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Apr 20, 2010 at 08:52:26PM -0500, H Hartley Sweeten wrote:
> On Tuesday, April 20, 2010 6:10 PM, Martin Guy wrote:
> > Not easily, but it seems a likely cause.
> > To prevent card deselection mid-message I think we would need to
> > handle multi-transfer messages by making the start of transfers 2..N
> > continuous with the end of transfers 1..N-1 instead of draining the
> > reply from each one before starting the next.
> > 
> > Am I on the right track?
> 
> Yes.  I'm just not sure how to implement this.

I made a hack that allows transfer handler to continue to the next transfer directly
if there is no special per transfer settings in the message. Could you try that out
and report whether SFRMOUT works better with it?

Note that this is just to make sure that we are on the right track.

Patch is against v4 of the driver.

Thanks,
MW

diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
index 310032d..11dcdd1 100644
--- a/drivers/spi/ep93xx_spi.c
+++ b/drivers/spi/ep93xx_spi.c
@@ -106,6 +106,8 @@ struct ep93xx_spi {
 	unsigned long			min_rate;
 	unsigned long			max_rate;
 	bool				running;
+	bool				can_continue;
+	struct spi_transfer 		*last_transfer;
 	struct workqueue_struct		*wq;
 	struct work_struct		msg_work;
 	struct completion		wait;
@@ -380,6 +382,7 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 	struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
 	struct spi_transfer *t;
 	unsigned long flags;
+	bool can_continue = true;
 
 	if (!msg || !msg->complete)
 		return -EINVAL;
@@ -387,11 +390,21 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 	/* first validate each transfer */
 	list_for_each_entry(t, &msg->transfers, transfer_list) {
 		if (t->bits_per_word) {
+			can_continue = false;
 			if (t->bits_per_word < 4 || t->bits_per_word > 16)
 				return -EINVAL;
 		}
-		if (t->speed_hz && t->speed_hz < espi->min_rate)
+		if (t->speed_hz) {
+			can_continue = false;
+			if (t->speed_hz < espi->min_rate)
 				return -EINVAL;
+		}
+		if (t->cs_change &&
+			!list_is_last(&t->transfer_list, &msg->transfers)) {
+			can_continue = false;
+		}
+		if (t->delay_usecs)
+			can_continue = false;
 	}
 
 	/*
@@ -400,7 +413,7 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 	 * error in transfer and @msg->state is used to hold pointer to the
 	 * current transfer (or %NULL if no active current transfer).
 	 */
-	msg->state = NULL;
+	msg->state = (void *)can_continue;
 	msg->status = 0;
 	msg->actual_length = 0;
 
@@ -606,10 +619,33 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
 	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
 	ep93xx_spi_select_device(espi, msg->spi);
 
-	list_for_each_entry(t, &msg->transfers, transfer_list) {
-		ep93xx_spi_process_transfer(espi, msg, t);
-		if (msg->status)
-			break;
+	if (msg->state) {
+		espi->can_continue = true;
+		espi->last_transfer = list_entry(msg->transfers.prev, struct spi_transfer,
+						 transfer_list);
+	} else {
+		espi->can_continue = false;
+		espi->last_transfer = NULL;
+	}
+
+	/*
+	 * In case there is no transfer specific settings in this message we
+	 * can transfer the whole message with interrupts. Otherwise we need
+	 * to perform transfer specific stuff in thread context.
+	 */
+	if (espi->can_continue) {
+		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
+					      transfer_list);
+		espi->rx = 0;
+		espi->tx = 0;
+		ep93xx_spi_enable_interrupts(espi);
+		wait_for_completion(&espi->wait);
+	} else {
+		list_for_each_entry(t, &msg->transfers, transfer_list) {
+			ep93xx_spi_process_transfer(espi, msg, t);
+			if (msg->status)
+				break;
+		}
 	}
 
 	/*
@@ -792,6 +828,24 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
 			 * interrupt then.
 			 */
 			return IRQ_HANDLED;
+		} else {
+			/*
+			 * If we can continue directly to the next transfer, do
+			 * that now.
+			 */
+			if (espi->can_continue) {
+				struct spi_message *msg = espi->current_msg;
+				struct spi_transfer *t = msg->state;
+
+				if (t != espi->last_transfer) {
+					msg->state = list_entry(t->transfer_list.next, struct spi_transfer,
+								transfer_list);
+					espi->rx = 0;
+					espi->tx = 0;
+					return IRQ_HANDLED;
+				}
+			}
+			/* otherwise we are ready */
 		}
 	}
 

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21  7:16             ` Mika Westerberg
@ 2010-04-21 16:47                 ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21 16:47 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Wednesday, April 21, 2010 12:16 AM, Mika Westerberg wrote:
>> 
>> These two functions can be combined.
>> 
>> /**
>>  * ep93xx_spi_chip_select() - select/deselect a given SPI device
>>  * @espi: ep93xx SPI controller struct
>>  * @spi: SPI device to select
>>  * @assert: flag to assert the chip select line
>>  *
>>  * Note that this function is called from a thread context and can sleep.
>>  */
>> static void ep93xx_spi_chip_select(const struct ep93xx_spi *espi,
>> 					     struct spi_device *spi, int assert)
>> {
>> 	int value = (spi->mode & SPI_CS_HIGH) ? !!assert : !assert;
>> 
>> 	if (espi->cs_control)
>> 		espi->cs_control(spi, value);
>> }
>> 
>> Then just do:
>> 
>> ep93xx_spi_select_device(espi, msg->spi, 1);	/* assert the spi chip select */
>> 
>> ep93xx_spi_select_device(espi, msg->spi, 0);	/* deassert the spi chip select */
>
>
> I think it is more readable to do:
>
>	ep93xx_spi_select_device(espi, msg->spi);
>
> and
>
>	ep93xx_spi_deselect_device(espi, msg->spi);
>
> It can be seen from the function names what we are doing.

So rename the combined function to ep93xx_spi_cs_control and pass the "control"
parameter as a bool; true = selected, false = deselected.

Having the two almost identical functions is a bit redundant.  It also gives you
two places to have to maintain basically the same operation.  I think this is
what Grant was referring to with his previous comment.

Regards,
Hartley
------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21 16:47                 ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21 16:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday, April 21, 2010 12:16 AM, Mika Westerberg wrote:
>> 
>> These two functions can be combined.
>> 
>> /**
>>  * ep93xx_spi_chip_select() - select/deselect a given SPI device
>>  * @espi: ep93xx SPI controller struct
>>  * @spi: SPI device to select
>>  * @assert: flag to assert the chip select line
>>  *
>>  * Note that this function is called from a thread context and can sleep.
>>  */
>> static void ep93xx_spi_chip_select(const struct ep93xx_spi *espi,
>> 					     struct spi_device *spi, int assert)
>> {
>> 	int value = (spi->mode & SPI_CS_HIGH) ? !!assert : !assert;
>> 
>> 	if (espi->cs_control)
>> 		espi->cs_control(spi, value);
>> }
>> 
>> Then just do:
>> 
>> ep93xx_spi_select_device(espi, msg->spi, 1);	/* assert the spi chip select */
>> 
>> ep93xx_spi_select_device(espi, msg->spi, 0);	/* deassert the spi chip select */
>
>
> I think it is more readable to do:
>
>	ep93xx_spi_select_device(espi, msg->spi);
>
> and
>
>	ep93xx_spi_deselect_device(espi, msg->spi);
>
> It can be seen from the function names what we are doing.

So rename the combined function to ep93xx_spi_cs_control and pass the "control"
parameter as a bool; true = selected, false = deselected.

Having the two almost identical functions is a bit redundant.  It also gives you
two places to have to maintain basically the same operation.  I think this is
what Grant was referring to with his previous comment.

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21 16:47                 ` H Hartley Sweeten
@ 2010-04-21 16:54                     ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-21 16:54 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Wed, Apr 21, 2010 at 11:47:13AM -0500, H Hartley Sweeten wrote:
> On Wednesday, April 21, 2010 12:16 AM, Mika Westerberg wrote:
> > I think it is more readable to do:
> >
> >	ep93xx_spi_select_device(espi, msg->spi);
> >
> > and
> >
> >	ep93xx_spi_deselect_device(espi, msg->spi);
> >
> > It can be seen from the function names what we are doing.
> 
> So rename the combined function to ep93xx_spi_cs_control and pass the "control"
> parameter as a bool; true = selected, false = deselected.
> 
> Having the two almost identical functions is a bit redundant.  It also gives you
> two places to have to maintain basically the same operation.  I think this is
> what Grant was referring to with his previous comment.

Agreed. Will do.

Thanks,
MW

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21 16:54                     ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-21 16:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 21, 2010 at 11:47:13AM -0500, H Hartley Sweeten wrote:
> On Wednesday, April 21, 2010 12:16 AM, Mika Westerberg wrote:
> > I think it is more readable to do:
> >
> >	ep93xx_spi_select_device(espi, msg->spi);
> >
> > and
> >
> >	ep93xx_spi_deselect_device(espi, msg->spi);
> >
> > It can be seen from the function names what we are doing.
> 
> So rename the combined function to ep93xx_spi_cs_control and pass the "control"
> parameter as a bool; true = selected, false = deselected.
> 
> Having the two almost identical functions is a bit redundant.  It also gives you
> two places to have to maintain basically the same operation.  I think this is
> what Grant was referring to with his previous comment.

Agreed. Will do.

Thanks,
MW

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21  6:37           ` Mika Westerberg
@ 2010-04-21 17:08               ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21 17:08 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tuesday, April 20, 2010 11:37 PM, Mika Westerberg wrote:
> On Tue, Apr 20, 2010 at 05:16:10PM -0500, H Hartley Sweeten wrote:
>> On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
>>>
>>> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
>>> in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
>>> 
>>> Signed-off-by: Mika Westerberg <mika.westerberg-X3B1VOXEql0@public.gmane.org>
>> 
>> Mika,
>> 
>> I discovered one gotcha with this driver.  Bear with me through this...
>> 
>> 1. ep93xx_spi_process_message is called by the workqueue worker function to handle
>>    a spi_message queued in by the ep93xx_spi_transfer function.  Before starting
>>    the actual transfer the chip select to the device is asserted.
>> 2. ep93xx_spi_process_transfer processes each transfer in the spi_message, one at a
>>    time, and does a wait_for_completion on each transfer.
>> 3. When the entire spi_message has been transferred the chip select to the device
>>    is deasserted.
>
> Yes. There is possibility that last transfer ->cs_change is set which can be used
> by SPI controller drivers to keep the chip selected in case next message is going
> to the same device.
>
> However, I haven't implemented that as it is optional (but trivial to add afterwards).

It should be implemented.  The mmc_spi driver basically requires this.  Refer to this
comment in the mmc_spi driver:

 * - We tell the controller to keep the chipselect active from the
 *   beginning of an mmc_host_ops.request until the end.  So beware
 *   of SPI controller drivers that mis-handle the cs_change flag!
 *
 *   However, many cards seem OK with chipselect flapping up/down
 *   during that time ... at least on unshared bus segments.

>> The problem is if a hardware design uses the SFRM1 pin as part of the chip select
>> logic.  The EP93xx User's Guide states that "the SFRMOUT signal behaves as a slave
>> Select" in Motorola SPI mode.  This signal behaves differently depending on the
>> SPI_MODE_* used.
>> 
>> Modes 0 and 2:
>>   SFRMOUT is forced HIGH during idle periods.
>>   Start of transmission, SFRMOUT is driven LOW.
>>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>>     SCLKOUT period after the last bit has been captured.
>>   Back-to-back transmissions, SFRMOUT signal is pulsed HIGH between each
>>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>>     HIGH state one SCLKOUT period after the last bit has been captured.
>> 
>> Modes 1 and 3:
>>   SFRMOUT is forced HIGH during idle periods.
>>   Start of transmission, SFRMOUT is driven LOW.
>>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>>     SCLKOUT period after the last bit has been captured.
>>   Back-to-back transmissions, SFRMOUT signal is held LOW between each
>>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>>     HIGH state one SCLKOUT period after the last bit has been captured.
>> 
>> So, since each transfer does a wait_for_completion, all the data is transmitted
>> which causes the SFRMOUT pin to go HIGH between each transfer in the message.
>
> Yes, unfortunately. SFRMOUT cannot be software controlled so it is
> not suitable for general purpose chipselect. This was the sole
> purpose of using GPIO lines for chipselects.

I agree.  But existing ep93xx designs, the EDB93xx boards and Sim.One for
instance, use the SFRMOUT either directly for the chip select or as part of
the logic generating the chip select.  If possible it would be nice to handle
this.

>> For devices like the sst25lf040a SPI Flash on the EDB93xx boards this causes a
>> problem.  To read data from that device you need to send a two part message.  The
>> first part is a write transfer with the one byte command and three byte address.
>> This is then followed by a read transfer to get the data.  But since the SFRMOUT
>> pin goes high this ends the command.>
>> 
>> The driver Ryan and I worked on actually does work with the sst25lf040a on the
>> EDB93xx boards.  But now that I know what the issue is, it was actually a race
>> condition.  Sometimes it worked and sometimes it didn't...
>> 
>> I would think the Sim.One board (Martin?) would have the same issue with the mmc
>> card since that design uses the SFRMOUT pin directly for the chip select.
>> 
>> Is there anyway to keep the transfers going in a muiltipart message?
>
> I'm not exactly sure but "polling" mode sounds something that could
> work around that. It just need to be sure that it transmits
> continuously to keep the SFRMOUT asserted.
>
> You could try v3 of the driver with:
>	# modprobe ep93xx-spi transfer_method=0
>
> and see if it works there.

I'll try to test this later.  The driver Ryan and I had used polling and it
worked but I think there was a race condition in it which occasionally broke
the transfer.

> An alternative would be that interrupt handler schedules tasklet which then
> takes next transfer immediately once current transfer is finished.

I think you would need to:

1. detect when all the transmit data in a transfer has been sent to the fifo
2. if there is another transfer pending, and a cs_change has not been requested,
   get it and start pumping it's transmit data into the fifo
3. read the remaining data for the first transfer then complete it
4. the pending transfer, which is already started, becomes the current transfer

Does this sound reasonable?

Regards,
Hartley


------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21 17:08               ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21 17:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, April 20, 2010 11:37 PM, Mika Westerberg wrote:
> On Tue, Apr 20, 2010 at 05:16:10PM -0500, H Hartley Sweeten wrote:
>> On Tuesday, April 20, 2010 8:12 AM, Mika Westerberg wrote:
>>>
>>> This patch adds an SPI master driver for the Cirrus EP93xx SPI controller found
>>> in EP93xx chips (EP9301, EP9302, EP9307, EP9312 and EP9315).
>>> 
>>> Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
>> 
>> Mika,
>> 
>> I discovered one gotcha with this driver.  Bear with me through this...
>> 
>> 1. ep93xx_spi_process_message is called by the workqueue worker function to handle
>>    a spi_message queued in by the ep93xx_spi_transfer function.  Before starting
>>    the actual transfer the chip select to the device is asserted.
>> 2. ep93xx_spi_process_transfer processes each transfer in the spi_message, one at a
>>    time, and does a wait_for_completion on each transfer.
>> 3. When the entire spi_message has been transferred the chip select to the device
>>    is deasserted.
>
> Yes. There is possibility that last transfer ->cs_change is set which can be used
> by SPI controller drivers to keep the chip selected in case next message is going
> to the same device.
>
> However, I haven't implemented that as it is optional (but trivial to add afterwards).

It should be implemented.  The mmc_spi driver basically requires this.  Refer to this
comment in the mmc_spi driver:

 * - We tell the controller to keep the chipselect active from the
 *   beginning of an mmc_host_ops.request until the end.  So beware
 *   of SPI controller drivers that mis-handle the cs_change flag!
 *
 *   However, many cards seem OK with chipselect flapping up/down
 *   during that time ... at least on unshared bus segments.

>> The problem is if a hardware design uses the SFRM1 pin as part of the chip select
>> logic.  The EP93xx User's Guide states that "the SFRMOUT signal behaves as a slave
>> Select" in Motorola SPI mode.  This signal behaves differently depending on the
>> SPI_MODE_* used.
>> 
>> Modes 0 and 2:
>>   SFRMOUT is forced HIGH during idle periods.
>>   Start of transmission, SFRMOUT is driven LOW.
>>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>>     SCLKOUT period after the last bit has been captured.
>>   Back-to-back transmissions, SFRMOUT signal is pulsed HIGH between each
>>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>>     HIGH state one SCLKOUT period after the last bit has been captured.
>> 
>> Modes 1 and 3:
>>   SFRMOUT is forced HIGH during idle periods.
>>   Start of transmission, SFRMOUT is driven LOW.
>>   Single word transmission, SFRMOUT is returned to its idle HIGH state one
>>     SCLKOUT period after the last bit has been captured.
>>   Back-to-back transmissions, SFRMOUT signal is held LOW between each
>>     data word transfer.  On completion the SFRMOUT pin returns to its idle
>>     HIGH state one SCLKOUT period after the last bit has been captured.
>> 
>> So, since each transfer does a wait_for_completion, all the data is transmitted
>> which causes the SFRMOUT pin to go HIGH between each transfer in the message.
>
> Yes, unfortunately. SFRMOUT cannot be software controlled so it is
> not suitable for general purpose chipselect. This was the sole
> purpose of using GPIO lines for chipselects.

I agree.  But existing ep93xx designs, the EDB93xx boards and Sim.One for
instance, use the SFRMOUT either directly for the chip select or as part of
the logic generating the chip select.  If possible it would be nice to handle
this.

>> For devices like the sst25lf040a SPI Flash on the EDB93xx boards this causes a
>> problem.  To read data from that device you need to send a two part message.  The
>> first part is a write transfer with the one byte command and three byte address.
>> This is then followed by a read transfer to get the data.  But since the SFRMOUT
>> pin goes high this ends the command.>
>> 
>> The driver Ryan and I worked on actually does work with the sst25lf040a on the
>> EDB93xx boards.  But now that I know what the issue is, it was actually a race
>> condition.  Sometimes it worked and sometimes it didn't...
>> 
>> I would think the Sim.One board (Martin?) would have the same issue with the mmc
>> card since that design uses the SFRMOUT pin directly for the chip select.
>> 
>> Is there anyway to keep the transfers going in a muiltipart message?
>
> I'm not exactly sure but "polling" mode sounds something that could
> work around that. It just need to be sure that it transmits
> continuously to keep the SFRMOUT asserted.
>
> You could try v3 of the driver with:
>	# modprobe ep93xx-spi transfer_method=0
>
> and see if it works there.

I'll try to test this later.  The driver Ryan and I had used polling and it
worked but I think there was a race condition in it which occasionally broke
the transfer.

> An alternative would be that interrupt handler schedules tasklet which then
> takes next transfer immediately once current transfer is finished.

I think you would need to:

1. detect when all the transmit data in a transfer has been sent to the fifo
2. if there is another transfer pending, and a cs_change has not been requested,
   get it and start pumping it's transmit data into the fifo
3. read the remaining data for the first transfer then complete it
4. the pending transfer, which is already started, becomes the current transfer

Does this sound reasonable?

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21 10:46                             ` Mika Westerberg
@ 2010-04-21 18:00                                 ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21 18:00 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 6053 bytes --]

On Wednesday, April 21, 2010 3:47 AM, Mika Westerberg wrote:
> On Tue, Apr 20, 2010 at 08:52:26PM -0500, H Hartley Sweeten wrote:
>> On Tuesday, April 20, 2010 6:10 PM, Martin Guy wrote:
>>> Not easily, but it seems a likely cause.
>>> To prevent card deselection mid-message I think we would need to
>>> handle multi-transfer messages by making the start of transfers 2..N
>>> continuous with the end of transfers 1..N-1 instead of draining the
>>> reply from each one before starting the next.
>>> 
>>> Am I on the right track?
>> 
>> Yes.  I'm just not sure how to implement this.
>
> I made a hack that allows transfer handler to continue to the next transfer directly
> if there is no special per transfer settings in the message. Could you try that out
> and report whether SFRMOUT works better with it?
>
> Note that this is just to make sure that we are on the right track.
>
> Patch is against v4 of the driver.
>
> Thanks,
> MW
>
> diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
> index 310032d..11dcdd1 100644
> --- a/drivers/spi/ep93xx_spi.c
> +++ b/drivers/spi/ep93xx_spi.c
> @@ -106,6 +106,8 @@ struct ep93xx_spi {
>  	unsigned long			min_rate;
>  	unsigned long			max_rate;
>  	bool				running;
> +	bool				can_continue;
> +	struct spi_transfer 		*last_transfer;
>  	struct workqueue_struct		*wq;
>  	struct work_struct		msg_work;
>  	struct completion		wait;
> @@ -380,6 +382,7 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
>  	struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
>  	struct spi_transfer *t;
>  	unsigned long flags;
> +	bool can_continue = true;
>  
>  	if (!msg || !msg->complete)
>  		return -EINVAL;
> @@ -387,11 +390,21 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
>  	/* first validate each transfer */
>  	list_for_each_entry(t, &msg->transfers, transfer_list) {
>  		if (t->bits_per_word) {
> +			can_continue = false;
>  			if (t->bits_per_word < 4 || t->bits_per_word > 16)
>  				return -EINVAL;
>  		}
> -		if (t->speed_hz && t->speed_hz < espi->min_rate)
> +		if (t->speed_hz) {
> +			can_continue = false;
> +			if (t->speed_hz < espi->min_rate)
>  				return -EINVAL;
> +		}
> +		if (t->cs_change &&
> +			!list_is_last(&t->transfer_list, &msg->transfers)) {
> +			can_continue = false;
> +		}
> +		if (t->delay_usecs)
> +			can_continue = false;
>  	}
>  
>  	/*
> @@ -400,7 +413,7 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
>  	 * error in transfer and @msg->state is used to hold pointer to the
>  	 * current transfer (or %NULL if no active current transfer).
>  	 */
> -	msg->state = NULL;
> +	msg->state = (void *)can_continue;
>  	msg->status = 0;
>  	msg->actual_length = 0;
>  
> @@ -606,10 +619,33 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
>  	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
>  	ep93xx_spi_select_device(espi, msg->spi);
>  
> -	list_for_each_entry(t, &msg->transfers, transfer_list) {
> -		ep93xx_spi_process_transfer(espi, msg, t);
> -		if (msg->status)
> -			break;
> +	if (msg->state) {
> +		espi->can_continue = true;
> +		espi->last_transfer = list_entry(msg->transfers.prev, struct spi_transfer,
> +						 transfer_list);
> +	} else {
> +		espi->can_continue = false;
> +		espi->last_transfer = NULL;
> +	}
> +
> +	/*
> +	 * In case there is no transfer specific settings in this message we
> +	 * can transfer the whole message with interrupts. Otherwise we need
> +	 * to perform transfer specific stuff in thread context.
> +	 */
> +	if (espi->can_continue) {
> +		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
> +					      transfer_list);
> +		espi->rx = 0;
> +		espi->tx = 0;
> +		ep93xx_spi_enable_interrupts(espi);
> +		wait_for_completion(&espi->wait);
> +	} else {
> +		list_for_each_entry(t, &msg->transfers, transfer_list) {
> +			ep93xx_spi_process_transfer(espi, msg, t);
> +			if (msg->status)
> +				break;
> +		}
>  	}
>  
>  	/*
> @@ -792,6 +828,24 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
>  			 * interrupt then.
>  			 */
>  			return IRQ_HANDLED;
> +		} else {
> +			/*
> +			 * If we can continue directly to the next transfer, do
> +			 * that now.
> +			 */
> +			if (espi->can_continue) {
> +				struct spi_message *msg = espi->current_msg;
> +				struct spi_transfer *t = msg->state;
> +
> +				if (t != espi->last_transfer) {
> +					msg->state = list_entry(t->transfer_list.next, struct spi_transfer,
> +								transfer_list);
> +					espi->rx = 0;
> +					espi->tx = 0;
> +					return IRQ_HANDLED;
> +				}
> +			}
> +			/* otherwise we are ready */
>  		}
>  	}
 
Same results are your v4 driver.  But, I think your on the right track.

I think the problem is in the ep93xx_spi_read_write routine.  That function
returns 0 as long as there is still data left in the current transfer.  The
only time it doesn't return 0, which will cause the can_continue, is when:

	if (espi->rx == t->len) {
		msg->actual_length += t->len;
		return t->len;
	}

At this point the tx and rx fifos will both be empty, which causes the SSP
peripheral to raise the SFRM signal.

A picture is worth a thousand words... Attached is a logic analyzer capture
of the Read-ID command and response from the SPI Flash.  EGPIO7 is my chip
select to the flash.  The first 4 SPI MOSI (Tx) blocks are the 0x90, 0x00,
0x00, 0x00 command to the flash.  You will notice that the SFRM line is
asserted for those bytes.  A bit later are the 2 SPI MISO (Rx) responses
from the flash with the ManID/DevID, again with the SFRM line asserted.

If the can_continue stuff worked correctly the second block should be right
with the first block.

I'm going to try hacking the spi flash driver to send the command/response
as a 6-byte full duplex message to make sure it works.

Regards,
Hartley

[-- Attachment #2: Type: text/plain, Size: 79 bytes --]

------------------------------------------------------------------------------

[-- Attachment #3: Type: text/plain, Size: 210 bytes --]

_______________________________________________
spi-devel-general mailing list
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-21 18:00                                 ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-21 18:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday, April 21, 2010 3:47 AM, Mika Westerberg wrote:
> On Tue, Apr 20, 2010 at 08:52:26PM -0500, H Hartley Sweeten wrote:
>> On Tuesday, April 20, 2010 6:10 PM, Martin Guy wrote:
>>> Not easily, but it seems a likely cause.
>>> To prevent card deselection mid-message I think we would need to
>>> handle multi-transfer messages by making the start of transfers 2..N
>>> continuous with the end of transfers 1..N-1 instead of draining the
>>> reply from each one before starting the next.
>>> 
>>> Am I on the right track?
>> 
>> Yes.  I'm just not sure how to implement this.
>
> I made a hack that allows transfer handler to continue to the next transfer directly
> if there is no special per transfer settings in the message. Could you try that out
> and report whether SFRMOUT works better with it?
>
> Note that this is just to make sure that we are on the right track.
>
> Patch is against v4 of the driver.
>
> Thanks,
> MW
>
> diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
> index 310032d..11dcdd1 100644
> --- a/drivers/spi/ep93xx_spi.c
> +++ b/drivers/spi/ep93xx_spi.c
> @@ -106,6 +106,8 @@ struct ep93xx_spi {
>  	unsigned long			min_rate;
>  	unsigned long			max_rate;
>  	bool				running;
> +	bool				can_continue;
> +	struct spi_transfer 		*last_transfer;
>  	struct workqueue_struct		*wq;
>  	struct work_struct		msg_work;
>  	struct completion		wait;
> @@ -380,6 +382,7 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
>  	struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
>  	struct spi_transfer *t;
>  	unsigned long flags;
> +	bool can_continue = true;
>  
>  	if (!msg || !msg->complete)
>  		return -EINVAL;
> @@ -387,11 +390,21 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
>  	/* first validate each transfer */
>  	list_for_each_entry(t, &msg->transfers, transfer_list) {
>  		if (t->bits_per_word) {
> +			can_continue = false;
>  			if (t->bits_per_word < 4 || t->bits_per_word > 16)
>  				return -EINVAL;
>  		}
> -		if (t->speed_hz && t->speed_hz < espi->min_rate)
> +		if (t->speed_hz) {
> +			can_continue = false;
> +			if (t->speed_hz < espi->min_rate)
>  				return -EINVAL;
> +		}
> +		if (t->cs_change &&
> +			!list_is_last(&t->transfer_list, &msg->transfers)) {
> +			can_continue = false;
> +		}
> +		if (t->delay_usecs)
> +			can_continue = false;
>  	}
>  
>  	/*
> @@ -400,7 +413,7 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
>  	 * error in transfer and @msg->state is used to hold pointer to the
>  	 * current transfer (or %NULL if no active current transfer).
>  	 */
> -	msg->state = NULL;
> +	msg->state = (void *)can_continue;
>  	msg->status = 0;
>  	msg->actual_length = 0;
>  
> @@ -606,10 +619,33 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
>  	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
>  	ep93xx_spi_select_device(espi, msg->spi);
>  
> -	list_for_each_entry(t, &msg->transfers, transfer_list) {
> -		ep93xx_spi_process_transfer(espi, msg, t);
> -		if (msg->status)
> -			break;
> +	if (msg->state) {
> +		espi->can_continue = true;
> +		espi->last_transfer = list_entry(msg->transfers.prev, struct spi_transfer,
> +						 transfer_list);
> +	} else {
> +		espi->can_continue = false;
> +		espi->last_transfer = NULL;
> +	}
> +
> +	/*
> +	 * In case there is no transfer specific settings in this message we
> +	 * can transfer the whole message with interrupts. Otherwise we need
> +	 * to perform transfer specific stuff in thread context.
> +	 */
> +	if (espi->can_continue) {
> +		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
> +					      transfer_list);
> +		espi->rx = 0;
> +		espi->tx = 0;
> +		ep93xx_spi_enable_interrupts(espi);
> +		wait_for_completion(&espi->wait);
> +	} else {
> +		list_for_each_entry(t, &msg->transfers, transfer_list) {
> +			ep93xx_spi_process_transfer(espi, msg, t);
> +			if (msg->status)
> +				break;
> +		}
>  	}
>  
>  	/*
> @@ -792,6 +828,24 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
>  			 * interrupt then.
>  			 */
>  			return IRQ_HANDLED;
> +		} else {
> +			/*
> +			 * If we can continue directly to the next transfer, do
> +			 * that now.
> +			 */
> +			if (espi->can_continue) {
> +				struct spi_message *msg = espi->current_msg;
> +				struct spi_transfer *t = msg->state;
> +
> +				if (t != espi->last_transfer) {
> +					msg->state = list_entry(t->transfer_list.next, struct spi_transfer,
> +								transfer_list);
> +					espi->rx = 0;
> +					espi->tx = 0;
> +					return IRQ_HANDLED;
> +				}
> +			}
> +			/* otherwise we are ready */
>  		}
>  	}
 
Same results are your v4 driver.  But, I think your on the right track.

I think the problem is in the ep93xx_spi_read_write routine.  That function
returns 0 as long as there is still data left in the current transfer.  The
only time it doesn't return 0, which will cause the can_continue, is when:

	if (espi->rx == t->len) {
		msg->actual_length += t->len;
		return t->len;
	}

At this point the tx and rx fifos will both be empty, which causes the SSP
peripheral to raise the SFRM signal.

A picture is worth a thousand words... Attached is a logic analyzer capture
of the Read-ID command and response from the SPI Flash.  EGPIO7 is my chip
select to the flash.  The first 4 SPI MOSI (Tx) blocks are the 0x90, 0x00,
0x00, 0x00 command to the flash.  You will notice that the SFRM line is
asserted for those bytes.  A bit later are the 2 SPI MISO (Rx) responses
from the flash with the ManID/DevID, again with the SFRM line asserted.

If the can_continue stuff worked correctly the second block should be right
with the first block.

I'm going to try hacking the spi flash driver to send the command/response
as a 6-byte full duplex message to make sure it works.

Regards,
Hartley
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ep93xx_spi.PNG
Type: image/png
Size: 38169 bytes
Desc: ep93xx_spi.PNG
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100421/4959d367/attachment-0001.png>

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21 16:54                     ` Mika Westerberg
@ 2010-04-22  2:47                         ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-22  2:47 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Mika,

I have added some debug messages to the driver trying to figure out
how to chain the transfers in a message together in order to keep
the SFRM signal asserted for the entire message.  I still haven't
worked out a good solution but I did notice something else.

First, every spi transaction, including a single byte transfer, is
going to generate at least two interrupts.  One when the interrupts
are first enabled because the TX FIFO is empty.  And a second when
that byte has been transferred and the TX FIFO is again empty.

The first interrupt can be prevented by priming the TX FIFO before
enabling the interrupts.  All you need to do is call ep93xx_spi_read_write
right before ep93xx_spi_enable_interrupts.

Second, at high clock rates the RX FIFO will actually start to
fill as you are putting data into the TX FIFO.  If you add an inner
reader loop to the writer loop in ep93xx_spi_read_write you can
take advantage of this and reduce the number of interrupts generated
for large transfers.

For instance the mmc_spi driver regularly does 3 transfer messages
where the last transfer is a 512 byte read.  With your current v4
driver this message averages 69 interrupts to complete.  By adding
the inner reader it reduces the number of interrupts to an average
of 40.

Regards,
Hartley

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-22  2:47                         ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-22  2:47 UTC (permalink / raw)
  To: linux-arm-kernel

Mika,

I have added some debug messages to the driver trying to figure out
how to chain the transfers in a message together in order to keep
the SFRM signal asserted for the entire message.  I still haven't
worked out a good solution but I did notice something else.

First, every spi transaction, including a single byte transfer, is
going to generate at least two interrupts.  One when the interrupts
are first enabled because the TX FIFO is empty.  And a second when
that byte has been transferred and the TX FIFO is again empty.

The first interrupt can be prevented by priming the TX FIFO before
enabling the interrupts.  All you need to do is call ep93xx_spi_read_write
right before ep93xx_spi_enable_interrupts.

Second, at high clock rates the RX FIFO will actually start to
fill as you are putting data into the TX FIFO.  If you add an inner
reader loop to the writer loop in ep93xx_spi_read_write you can
take advantage of this and reduce the number of interrupts generated
for large transfers.

For instance the mmc_spi driver regularly does 3 transfer messages
where the last transfer is a 512 byte read.  With your current v4
driver this message averages 69 interrupts to complete.  By adding
the inner reader it reduces the number of interrupts to an average
of 40.

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21 18:00                                 ` H Hartley Sweeten
@ 2010-04-22  5:45                                     ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-22  5:45 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Wed, Apr 21, 2010 at 01:00:56PM -0500, H Hartley Sweeten wrote:
> Same results are your v4 driver.  But, I think your on the right track.

Thanks for testing.

> I think the problem is in the ep93xx_spi_read_write routine.  That function
> returns 0 as long as there is still data left in the current transfer.  The
> only time it doesn't return 0, which will cause the can_continue, is when:
> 
> 	if (espi->rx == t->len) {
> 		msg->actual_length += t->len;
> 		return t->len;
> 	}
> 
> At this point the tx and rx fifos will both be empty, which causes the SSP
> peripheral to raise the SFRM signal.

True.

> A picture is worth a thousand words... Attached is a logic analyzer capture
> of the Read-ID command and response from the SPI Flash.  EGPIO7 is my chip
> select to the flash.  The first 4 SPI MOSI (Tx) blocks are the 0x90, 0x00,
> 0x00, 0x00 command to the flash.  You will notice that the SFRM line is
> asserted for those bytes.  A bit later are the 2 SPI MISO (Rx) responses
> from the flash with the ManID/DevID, again with the SFRM line asserted.

Yeah, it clearly shows that SFRMOUT is deasserted between transfers :(

I will try to work out some sort of hack which will keep the FIFOs from
emptying.

MW

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-22  5:45                                     ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-22  5:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 21, 2010 at 01:00:56PM -0500, H Hartley Sweeten wrote:
> Same results are your v4 driver.  But, I think your on the right track.

Thanks for testing.

> I think the problem is in the ep93xx_spi_read_write routine.  That function
> returns 0 as long as there is still data left in the current transfer.  The
> only time it doesn't return 0, which will cause the can_continue, is when:
> 
> 	if (espi->rx == t->len) {
> 		msg->actual_length += t->len;
> 		return t->len;
> 	}
> 
> At this point the tx and rx fifos will both be empty, which causes the SSP
> peripheral to raise the SFRM signal.

True.

> A picture is worth a thousand words... Attached is a logic analyzer capture
> of the Read-ID command and response from the SPI Flash.  EGPIO7 is my chip
> select to the flash.  The first 4 SPI MOSI (Tx) blocks are the 0x90, 0x00,
> 0x00, 0x00 command to the flash.  You will notice that the SFRM line is
> asserted for those bytes.  A bit later are the 2 SPI MISO (Rx) responses
> from the flash with the ManID/DevID, again with the SFRM line asserted.

Yeah, it clearly shows that SFRMOUT is deasserted between transfers :(

I will try to work out some sort of hack which will keep the FIFOs from
emptying.

MW

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-22  2:47                         ` H Hartley Sweeten
@ 2010-04-22  5:53                             ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-22  5:53 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	martinwguy-Re5JQEeQqe8AvxtiuMwx3w, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Wed, Apr 21, 2010 at 09:47:14PM -0500, H Hartley Sweeten wrote:
[...]
> First, every spi transaction, including a single byte transfer, is
> going to generate at least two interrupts.  One when the interrupts
> are first enabled because the TX FIFO is empty.  And a second when
> that byte has been transferred and the TX FIFO is again empty.
> 
> The first interrupt can be prevented by priming the TX FIFO before
> enabling the interrupts.  All you need to do is call ep93xx_spi_read_write
> right before ep93xx_spi_enable_interrupts.

OK thanks.

> Second, at high clock rates the RX FIFO will actually start to
> fill as you are putting data into the TX FIFO.  If you add an inner
> reader loop to the writer loop in ep93xx_spi_read_write you can
> take advantage of this and reduce the number of interrupts generated
> for large transfers.

I originally had inner read loop in the first version of the driver
but it wasn't functioning as it should (this was pointed out by
Martin). But now when we have explicit FIFO size handling, I think
that it can be added there again.

Thanks,
MW

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-22  5:53                             ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-22  5:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 21, 2010 at 09:47:14PM -0500, H Hartley Sweeten wrote:
[...]
> First, every spi transaction, including a single byte transfer, is
> going to generate at least two interrupts.  One when the interrupts
> are first enabled because the TX FIFO is empty.  And a second when
> that byte has been transferred and the TX FIFO is again empty.
> 
> The first interrupt can be prevented by priming the TX FIFO before
> enabling the interrupts.  All you need to do is call ep93xx_spi_read_write
> right before ep93xx_spi_enable_interrupts.

OK thanks.

> Second, at high clock rates the RX FIFO will actually start to
> fill as you are putting data into the TX FIFO.  If you add an inner
> reader loop to the writer loop in ep93xx_spi_read_write you can
> take advantage of this and reduce the number of interrupts generated
> for large transfers.

I originally had inner read loop in the first version of the driver
but it wasn't functioning as it should (this was pointed out by
Martin). But now when we have explicit FIFO size handling, I think
that it can be added there again.

Thanks,
MW

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-22  2:47                         ` H Hartley Sweeten
@ 2010-04-22 14:11                             ` Martin Guy
  -1 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-22 14:11 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 4/22/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
>  I have added some debug messages to the driver trying to figure out
>  how to chain the transfers in a message together in order to keep
>  the SFRM signal asserted for the entire message.  I still haven't
>  worked out a good solution but I did notice something else.
>
>  First, every spi transaction, including a single byte transfer, is
>  going to generate at least two interrupts.  One when the interrupts
>  are first enabled because the TX FIFO is empty.  And a second when
>  that byte has been transferred and the TX FIFO is again empty.
>
>  The first interrupt can be prevented by priming the TX FIFO before
>  enabling the interrupts.  All you need to do is call ep93xx_spi_read_write
>  right before ep93xx_spi_enable_interrupts.


>  Second, at high clock rates the RX FIFO will actually start to
>  fill as you are putting data into the TX FIFO.  If you add an inner
>  reader loop to the writer loop in ep93xx_spi_read_write you can
>  take advantage of this and reduce the number of interrupts generated
>  for large transfers.
>
>  For instance the mmc_spi driver regularly does 3 transfer messages
>  where the last transfer is a 512 byte read.  With your current v4
>  driver this message averages 69 interrupts to complete.  By adding
>  the inner reader it reduces the number of interrupts to an average
>  of 40.

I assume you mean something like

        /* read as long as RX FIFO has frames in it */
        while (ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE) {
                ep93xx_do_read(espi, t);
                espi->fifo_level--;
        }

        /* write as long as TX FIFO has room */
        while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
                ep93xx_do_write(espi, t);
                espi->fifo_level++;
+
+               while (ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE) {
+                       ep93xx_do_read(espi, t);
+                       espi->fifo_level--;
+               }
        }

Well, you're gonna love this :)

I've run some timing tests on this, and it turns out to give the same
data transfer speed but take more system CPU time: 64% instead of 60%,
i.e it is slower.

You are seeing a lower interrupt count, not because more useful work
is being done in each interrupt, but only because the extra code in
the inner loop makes the interrupt routine slower. Bear with me...

I'm using v4 with mika's continuity hack compiled for speed not space
and averaging the vmstat "sy" output column over 50 seconds while
block-reading 20 meg with dd from /dev/mmcblk0 to /dev/null using a
fairly old Sandisk 1MB SD card and clocking at 3.7 MHz.
All tests report 367 or 368 kB/sec; the variability of the system time
average in successive runs is about 1%

Figures are (commas separate values from successive runs)
v4 with Mika's hack:
     61.9,60.2%  234724,234727 irq/MB
with "while" reader in write loop:
     63.4,64.5%  197772,97801 irq/MB
with "if" reader in while loop:
     61.9,62.5%  197845,197847  irq/MB
with an "if" reader after the write loop:
     66.0,67.1%  278207,277166 irq/MB
with a "while" reader after the write loop:
     67.0%  275000 irq/MB

Further, on a suspicion about the silliness of the per-transfer
bits_per_word being checked right down the bottom of the lowest lever
byte-read/writing routine instead of once per transfer, I split
ep93xx_spi_read and _write into 8 and 16-bit variants, and checked
t->bits_per_word once outside the read and write loops.

This gives:
     60.0% 59.3%  285906 irq/MB

Note: it takes *more* interrupts to transfer a megabyte when the
interrupt routine is more efficient!

The reason is that almost all of those interrupts happen while waiting
for the last 4, 3, 2 or 1 bytes of a transfer to arrive in the RX
FIFO. On this dreadful chip there is no interrupt mechanism to say
"the TX buffer is empty and the received data has finished arriving".
There is only "the TX buffer is half empty or less" and "the RX buffer
is half full or more", so repeated interrupts now perform the function
that the old busy-wait loop performed in v1.

This is another good reason to unite multiple transfers into one
continuous stream, to have less of this effective busy-waiting with
interrupts spinning madly.

It now occurs to me that another step in CPU efficiency could be had
by abusing the receive-fifo-is-half-full interrupt to signal the
completion of a transfer. This would only work for transfers of four
or more words and would need some careful jiggery-pokery at end of
transfer to turn the tx-fifo-is-half-empty interrupt enable off and
ensure that exactly four words would end up in the RX FIFO.
It's a horrible thought, and I suspect that the DMA engine is the real answer.

   M

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-22 14:11                             ` Martin Guy
  0 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-22 14:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 4/22/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
>  I have added some debug messages to the driver trying to figure out
>  how to chain the transfers in a message together in order to keep
>  the SFRM signal asserted for the entire message.  I still haven't
>  worked out a good solution but I did notice something else.
>
>  First, every spi transaction, including a single byte transfer, is
>  going to generate at least two interrupts.  One when the interrupts
>  are first enabled because the TX FIFO is empty.  And a second when
>  that byte has been transferred and the TX FIFO is again empty.
>
>  The first interrupt can be prevented by priming the TX FIFO before
>  enabling the interrupts.  All you need to do is call ep93xx_spi_read_write
>  right before ep93xx_spi_enable_interrupts.


>  Second, at high clock rates the RX FIFO will actually start to
>  fill as you are putting data into the TX FIFO.  If you add an inner
>  reader loop to the writer loop in ep93xx_spi_read_write you can
>  take advantage of this and reduce the number of interrupts generated
>  for large transfers.
>
>  For instance the mmc_spi driver regularly does 3 transfer messages
>  where the last transfer is a 512 byte read.  With your current v4
>  driver this message averages 69 interrupts to complete.  By adding
>  the inner reader it reduces the number of interrupts to an average
>  of 40.

I assume you mean something like

        /* read as long as RX FIFO has frames in it */
        while (ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE) {
                ep93xx_do_read(espi, t);
                espi->fifo_level--;
        }

        /* write as long as TX FIFO has room */
        while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
                ep93xx_do_write(espi, t);
                espi->fifo_level++;
+
+               while (ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE) {
+                       ep93xx_do_read(espi, t);
+                       espi->fifo_level--;
+               }
        }

Well, you're gonna love this :)

I've run some timing tests on this, and it turns out to give the same
data transfer speed but take more system CPU time: 64% instead of 60%,
i.e it is slower.

You are seeing a lower interrupt count, not because more useful work
is being done in each interrupt, but only because the extra code in
the inner loop makes the interrupt routine slower. Bear with me...

I'm using v4 with mika's continuity hack compiled for speed not space
and averaging the vmstat "sy" output column over 50 seconds while
block-reading 20 meg with dd from /dev/mmcblk0 to /dev/null using a
fairly old Sandisk 1MB SD card and clocking at 3.7 MHz.
All tests report 367 or 368 kB/sec; the variability of the system time
average in successive runs is about 1%

Figures are (commas separate values from successive runs)
v4 with Mika's hack:
     61.9,60.2%  234724,234727 irq/MB
with "while" reader in write loop:
     63.4,64.5%  197772,97801 irq/MB
with "if" reader in while loop:
     61.9,62.5%  197845,197847  irq/MB
with an "if" reader after the write loop:
     66.0,67.1%  278207,277166 irq/MB
with a "while" reader after the write loop:
     67.0%  275000 irq/MB

Further, on a suspicion about the silliness of the per-transfer
bits_per_word being checked right down the bottom of the lowest lever
byte-read/writing routine instead of once per transfer, I split
ep93xx_spi_read and _write into 8 and 16-bit variants, and checked
t->bits_per_word once outside the read and write loops.

This gives:
     60.0% 59.3%  285906 irq/MB

Note: it takes *more* interrupts to transfer a megabyte when the
interrupt routine is more efficient!

The reason is that almost all of those interrupts happen while waiting
for the last 4, 3, 2 or 1 bytes of a transfer to arrive in the RX
FIFO. On this dreadful chip there is no interrupt mechanism to say
"the TX buffer is empty and the received data has finished arriving".
There is only "the TX buffer is half empty or less" and "the RX buffer
is half full or more", so repeated interrupts now perform the function
that the old busy-wait loop performed in v1.

This is another good reason to unite multiple transfers into one
continuous stream, to have less of this effective busy-waiting with
interrupts spinning madly.

It now occurs to me that another step in CPU efficiency could be had
by abusing the receive-fifo-is-half-full interrupt to signal the
completion of a transfer. This would only work for transfers of four
or more words and would need some careful jiggery-pokery at end of
transfer to turn the tx-fifo-is-half-empty interrupt enable off and
ensure that exactly four words would end up in the RX FIFO.
It's a horrible thought, and I suspect that the DMA engine is the real answer.

   M

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-22  2:47                         ` H Hartley Sweeten
@ 2010-04-22 14:28                             ` Martin Guy
  -1 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-22 14:28 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 4/22/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
>  First, every spi transaction, including a single byte transfer, is
>  going to generate at least two interrupts.  One when the interrupts
>  are first enabled because the TX FIFO is empty.  And a second when
>  that byte has been transferred and the TX FIFO is again empty.
>
>  The first interrupt can be prevented by priming the TX FIFO before
>  enabling the interrupts.  All you need to do is call ep93xx_spi_read_write
>  right before ep93xx_spi_enable_interrupts.

Nice. That increases the data throughput from 367 to 372 kB/sec and
reduces the CPU usage from 61 to 60.2% for large transfers

    M

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-22 14:28                             ` Martin Guy
  0 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-22 14:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 4/22/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
>  First, every spi transaction, including a single byte transfer, is
>  going to generate at least two interrupts.  One when the interrupts
>  are first enabled because the TX FIFO is empty.  And a second when
>  that byte has been transferred and the TX FIFO is again empty.
>
>  The first interrupt can be prevented by priming the TX FIFO before
>  enabling the interrupts.  All you need to do is call ep93xx_spi_read_write
>  right before ep93xx_spi_enable_interrupts.

Nice. That increases the data throughput from 367 to 372 kB/sec and
reduces the CPU usage from 61 to 60.2% for large transfers

    M

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-22 14:28                             ` Martin Guy
@ 2010-04-22 17:39                                 ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-22 17:39 UTC (permalink / raw)
  To: Martin Guy
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Martin,

I'm replying to both of your previous messages.

On Thursday, April 22, 2010 7:28 AM, Martin Guy wrote:
> On 4/22/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
>>  First, every spi transaction, including a single byte transfer, is
>>  going to generate at least two interrupts.  One when the interrupts
>>  are first enabled because the TX FIFO is empty.  And a second when
>>  that byte has been transferred and the TX FIFO is again empty.
>>
>>  The first interrupt can be prevented by priming the TX FIFO before
>>  enabling the interrupts.  All you need to do is call ep93xx_spi_read_write
>>  right before ep93xx_spi_enable_interrupts.
>
> Nice. That increases the data throughput from 367 to 372 kB/sec and
> reduces the CPU usage from 61 to 60.2% for large transfers

I figured "priming the fifo" before turning the transfer over to the
interrupt handler would help.

On Thursday, April 22, 2010 7:12 AM, Martin Guy wrote:
>>  Second, at high clock rates the RX FIFO will actually start to
>>  fill as you are putting data into the TX FIFO.  If you add an inner
>>  reader loop to the writer loop in ep93xx_spi_read_write you can
>>  take advantage of this and reduce the number of interrupts generated
>>  for large transfers.
>>
>>  For instance the mmc_spi driver regularly does 3 transfer messages
>>  where the last transfer is a 512 byte read.  With your current v4
>>  driver this message averages 69 interrupts to complete.  By adding
>>  the inner reader it reduces the number of interrupts to an average
>>  of 40.
>
> I assume you mean something like
>
>        /* read as long as RX FIFO has frames in it */
>        while (ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE) {
>                ep93xx_do_read(espi, t);
>                espi->fifo_level--;
>        }
>
>        /* write as long as TX FIFO has room */
>        while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
>                ep93xx_do_write(espi, t);
>                espi->fifo_level++;
>+
>+               while (ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE) {
>+                       ep93xx_do_read(espi, t);
>+                       espi->fifo_level--;
>+               }
>        }

Exactly what I did.

> Well, you're gonna love this :)
>
> I've run some timing tests on this, and it turns out to give the same
> data transfer speed but take more system CPU time: 64% instead of 60%,
> i.e it is slower.
>
> You are seeing a lower interrupt count, not because more useful work
> is being done in each interrupt, but only because the extra code in
> the inner loop makes the interrupt routine slower. Bear with me...
> 
> I'm using v4 with mika's continuity hack compiled for speed not space
> and averaging the vmstat "sy" output column over 50 seconds while
> block-reading 20 meg with dd from /dev/mmcblk0 to /dev/null using a
> fairly old Sandisk 1MB SD card and clocking at 3.7 MHz.
> All tests report 367 or 368 kB/sec; the variability of the system time
> average in successive runs is about 1%
> 
> Figures are (commas separate values from successive runs)
> v4 with Mika's hack:
>      61.9,60.2%  234724,234727 irq/MB
> with "while" reader in write loop:
>      63.4,64.5%  197772,97801 irq/MB
> with "if" reader in while loop:
>      61.9,62.5%  197845,197847  irq/MB
> with an "if" reader after the write loop:
>      66.0,67.1%  278207,277166 irq/MB
> with a "while" reader after the write loop:
>      67.0%  275000 irq/MB

I am surprised my this :-(.  I thought getting rid of the extra
interrupt context switches would help the data transfer time.  Oh well...

> Further, on a suspicion about the silliness of the per-transfer
> bits_per_word being checked right down the bottom of the lowest lever
> byte-read/writing routine instead of once per transfer, I split
> ep93xx_spi_read and _write into 8 and 16-bit variants, and checked
> t->bits_per_word once outside the read and write loops.
> 
> This gives:
>      60.0% 59.3%  285906 irq/MB

It looks like splitting the 8/16-bit read/write routines does help
with cpu usage compared to the tests above.  Was the data transfer
(kB/sec) any better?

> Note: it takes *more* interrupts to transfer a megabyte when the
> interrupt routine is more efficient!
> 
> The reason is that almost all of those interrupts happen while waiting
> for the last 4, 3, 2 or 1 bytes of a transfer to arrive in the RX
> FIFO. On this dreadful chip there is no interrupt mechanism to say
> "the TX buffer is empty and the received data has finished arriving".
> There is only "the TX buffer is half empty or less" and "the RX buffer
> is half full or more", so repeated interrupts now perform the function
> that the old busy-wait loop performed in v1.

Agree.  Kind of a pain...

> This is another good reason to unite multiple transfers into one
> continuous stream, to have less of this effective busy-waiting with
> interrupts spinning madly.

Yes.  Too bad we can't also combine multiple messages that might be in
the queue...

But, if this gets to complicated it might not be worth holding off
getting it merged, at least into linux-next or possibly into the
staging branch.  At that point it will be easier to provide patches.
I still have one hanging for Mika to expand the chip select options.

> It now occurs to me that another step in CPU efficiency could be had
> by abusing the receive-fifo-is-half-full interrupt to signal the
> completion of a transfer. This would only work for transfers of four
> or more words and would need some careful jiggery-pokery at end of
> transfer to turn the tx-fifo-is-half-empty interrupt enable off and
> ensure that exactly four words would end up in the RX FIFO.

That might work but I think it could break horribly.  The "jiggery-pokery"
could end up being pretty messy.

But, the tx-fifo-is-half-empty might be what is needed to handle the
multiple transfer merging.  We know the driver is finished transfering
the data to the fifo when (espi->tx == t->len).  At this point we are
just wating for the last (fifo_level) bytes to come in on the rx fifo,
this could be anything from 1 to 8 bytes.  If it's <= 4 the next interrupt
will be a tx-fifo-is-half-empty which is killing us trying to pull those
last bytes out of the rx fifo.  So how about something like this at the
end of ep93xx_spi_read_write:

	if (can_continue && espi->tx == t->len) {
		if (fifo_level < SPI_FIFO_SIZE/2) {
			/*
			 * Pull the next transfer out of the queue and
			 * use it to finish filling the tx fifo.  The
			 * next interrupt will complete this transfer.
			 * We then need to continue with the next transfer.
			 */
		}
	}

> It's a horrible thought, and I suspect that the DMA engine is the real answer.

The DMA engine might help but it's not here yet....

Regards,
Hartley

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-22 17:39                                 ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-22 17:39 UTC (permalink / raw)
  To: linux-arm-kernel

Martin,

I'm replying to both of your previous messages.

On Thursday, April 22, 2010 7:28 AM, Martin Guy wrote:
> On 4/22/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
>>  First, every spi transaction, including a single byte transfer, is
>>  going to generate at least two interrupts.  One when the interrupts
>>  are first enabled because the TX FIFO is empty.  And a second when
>>  that byte has been transferred and the TX FIFO is again empty.
>>
>>  The first interrupt can be prevented by priming the TX FIFO before
>>  enabling the interrupts.  All you need to do is call ep93xx_spi_read_write
>>  right before ep93xx_spi_enable_interrupts.
>
> Nice. That increases the data throughput from 367 to 372 kB/sec and
> reduces the CPU usage from 61 to 60.2% for large transfers

I figured "priming the fifo" before turning the transfer over to the
interrupt handler would help.

On Thursday, April 22, 2010 7:12 AM, Martin Guy wrote:
>>  Second, at high clock rates the RX FIFO will actually start to
>>  fill as you are putting data into the TX FIFO.  If you add an inner
>>  reader loop to the writer loop in ep93xx_spi_read_write you can
>>  take advantage of this and reduce the number of interrupts generated
>>  for large transfers.
>>
>>  For instance the mmc_spi driver regularly does 3 transfer messages
>>  where the last transfer is a 512 byte read.  With your current v4
>>  driver this message averages 69 interrupts to complete.  By adding
>>  the inner reader it reduces the number of interrupts to an average
>>  of 40.
>
> I assume you mean something like
>
>        /* read as long as RX FIFO has frames in it */
>        while (ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE) {
>                ep93xx_do_read(espi, t);
>                espi->fifo_level--;
>        }
>
>        /* write as long as TX FIFO has room */
>        while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
>                ep93xx_do_write(espi, t);
>                espi->fifo_level++;
>+
>+               while (ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE) {
>+                       ep93xx_do_read(espi, t);
>+                       espi->fifo_level--;
>+               }
>        }

Exactly what I did.

> Well, you're gonna love this :)
>
> I've run some timing tests on this, and it turns out to give the same
> data transfer speed but take more system CPU time: 64% instead of 60%,
> i.e it is slower.
>
> You are seeing a lower interrupt count, not because more useful work
> is being done in each interrupt, but only because the extra code in
> the inner loop makes the interrupt routine slower. Bear with me...
> 
> I'm using v4 with mika's continuity hack compiled for speed not space
> and averaging the vmstat "sy" output column over 50 seconds while
> block-reading 20 meg with dd from /dev/mmcblk0 to /dev/null using a
> fairly old Sandisk 1MB SD card and clocking at 3.7 MHz.
> All tests report 367 or 368 kB/sec; the variability of the system time
> average in successive runs is about 1%
> 
> Figures are (commas separate values from successive runs)
> v4 with Mika's hack:
>      61.9,60.2%  234724,234727 irq/MB
> with "while" reader in write loop:
>      63.4,64.5%  197772,97801 irq/MB
> with "if" reader in while loop:
>      61.9,62.5%  197845,197847  irq/MB
> with an "if" reader after the write loop:
>      66.0,67.1%  278207,277166 irq/MB
> with a "while" reader after the write loop:
>      67.0%  275000 irq/MB

I am surprised my this :-(.  I thought getting rid of the extra
interrupt context switches would help the data transfer time.  Oh well...

> Further, on a suspicion about the silliness of the per-transfer
> bits_per_word being checked right down the bottom of the lowest lever
> byte-read/writing routine instead of once per transfer, I split
> ep93xx_spi_read and _write into 8 and 16-bit variants, and checked
> t->bits_per_word once outside the read and write loops.
> 
> This gives:
>      60.0% 59.3%  285906 irq/MB

It looks like splitting the 8/16-bit read/write routines does help
with cpu usage compared to the tests above.  Was the data transfer
(kB/sec) any better?

> Note: it takes *more* interrupts to transfer a megabyte when the
> interrupt routine is more efficient!
> 
> The reason is that almost all of those interrupts happen while waiting
> for the last 4, 3, 2 or 1 bytes of a transfer to arrive in the RX
> FIFO. On this dreadful chip there is no interrupt mechanism to say
> "the TX buffer is empty and the received data has finished arriving".
> There is only "the TX buffer is half empty or less" and "the RX buffer
> is half full or more", so repeated interrupts now perform the function
> that the old busy-wait loop performed in v1.

Agree.  Kind of a pain...

> This is another good reason to unite multiple transfers into one
> continuous stream, to have less of this effective busy-waiting with
> interrupts spinning madly.

Yes.  Too bad we can't also combine multiple messages that might be in
the queue...

But, if this gets to complicated it might not be worth holding off
getting it merged, at least into linux-next or possibly into the
staging branch.  At that point it will be easier to provide patches.
I still have one hanging for Mika to expand the chip select options.

> It now occurs to me that another step in CPU efficiency could be had
> by abusing the receive-fifo-is-half-full interrupt to signal the
> completion of a transfer. This would only work for transfers of four
> or more words and would need some careful jiggery-pokery at end of
> transfer to turn the tx-fifo-is-half-empty interrupt enable off and
> ensure that exactly four words would end up in the RX FIFO.

That might work but I think it could break horribly.  The "jiggery-pokery"
could end up being pretty messy.

But, the tx-fifo-is-half-empty might be what is needed to handle the
multiple transfer merging.  We know the driver is finished transfering
the data to the fifo when (espi->tx == t->len).  At this point we are
just wating for the last (fifo_level) bytes to come in on the rx fifo,
this could be anything from 1 to 8 bytes.  If it's <= 4 the next interrupt
will be a tx-fifo-is-half-empty which is killing us trying to pull those
last bytes out of the rx fifo.  So how about something like this@the
end of ep93xx_spi_read_write:

	if (can_continue && espi->tx == t->len) {
		if (fifo_level < SPI_FIFO_SIZE/2) {
			/*
			 * Pull the next transfer out of the queue and
			 * use it to finish filling the tx fifo.  The
			 * next interrupt will complete this transfer.
			 * We then need to continue with the next transfer.
			 */
		}
	}

> It's a horrible thought, and I suspect that the DMA engine is the real answer.

The DMA engine might help but it's not here yet....

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21 18:00                                 ` H Hartley Sweeten
@ 2010-04-22 17:55                                     ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-22 17:55 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Wed, Apr 21, 2010 at 01:00:56PM -0500, H Hartley Sweeten wrote:
>  
> Same results are your v4 driver.  But, I think your on the right track.
> 
> I think the problem is in the ep93xx_spi_read_write routine.  That function
> returns 0 as long as there is still data left in the current transfer.  The
> only time it doesn't return 0, which will cause the can_continue, is when:
> 
> 	if (espi->rx == t->len) {
> 		msg->actual_length += t->len;
> 		return t->len;
> 	}
> 
> At this point the tx and rx fifos will both be empty, which causes the SSP
> peripheral to raise the SFRM signal.

Hi again,

I crafted up next hack. It includes also your priming the FIFO
finding (thanks for that). Following patch is against v4 version
of the driver.

It performs another read/write after given transfer is finished.
I'm hoping that it could make it before SFRMOUT is deasserted.

Could you test this in your setup?

Thanks,
MW

diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
index 310032d..7a5c89e 100644
--- a/drivers/spi/ep93xx_spi.c
+++ b/drivers/spi/ep93xx_spi.c
@@ -105,6 +105,7 @@ struct ep93xx_spi {
 	int				irq;
 	unsigned long			min_rate;
 	unsigned long			max_rate;
+	bool				continuous;
 	bool				running;
 	struct workqueue_struct		*wq;
 	struct work_struct		msg_work;
@@ -380,6 +381,7 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 	struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
 	struct spi_transfer *t;
 	unsigned long flags;
+	bool continuous = true;
 
 	if (!msg || !msg->complete)
 		return -EINVAL;
@@ -389,9 +391,19 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 		if (t->bits_per_word) {
 			if (t->bits_per_word < 4 || t->bits_per_word > 16)
 				return -EINVAL;
+			continuous = false;
 		}
-		if (t->speed_hz && t->speed_hz < espi->min_rate)
+		if (t->speed_hz) {
+			if (t->speed_hz < espi->min_rate)
 				return -EINVAL;
+			continuous = false;
+		}
+		if (t->cs_change) {
+			if (!list_is_last(&t->transfer_list, &msg->transfers))
+				continuous = false;
+		}
+		if (t->delay_usecs)
+			continuous = false;
 	}
 
 	/*
@@ -399,8 +411,11 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 	 * suitable for us. We use @msg->status to signal whether there was
 	 * error in transfer and @msg->state is used to hold pointer to the
 	 * current transfer (or %NULL if no active current transfer).
+	 *
+	 * We hold continuation information in @msg->state while it is not
+	 * processed.
 	 */
-	msg->state = NULL;
+	msg->state = (void *)continuous;
 	msg->status = 0;
 	msg->actual_length = 0;
 
@@ -550,6 +565,91 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
 		ep93xx_spi_chip_setup(espi, chip);
 }
 
+/**
+ * bits_per_word() - returns bits per word for current message
+ */
+static inline int bits_per_word(const struct ep93xx_spi *espi)
+{
+	struct spi_message *msg = espi->current_msg;
+	struct spi_transfer *t = msg->state;
+
+	return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
+}
+
+static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+	if (bits_per_word(espi) > 8) {
+		u16 tx_val = 0;
+
+		if (t->tx_buf)
+			tx_val = ((u16 *)t->tx_buf)[espi->tx];
+		ep93xx_spi_write_u16(espi, SSPDR, tx_val);
+		espi->tx += sizeof(tx_val);
+	} else {
+		u8 tx_val = 0;
+
+		if (t->tx_buf)
+			tx_val = ((u8 *)t->tx_buf)[espi->tx];
+		ep93xx_spi_write_u8(espi, SSPDR, tx_val);
+		espi->tx += sizeof(tx_val);
+	}
+}
+
+static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+	if (bits_per_word(espi) > 8) {
+		u16 rx_val;
+
+		rx_val = ep93xx_spi_read_u16(espi, SSPDR);
+		if (t->rx_buf)
+			((u16 *)t->rx_buf)[espi->rx] = rx_val;
+		espi->rx += sizeof(rx_val);
+	} else {
+		u8 rx_val;
+
+		rx_val = ep93xx_spi_read_u8(espi, SSPDR);
+		if (t->rx_buf)
+			((u8 *)t->rx_buf)[espi->rx] = rx_val;
+		espi->rx += sizeof(rx_val);
+	}
+}
+
+/**
+ * ep93xx_spi_read_write() - perform next RX/TX transfer
+ * @espi: ep93xx SPI controller struct
+ *
+ * This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
+ * called several times, the whole transfer will be completed. Returns %0 when
+ * current transfer was not yet completed otherwise length of the transfer
+ * (>%0). When this function is finished, RX FIFO should be empty and TX FIFO
+ * should be full.
+ */
+static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
+{
+	struct spi_message *msg = espi->current_msg;
+	struct spi_transfer *t = msg->state;
+
+	/* read as long as RX FIFO has frames in it */
+	while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
+		ep93xx_do_read(espi, t);
+		espi->fifo_level--;
+	}
+
+	/* write as long as TX FIFO has room */
+	while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
+		ep93xx_do_write(espi, t);
+		espi->fifo_level++;
+	}
+
+	if (espi->rx == t->len) {
+		msg->actual_length += t->len;
+		return t->len;
+	}
+
+	return 0;
+}
+
+
 /*
  * ep93xx_spi_process_message() - process one SPI message
  * @espi: ep93xx SPI controller struct
@@ -569,6 +669,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
 	struct spi_transfer *t;
 	int err;
 
+	espi->continuous = (bool)msg->state;
+
 	/*
 	 * Enable the SPI controller and its clock.
 	 */
@@ -606,12 +708,43 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
 	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
 	ep93xx_spi_select_device(espi, msg->spi);
 
-	list_for_each_entry(t, &msg->transfers, transfer_list) {
-		ep93xx_spi_process_transfer(espi, msg, t);
-		if (msg->status)
-			break;
+	if (espi->continuous) {
+		/*
+		 * We can transfer all the transfers continuously.
+		 */
+		espi->rx = 0;
+		espi->tx = 0;
+		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
+					transfer_list);
+
+		/* prime the first transfer */
+		if (ep93xx_spi_read_write(espi)) {
+			/*
+			 * Transfer was completed. Pick next one and continue
+			 * if necessary.
+			 */
+			t = msg->state;
+			if (list_is_last(&t->transfer_list, &msg->transfers))
+				goto done;
+
+			espi->rx = 0;
+			espi->tx = 0;
+			msg->state = list_entry(t->transfer_list.next,
+						struct spi_transfer,
+						transfer_list);
+		}
+
+		ep93xx_spi_enable_interrupts(espi);
+		wait_for_completion(&espi->wait);
+	} else {
+		list_for_each_entry(t, &msg->transfers, transfer_list) {
+			ep93xx_spi_process_transfer(espi, msg, t);
+			if (msg->status)
+				break;
+		}
 	}
 
+done:
 	/*
 	 * Now the whole message is transferred (or failed for some reason). We
 	 * deselect the device and disable the SPI controller.
@@ -667,90 +800,6 @@ static void ep93xx_spi_work(struct work_struct *work)
 }
 
 /**
- * bits_per_word() - returns bits per word for current message
- */
-static inline int bits_per_word(const struct ep93xx_spi *espi)
-{
-	struct spi_message *msg = espi->current_msg;
-	struct spi_transfer *t = msg->state;
-
-	return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
-}
-
-static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
-{
-	if (bits_per_word(espi) > 8) {
-		u16 tx_val = 0;
-
-		if (t->tx_buf)
-			tx_val = ((u16 *)t->tx_buf)[espi->tx];
-		ep93xx_spi_write_u16(espi, SSPDR, tx_val);
-		espi->tx += sizeof(tx_val);
-	} else {
-		u8 tx_val = 0;
-
-		if (t->tx_buf)
-			tx_val = ((u8 *)t->tx_buf)[espi->tx];
-		ep93xx_spi_write_u8(espi, SSPDR, tx_val);
-		espi->tx += sizeof(tx_val);
-	}
-}
-
-static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
-{
-	if (bits_per_word(espi) > 8) {
-		u16 rx_val;
-
-		rx_val = ep93xx_spi_read_u16(espi, SSPDR);
-		if (t->rx_buf)
-			((u16 *)t->rx_buf)[espi->rx] = rx_val;
-		espi->rx += sizeof(rx_val);
-	} else {
-		u8 rx_val;
-
-		rx_val = ep93xx_spi_read_u8(espi, SSPDR);
-		if (t->rx_buf)
-			((u8 *)t->rx_buf)[espi->rx] = rx_val;
-		espi->rx += sizeof(rx_val);
-	}
-}
-
-/**
- * ep93xx_spi_read_write() - perform next RX/TX transfer
- * @espi: ep93xx SPI controller struct
- *
- * This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
- * called several times, the whole transfer will be completed. Returns %0 when
- * current transfer was not yet completed otherwise length of the transfer
- * (>%0). When this function is finished, RX FIFO should be empty and TX FIFO
- * should be full.
- */
-static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
-{
-	struct spi_message *msg = espi->current_msg;
-	struct spi_transfer *t = msg->state;
-
-	/* read as long as RX FIFO has frames in it */
-	while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
-		ep93xx_do_read(espi, t);
-		espi->fifo_level--;
-	}
-
-	/* write as long as TX FIFO has room */
-	while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
-		ep93xx_do_write(espi, t);
-		espi->fifo_level++;
-	}
-
-	if (espi->rx == t->len) {
-		msg->actual_length += t->len;
-		return t->len;
-	}
-
-	return 0;
-}
-
-/**
  * ep93xx_spi_interrupt() - SPI interrupt handler
  * @irq: IRQ number (not used)
  * @dev_id: pointer to EP93xx controller struct
@@ -792,6 +841,27 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
 			 * interrupt then.
 			 */
 			return IRQ_HANDLED;
+		} else {
+			struct spi_message *msg = espi->current_msg;
+			struct spi_transfer *t = msg->state;
+
+			if (!espi->continuous)
+				goto done;
+
+			if (!list_is_last(&t->transfer_list, &msg->transfers)) {
+				/*
+				 * Pick next transfer and refill the FIFO.
+				 */
+				msg->state = list_entry(t->transfer_list.next,
+							struct spi_transfer,
+							transfer_list);
+				espi->rx = 0;
+				espi->tx = 0;
+
+				ep93xx_spi_read_write(espi);
+				return IRQ_HANDLED;
+			}
+			/* we are done here */
 		}
 	}
 
@@ -800,6 +870,7 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
 	 * any case we disable interrupts and notify the worker to handle
 	 * any post-processing of the message.
 	 */
+done:
 	ep93xx_spi_disable_interrupts(espi);
 	complete(&espi->wait);
 	return IRQ_HANDLED;

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-22 17:55                                     ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-22 17:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 21, 2010 at 01:00:56PM -0500, H Hartley Sweeten wrote:
>  
> Same results are your v4 driver.  But, I think your on the right track.
> 
> I think the problem is in the ep93xx_spi_read_write routine.  That function
> returns 0 as long as there is still data left in the current transfer.  The
> only time it doesn't return 0, which will cause the can_continue, is when:
> 
> 	if (espi->rx == t->len) {
> 		msg->actual_length += t->len;
> 		return t->len;
> 	}
> 
> At this point the tx and rx fifos will both be empty, which causes the SSP
> peripheral to raise the SFRM signal.

Hi again,

I crafted up next hack. It includes also your priming the FIFO
finding (thanks for that). Following patch is against v4 version
of the driver.

It performs another read/write after given transfer is finished.
I'm hoping that it could make it before SFRMOUT is deasserted.

Could you test this in your setup?

Thanks,
MW

diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c
index 310032d..7a5c89e 100644
--- a/drivers/spi/ep93xx_spi.c
+++ b/drivers/spi/ep93xx_spi.c
@@ -105,6 +105,7 @@ struct ep93xx_spi {
 	int				irq;
 	unsigned long			min_rate;
 	unsigned long			max_rate;
+	bool				continuous;
 	bool				running;
 	struct workqueue_struct		*wq;
 	struct work_struct		msg_work;
@@ -380,6 +381,7 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 	struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
 	struct spi_transfer *t;
 	unsigned long flags;
+	bool continuous = true;
 
 	if (!msg || !msg->complete)
 		return -EINVAL;
@@ -389,9 +391,19 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 		if (t->bits_per_word) {
 			if (t->bits_per_word < 4 || t->bits_per_word > 16)
 				return -EINVAL;
+			continuous = false;
 		}
-		if (t->speed_hz && t->speed_hz < espi->min_rate)
+		if (t->speed_hz) {
+			if (t->speed_hz < espi->min_rate)
 				return -EINVAL;
+			continuous = false;
+		}
+		if (t->cs_change) {
+			if (!list_is_last(&t->transfer_list, &msg->transfers))
+				continuous = false;
+		}
+		if (t->delay_usecs)
+			continuous = false;
 	}
 
 	/*
@@ -399,8 +411,11 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 	 * suitable for us. We use @msg->status to signal whether there was
 	 * error in transfer and @msg->state is used to hold pointer to the
 	 * current transfer (or %NULL if no active current transfer).
+	 *
+	 * We hold continuation information in @msg->state while it is not
+	 * processed.
 	 */
-	msg->state = NULL;
+	msg->state = (void *)continuous;
 	msg->status = 0;
 	msg->actual_length = 0;
 
@@ -550,6 +565,91 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
 		ep93xx_spi_chip_setup(espi, chip);
 }
 
+/**
+ * bits_per_word() - returns bits per word for current message
+ */
+static inline int bits_per_word(const struct ep93xx_spi *espi)
+{
+	struct spi_message *msg = espi->current_msg;
+	struct spi_transfer *t = msg->state;
+
+	return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
+}
+
+static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+	if (bits_per_word(espi) > 8) {
+		u16 tx_val = 0;
+
+		if (t->tx_buf)
+			tx_val = ((u16 *)t->tx_buf)[espi->tx];
+		ep93xx_spi_write_u16(espi, SSPDR, tx_val);
+		espi->tx += sizeof(tx_val);
+	} else {
+		u8 tx_val = 0;
+
+		if (t->tx_buf)
+			tx_val = ((u8 *)t->tx_buf)[espi->tx];
+		ep93xx_spi_write_u8(espi, SSPDR, tx_val);
+		espi->tx += sizeof(tx_val);
+	}
+}
+
+static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
+{
+	if (bits_per_word(espi) > 8) {
+		u16 rx_val;
+
+		rx_val = ep93xx_spi_read_u16(espi, SSPDR);
+		if (t->rx_buf)
+			((u16 *)t->rx_buf)[espi->rx] = rx_val;
+		espi->rx += sizeof(rx_val);
+	} else {
+		u8 rx_val;
+
+		rx_val = ep93xx_spi_read_u8(espi, SSPDR);
+		if (t->rx_buf)
+			((u8 *)t->rx_buf)[espi->rx] = rx_val;
+		espi->rx += sizeof(rx_val);
+	}
+}
+
+/**
+ * ep93xx_spi_read_write() - perform next RX/TX transfer
+ * @espi: ep93xx SPI controller struct
+ *
+ * This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
+ * called several times, the whole transfer will be completed. Returns %0 when
+ * current transfer was not yet completed otherwise length of the transfer
+ * (>%0). When this function is finished, RX FIFO should be empty and TX FIFO
+ * should be full.
+ */
+static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
+{
+	struct spi_message *msg = espi->current_msg;
+	struct spi_transfer *t = msg->state;
+
+	/* read as long as RX FIFO has frames in it */
+	while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
+		ep93xx_do_read(espi, t);
+		espi->fifo_level--;
+	}
+
+	/* write as long as TX FIFO has room */
+	while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
+		ep93xx_do_write(espi, t);
+		espi->fifo_level++;
+	}
+
+	if (espi->rx == t->len) {
+		msg->actual_length += t->len;
+		return t->len;
+	}
+
+	return 0;
+}
+
+
 /*
  * ep93xx_spi_process_message() - process one SPI message
  * @espi: ep93xx SPI controller struct
@@ -569,6 +669,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
 	struct spi_transfer *t;
 	int err;
 
+	espi->continuous = (bool)msg->state;
+
 	/*
 	 * Enable the SPI controller and its clock.
 	 */
@@ -606,12 +708,43 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
 	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
 	ep93xx_spi_select_device(espi, msg->spi);
 
-	list_for_each_entry(t, &msg->transfers, transfer_list) {
-		ep93xx_spi_process_transfer(espi, msg, t);
-		if (msg->status)
-			break;
+	if (espi->continuous) {
+		/*
+		 * We can transfer all the transfers continuously.
+		 */
+		espi->rx = 0;
+		espi->tx = 0;
+		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
+					transfer_list);
+
+		/* prime the first transfer */
+		if (ep93xx_spi_read_write(espi)) {
+			/*
+			 * Transfer was completed. Pick next one and continue
+			 * if necessary.
+			 */
+			t = msg->state;
+			if (list_is_last(&t->transfer_list, &msg->transfers))
+				goto done;
+
+			espi->rx = 0;
+			espi->tx = 0;
+			msg->state = list_entry(t->transfer_list.next,
+						struct spi_transfer,
+						transfer_list);
+		}
+
+		ep93xx_spi_enable_interrupts(espi);
+		wait_for_completion(&espi->wait);
+	} else {
+		list_for_each_entry(t, &msg->transfers, transfer_list) {
+			ep93xx_spi_process_transfer(espi, msg, t);
+			if (msg->status)
+				break;
+		}
 	}
 
+done:
 	/*
 	 * Now the whole message is transferred (or failed for some reason). We
 	 * deselect the device and disable the SPI controller.
@@ -667,90 +800,6 @@ static void ep93xx_spi_work(struct work_struct *work)
 }
 
 /**
- * bits_per_word() - returns bits per word for current message
- */
-static inline int bits_per_word(const struct ep93xx_spi *espi)
-{
-	struct spi_message *msg = espi->current_msg;
-	struct spi_transfer *t = msg->state;
-
-	return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
-}
-
-static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
-{
-	if (bits_per_word(espi) > 8) {
-		u16 tx_val = 0;
-
-		if (t->tx_buf)
-			tx_val = ((u16 *)t->tx_buf)[espi->tx];
-		ep93xx_spi_write_u16(espi, SSPDR, tx_val);
-		espi->tx += sizeof(tx_val);
-	} else {
-		u8 tx_val = 0;
-
-		if (t->tx_buf)
-			tx_val = ((u8 *)t->tx_buf)[espi->tx];
-		ep93xx_spi_write_u8(espi, SSPDR, tx_val);
-		espi->tx += sizeof(tx_val);
-	}
-}
-
-static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
-{
-	if (bits_per_word(espi) > 8) {
-		u16 rx_val;
-
-		rx_val = ep93xx_spi_read_u16(espi, SSPDR);
-		if (t->rx_buf)
-			((u16 *)t->rx_buf)[espi->rx] = rx_val;
-		espi->rx += sizeof(rx_val);
-	} else {
-		u8 rx_val;
-
-		rx_val = ep93xx_spi_read_u8(espi, SSPDR);
-		if (t->rx_buf)
-			((u8 *)t->rx_buf)[espi->rx] = rx_val;
-		espi->rx += sizeof(rx_val);
-	}
-}
-
-/**
- * ep93xx_spi_read_write() - perform next RX/TX transfer
- * @espi: ep93xx SPI controller struct
- *
- * This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
- * called several times, the whole transfer will be completed. Returns %0 when
- * current transfer was not yet completed otherwise length of the transfer
- * (>%0). When this function is finished, RX FIFO should be empty and TX FIFO
- * should be full.
- */
-static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
-{
-	struct spi_message *msg = espi->current_msg;
-	struct spi_transfer *t = msg->state;
-
-	/* read as long as RX FIFO has frames in it */
-	while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
-		ep93xx_do_read(espi, t);
-		espi->fifo_level--;
-	}
-
-	/* write as long as TX FIFO has room */
-	while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
-		ep93xx_do_write(espi, t);
-		espi->fifo_level++;
-	}
-
-	if (espi->rx == t->len) {
-		msg->actual_length += t->len;
-		return t->len;
-	}
-
-	return 0;
-}
-
-/**
  * ep93xx_spi_interrupt() - SPI interrupt handler
  * @irq: IRQ number (not used)
  * @dev_id: pointer to EP93xx controller struct
@@ -792,6 +841,27 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
 			 * interrupt then.
 			 */
 			return IRQ_HANDLED;
+		} else {
+			struct spi_message *msg = espi->current_msg;
+			struct spi_transfer *t = msg->state;
+
+			if (!espi->continuous)
+				goto done;
+
+			if (!list_is_last(&t->transfer_list, &msg->transfers)) {
+				/*
+				 * Pick next transfer and refill the FIFO.
+				 */
+				msg->state = list_entry(t->transfer_list.next,
+							struct spi_transfer,
+							transfer_list);
+				espi->rx = 0;
+				espi->tx = 0;
+
+				ep93xx_spi_read_write(espi);
+				return IRQ_HANDLED;
+			}
+			/* we are done here */
 		}
 	}
 
@@ -800,6 +870,7 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
 	 * any case we disable interrupts and notify the worker to handle
 	 * any post-processing of the message.
 	 */
+done:
 	ep93xx_spi_disable_interrupts(espi);
 	complete(&espi->wait);
 	return IRQ_HANDLED;

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-22 17:39                                 ` H Hartley Sweeten
@ 2010-04-22 20:19                                     ` Martin Guy
  -1 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-22 20:19 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 4/22/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
>  > Further, on a suspicion about the silliness of the per-transfer
>  > bits_per_word being checked right down the bottom of the lowest lever
>  > byte-read/writing routine instead of once per transfer, I split
>  > ep93xx_spi_read and _write into 8 and 16-bit variants, and checked
>  > t->bits_per_word once outside the read and write loops.
>  >
>  > This gives:
>  >      60.0% 59.3%  285906 irq/MB
>
>
> It looks like splitting the 8/16-bit read/write routines does help
>  with cpu usage compared to the tests above.  Was the data transfer
>  (kB/sec) any better?

No, exactly the same.

>From a code poin tof view, one of the routines is just
if (bits > 8) {
   this16
} else {
   that8
}
so no loss in splitting it. You need two copies of the read and write
loops in the read_write routine, though it's only 8 extra lines of
code for a 1% CPU increase.
I don't have strong feelings about this it way.

> Yes.  Too bad we can't also combine multiple messages that might be in
>  the queue...

I wonder if it might be easier, if there are several parts to a
message, to just cook up  one big new transfer, copy the data into it
and just do that. It would mean copying every data block of course
since in the MMC/SD case they are 512+2+1.

>  But, if this gets to complicated it might not be worth holding off
>  getting it merged
Possibly. It depends on the timing of the merge windows. The current
code works with some devices.

>  > It now occurs to me that another step in CPU efficiency could be had
>  > by abusing the receive-fifo-is-half-full interrupt to signal the
>  > completion of a transfer. This would only work for transfers of four
>  > or more words and would need some careful jiggery-pokery at end of
>  > transfer to turn the tx-fifo-is-half-empty interrupt enable off and
>  > ensure that exactly four words would end up in the RX FIFO.
>
> That might work but I think it could break horribly.  The "jiggery-pokery"
>  could end up being pretty messy.

Yes. It is looking nasty and it would make a mess of the place where
the continuity stuff needs to happen to achieve actual functionality
improvements.

To get some idea of the potential wins I've been instrumenting the
code today to see how many interrupts it takes to receive the last 4
words
At 3.7MHz I'm seeing up to 3 interrupts waiting for the final draining
to happen, with an average of 1.36 (1 would be the perfect figure)
At 400kHz it takes up to 26 with an average of 9.92

Me, I only really care about the SD card case, where a half dozen
useless interrupts per 512-byte block is not going to impact on the
CPU usage much. In fact, by making the interrupt routine more complex
it may even end up being more cpu hungry in the end.

On the other hand, slow clock-speed devices are using needless high
CPU, especially if the transfer sizes are small as is typical with
command-response devices.

>  But, the tx-fifo-is-half-empty might be what is needed to handle the
>  multiple transfer merging.  We know the driver is finished transfering
>  the data to the fifo when (espi->tx == t->len).  At this point we are
>  just wating for the last (fifo_level) bytes to come in on the rx fifo,
>  this could be anything from 1 to 8 bytes.

Another instrumentation show that yes, at 3.7MHz, the data read on
each interrupt is between 1 and 8 words. I'm surprised it gets to 8
full - maybe when the interrupt is requested while some other IRQ
(ether? clock tick?) is already in progress? I'm instrumenting in a
way that shouldn't change the timing characteristics of the transfer
(ie a tiny printk's only after end of transfer)

>  > It's a horrible thought, and I suspect that the DMA engine is the real answer.
>
> The DMA engine might help but it's not here yet....

Yes. What I mean is that the prospect of that happening somewhere in
the future reduces the importance of doing hairy jiggery pokery with
the interrupt version.

     M

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-22 20:19                                     ` Martin Guy
  0 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-22 20:19 UTC (permalink / raw)
  To: linux-arm-kernel

On 4/22/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
>  > Further, on a suspicion about the silliness of the per-transfer
>  > bits_per_word being checked right down the bottom of the lowest lever
>  > byte-read/writing routine instead of once per transfer, I split
>  > ep93xx_spi_read and _write into 8 and 16-bit variants, and checked
>  > t->bits_per_word once outside the read and write loops.
>  >
>  > This gives:
>  >      60.0% 59.3%  285906 irq/MB
>
>
> It looks like splitting the 8/16-bit read/write routines does help
>  with cpu usage compared to the tests above.  Was the data transfer
>  (kB/sec) any better?

No, exactly the same.

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

* RE: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-22 17:55                                     ` Mika Westerberg
@ 2010-04-22 20:43                                       ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-22 20:43 UTC (permalink / raw)
  To: Mika Westerberg; +Cc: spi-devel-general, Martin Guy, ryan, linux-arm-kernel

On Thursday, April 22, 2010 10:55 AM, Mika Westerberg wrote:
> On Wed, Apr 21, 2010 at 01:00:56PM -0500, H Hartley Sweeten wrote:
>>  
>> Same results are your v4 driver.  But, I think your on the right track.
>> 
>> I think the problem is in the ep93xx_spi_read_write routine.  That function
>> returns 0 as long as there is still data left in the current transfer.  The
>> only time it doesn't return 0, which will cause the can_continue, is when:
>> 
>> 	if (espi->rx == t->len) {
>> 		msg->actual_length += t->len;
>> 		return t->len;
>> 	}
>> 
>> At this point the tx and rx fifos will both be empty, which causes the SSP
>> peripheral to raise the SFRM signal.
>
> Hi again,
>
> I crafted up next hack. It includes also your priming the FIFO
> finding (thanks for that). 

Great!

> Following patch is against v4 version of the driver.
>
> It performs another read/write after given transfer is finished.
> I'm hoping that it could make it before SFRMOUT is deasserted.
> 
> Could you test this in your setup?

Same results.

I hacked your driver to allow me to toggle a gpio when the interrupt routine
starts and exits.

I captured the 4 byte write/2 byte read caused by the spi_write_then_read in
the sst25l driver when it does the Read-ID command.  The chip select goes low
followed by the first 4 byte transfer of the message due to the fifo's getting
primed.  This transfer actually doesn't finish since the rx data has not been
received.  So the interrupts just get enabled as normal.

The data starts transferring when the first byte is placed in the tx fifo.  It
takes about 4.45us to send/receive the 4 bytes.  Approximately 15.9us after the
last byte has been received the interrupt routine starts.  It then takes about
5.7us for the second 2 byte transfer to start.  So there is a total of about
21.6us between the two transfers where SFRM is deasserted.

Let me know if you want the picture posted.

[snip]

> +/**
> + * ep93xx_spi_read_write() - perform next RX/TX transfer
> + * @espi: ep93xx SPI controller struct
> + *
> + * This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
> + * called several times, the whole transfer will be completed. Returns %0 when
> + * current transfer was not yet completed otherwise length of the transfer
> + * (>%0). When this function is finished, RX FIFO should be empty and TX FIFO
> + * should be full.
> + */
> +static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
> +{
> +	struct spi_message *msg = espi->current_msg;
> +	struct spi_transfer *t = msg->state;
> +
> +	/* read as long as RX FIFO has frames in it */
> +	while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
> +		ep93xx_do_read(espi, t);
> +		espi->fifo_level--;
> +	}
> +
> +	/* write as long as TX FIFO has room */
> +	while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
> +		ep93xx_do_write(espi, t);
> +		espi->fifo_level++;
> +	}
> +
> +	if (espi->rx == t->len) {
> +		msg->actual_length += t->len;
> +		return t->len;
> +	}
> +
> +	return 0;
> +}
> +
> +
>  /*
>   * ep93xx_spi_process_message() - process one SPI message
>   * @espi: ep93xx SPI controller struct
> @@ -569,6 +669,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
>  	struct spi_transfer *t;
>  	int err;
>  
> +	espi->continuous = (bool)msg->state;
> +
>  	/*
>  	 * Enable the SPI controller and its clock.
>  	 */
> @@ -606,12 +708,43 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
>  	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
>  	ep93xx_spi_select_device(espi, msg->spi);
>  
> -	list_for_each_entry(t, &msg->transfers, transfer_list) {
> -		ep93xx_spi_process_transfer(espi, msg, t);
> -		if (msg->status)
> -			break;
> +	if (espi->continuous) {
> +		/*
> +		 * We can transfer all the transfers continuously.
> +		 */
> +		espi->rx = 0;
> +		espi->tx = 0;
> +		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
> +					transfer_list);
> +
> +		/* prime the first transfer */
> +		if (ep93xx_spi_read_write(espi)) {

On the first read/write for a transfer this condition can never succeed.

The ep93xx_spi_read_write function first empties the rx fifo then fills the
tx fifo.  Putting any data in the tx fifo means that you are going to have to
come back to empty the rx fifo.

So, the block below never executes.

> +			/*
> +			 * Transfer was completed. Pick next one and continue
> +			 * if necessary.
> +			 */
> +			t = msg->state;
> +			if (list_is_last(&t->transfer_list, &msg->transfers))
> +				goto done;
> +
> +			espi->rx = 0;
> +			espi->tx = 0;
> +			msg->state = list_entry(t->transfer_list.next,
> +						struct spi_transfer,
> +						transfer_list);
> +		}
> +
> +		ep93xx_spi_enable_interrupts(espi);
> +		wait_for_completion(&espi->wait);

Even if the first read/write did succeed you are not starting the second transfer.
This is just passing the operation off to the interrupt routine using the second
transfer in the message.

[snip]

> -/**
>   * ep93xx_spi_interrupt() - SPI interrupt handler
>   * @irq: IRQ number (not used)
>   * @dev_id: pointer to EP93xx controller struct
> @@ -792,6 +841,27 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
>  			 * interrupt then.
>  			 */
>  			return IRQ_HANDLED;
> +		} else {
> +			struct spi_message *msg = espi->current_msg;
> +			struct spi_transfer *t = msg->state;
> +
> +			if (!espi->continuous)
> +				goto done;
> +
> +			if (!list_is_last(&t->transfer_list, &msg->transfers)) {
> +				/*
> +				 * Pick next transfer and refill the FIFO.
> +				 */
> +				msg->state = list_entry(t->transfer_list.next,
> +							struct spi_transfer,
> +							transfer_list);
> +				espi->rx = 0;
> +				espi->tx = 0;
> +
> +				ep93xx_spi_read_write(espi);
> +				return IRQ_HANDLED;
> +			}

Here the N transfer has been completed and we are trying to continue with the N+1
transfer.  This should work but I need to figure out a way to capture it with my
logic analyzer.  The only problem is if the N transfer is complete that means the
tx and rx fifos are empty so the SFRM signal is going to be deasserted.  The N+1
transfer might start really soon after but there will still be a glitch in the SFRM
signal.

> +			/* we are done here */

Regards,
Hartley

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-22 20:43                                       ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-22 20:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday, April 22, 2010 10:55 AM, Mika Westerberg wrote:
> On Wed, Apr 21, 2010 at 01:00:56PM -0500, H Hartley Sweeten wrote:
>>  
>> Same results are your v4 driver.  But, I think your on the right track.
>> 
>> I think the problem is in the ep93xx_spi_read_write routine.  That function
>> returns 0 as long as there is still data left in the current transfer.  The
>> only time it doesn't return 0, which will cause the can_continue, is when:
>> 
>> 	if (espi->rx == t->len) {
>> 		msg->actual_length += t->len;
>> 		return t->len;
>> 	}
>> 
>> At this point the tx and rx fifos will both be empty, which causes the SSP
>> peripheral to raise the SFRM signal.
>
> Hi again,
>
> I crafted up next hack. It includes also your priming the FIFO
> finding (thanks for that). 

Great!

> Following patch is against v4 version of the driver.
>
> It performs another read/write after given transfer is finished.
> I'm hoping that it could make it before SFRMOUT is deasserted.
> 
> Could you test this in your setup?

Same results.

I hacked your driver to allow me to toggle a gpio when the interrupt routine
starts and exits.

I captured the 4 byte write/2 byte read caused by the spi_write_then_read in
the sst25l driver when it does the Read-ID command.  The chip select goes low
followed by the first 4 byte transfer of the message due to the fifo's getting
primed.  This transfer actually doesn't finish since the rx data has not been
received.  So the interrupts just get enabled as normal.

The data starts transferring when the first byte is placed in the tx fifo.  It
takes about 4.45us to send/receive the 4 bytes.  Approximately 15.9us after the
last byte has been received the interrupt routine starts.  It then takes about
5.7us for the second 2 byte transfer to start.  So there is a total of about
21.6us between the two transfers where SFRM is deasserted.

Let me know if you want the picture posted.

[snip]

> +/**
> + * ep93xx_spi_read_write() - perform next RX/TX transfer
> + * @espi: ep93xx SPI controller struct
> + *
> + * This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
> + * called several times, the whole transfer will be completed. Returns %0 when
> + * current transfer was not yet completed otherwise length of the transfer
> + * (>%0). When this function is finished, RX FIFO should be empty and TX FIFO
> + * should be full.
> + */
> +static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
> +{
> +	struct spi_message *msg = espi->current_msg;
> +	struct spi_transfer *t = msg->state;
> +
> +	/* read as long as RX FIFO has frames in it */
> +	while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
> +		ep93xx_do_read(espi, t);
> +		espi->fifo_level--;
> +	}
> +
> +	/* write as long as TX FIFO has room */
> +	while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
> +		ep93xx_do_write(espi, t);
> +		espi->fifo_level++;
> +	}
> +
> +	if (espi->rx == t->len) {
> +		msg->actual_length += t->len;
> +		return t->len;
> +	}
> +
> +	return 0;
> +}
> +
> +
>  /*
>   * ep93xx_spi_process_message() - process one SPI message
>   * @espi: ep93xx SPI controller struct
> @@ -569,6 +669,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
>  	struct spi_transfer *t;
>  	int err;
>  
> +	espi->continuous = (bool)msg->state;
> +
>  	/*
>  	 * Enable the SPI controller and its clock.
>  	 */
> @@ -606,12 +708,43 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
>  	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
>  	ep93xx_spi_select_device(espi, msg->spi);
>  
> -	list_for_each_entry(t, &msg->transfers, transfer_list) {
> -		ep93xx_spi_process_transfer(espi, msg, t);
> -		if (msg->status)
> -			break;
> +	if (espi->continuous) {
> +		/*
> +		 * We can transfer all the transfers continuously.
> +		 */
> +		espi->rx = 0;
> +		espi->tx = 0;
> +		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
> +					transfer_list);
> +
> +		/* prime the first transfer */
> +		if (ep93xx_spi_read_write(espi)) {

On the first read/write for a transfer this condition can never succeed.

The ep93xx_spi_read_write function first empties the rx fifo then fills the
tx fifo.  Putting any data in the tx fifo means that you are going to have to
come back to empty the rx fifo.

So, the block below never executes.

> +			/*
> +			 * Transfer was completed. Pick next one and continue
> +			 * if necessary.
> +			 */
> +			t = msg->state;
> +			if (list_is_last(&t->transfer_list, &msg->transfers))
> +				goto done;
> +
> +			espi->rx = 0;
> +			espi->tx = 0;
> +			msg->state = list_entry(t->transfer_list.next,
> +						struct spi_transfer,
> +						transfer_list);
> +		}
> +
> +		ep93xx_spi_enable_interrupts(espi);
> +		wait_for_completion(&espi->wait);

Even if the first read/write did succeed you are not starting the second transfer.
This is just passing the operation off to the interrupt routine using the second
transfer in the message.

[snip]

> -/**
>   * ep93xx_spi_interrupt() - SPI interrupt handler
>   * @irq: IRQ number (not used)
>   * @dev_id: pointer to EP93xx controller struct
> @@ -792,6 +841,27 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
>  			 * interrupt then.
>  			 */
>  			return IRQ_HANDLED;
> +		} else {
> +			struct spi_message *msg = espi->current_msg;
> +			struct spi_transfer *t = msg->state;
> +
> +			if (!espi->continuous)
> +				goto done;
> +
> +			if (!list_is_last(&t->transfer_list, &msg->transfers)) {
> +				/*
> +				 * Pick next transfer and refill the FIFO.
> +				 */
> +				msg->state = list_entry(t->transfer_list.next,
> +							struct spi_transfer,
> +							transfer_list);
> +				espi->rx = 0;
> +				espi->tx = 0;
> +
> +				ep93xx_spi_read_write(espi);
> +				return IRQ_HANDLED;
> +			}

Here the N transfer has been completed and we are trying to continue with the N+1
transfer.  This should work but I need to figure out a way to capture it with my
logic analyzer.  The only problem is if the N transfer is complete that means the
tx and rx fifos are empty so the SFRM signal is going to be deasserted.  The N+1
transfer might start really soon after but there will still be a glitch in the SFRM
signal.

> +			/* we are done here */

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-22  5:45                                     ` Mika Westerberg
@ 2010-04-22 21:29                                         ` Ryan Mallon
  -1 siblings, 0 replies; 89+ messages in thread
From: Ryan Mallon @ 2010-04-22 21:29 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Mika Westerberg wrote:
> On Wed, Apr 21, 2010 at 01:00:56PM -0500, H Hartley Sweeten wrote:
>> Same results are your v4 driver.  But, I think your on the right track.
> 
> Thanks for testing.
> 
>> I think the problem is in the ep93xx_spi_read_write routine.  That function
>> returns 0 as long as there is still data left in the current transfer.  The
>> only time it doesn't return 0, which will cause the can_continue, is when:
>>
>> 	if (espi->rx == t->len) {
>> 		msg->actual_length += t->len;
>> 		return t->len;
>> 	}
>>
>> At this point the tx and rx fifos will both be empty, which causes the SSP
>> peripheral to raise the SFRM signal.
> 
> True.
> 
>> A picture is worth a thousand words... Attached is a logic analyzer capture
>> of the Read-ID command and response from the SPI Flash.  EGPIO7 is my chip
>> select to the flash.  The first 4 SPI MOSI (Tx) blocks are the 0x90, 0x00,
>> 0x00, 0x00 command to the flash.  You will notice that the SFRM line is
>> asserted for those bytes.  A bit later are the 2 SPI MISO (Rx) responses
>> from the flash with the ManID/DevID, again with the SFRM line asserted.
> 
> Yeah, it clearly shows that SFRMOUT is deasserted between transfers :(
> 
> I will try to work out some sort of hack which will keep the FIFOs from
> emptying.
> 
> MW

I still have not found time to test this, but I think this is the
problem we had we resulted in us using polling mode rather than
interrupts. If the spi fifo empties then it will deassert the frame
signal. By using polling code we could ensure that the fifos would not
drain at the incorrect time. The other solution is to use an externally
drivable signal for the frame (such as a gpio), but this is obviously
not possible on some existing hardware.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan-7Wk5F4Od5/oYd5yxfr4S2w@public.gmane.org         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-22 21:29                                         ` Ryan Mallon
  0 siblings, 0 replies; 89+ messages in thread
From: Ryan Mallon @ 2010-04-22 21:29 UTC (permalink / raw)
  To: linux-arm-kernel

Mika Westerberg wrote:
> On Wed, Apr 21, 2010 at 01:00:56PM -0500, H Hartley Sweeten wrote:
>> Same results are your v4 driver.  But, I think your on the right track.
> 
> Thanks for testing.
> 
>> I think the problem is in the ep93xx_spi_read_write routine.  That function
>> returns 0 as long as there is still data left in the current transfer.  The
>> only time it doesn't return 0, which will cause the can_continue, is when:
>>
>> 	if (espi->rx == t->len) {
>> 		msg->actual_length += t->len;
>> 		return t->len;
>> 	}
>>
>> At this point the tx and rx fifos will both be empty, which causes the SSP
>> peripheral to raise the SFRM signal.
> 
> True.
> 
>> A picture is worth a thousand words... Attached is a logic analyzer capture
>> of the Read-ID command and response from the SPI Flash.  EGPIO7 is my chip
>> select to the flash.  The first 4 SPI MOSI (Tx) blocks are the 0x90, 0x00,
>> 0x00, 0x00 command to the flash.  You will notice that the SFRM line is
>> asserted for those bytes.  A bit later are the 2 SPI MISO (Rx) responses
>> from the flash with the ManID/DevID, again with the SFRM line asserted.
> 
> Yeah, it clearly shows that SFRMOUT is deasserted between transfers :(
> 
> I will try to work out some sort of hack which will keep the FIFOs from
> emptying.
> 
> MW

I still have not found time to test this, but I think this is the
problem we had we resulted in us using polling mode rather than
interrupts. If the spi fifo empties then it will deassert the frame
signal. By using polling code we could ensure that the fifos would not
drain at the incorrect time. The other solution is to use an externally
drivable signal for the frame (such as a gpio), but this is obviously
not possible on some existing hardware.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan at bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-22 20:43                                       ` H Hartley Sweeten
@ 2010-04-23  5:20                                           ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-23  5:20 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Thu, Apr 22, 2010 at 03:43:24PM -0500, H Hartley Sweeten wrote:
> On Thursday, April 22, 2010 10:55 AM, Mika Westerberg wrote:
> > Could you test this in your setup?
> 
> Same results.

OK. thanks for testing.

> I hacked your driver to allow me to toggle a gpio when the interrupt routine
> starts and exits.
> 
> I captured the 4 byte write/2 byte read caused by the spi_write_then_read in
> the sst25l driver when it does the Read-ID command.  The chip select goes low
> followed by the first 4 byte transfer of the message due to the fifo's getting
> primed.  This transfer actually doesn't finish since the rx data has not been
> received.  So the interrupts just get enabled as normal.
> 
> The data starts transferring when the first byte is placed in the tx fifo.  It
> takes about 4.45us to send/receive the 4 bytes.  Approximately 15.9us after the
> last byte has been received the interrupt routine starts.  It then takes about
> 5.7us for the second 2 byte transfer to start.  So there is a total of about
> 21.6us between the two transfers where SFRM is deasserted.

If I understand this correctly, for this particular message it might have worked if
the priming is not done? What I mean is that if we start the transfer in interrupt
handler and after the transfer is finished, immediately continue with the next one
(like in the patch) could it make SFRM to stay asserted (at least shorten the gap)?

> >  /*
> >   * ep93xx_spi_process_message() - process one SPI message
> >   * @espi: ep93xx SPI controller struct
> > @@ -569,6 +669,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
> >  	struct spi_transfer *t;
> >  	int err;
> >  
> > +	espi->continuous = (bool)msg->state;
> > +
> >  	/*
> >  	 * Enable the SPI controller and its clock.
> >  	 */
> > @@ -606,12 +708,43 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
> >  	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
> >  	ep93xx_spi_select_device(espi, msg->spi);
> >  
> > -	list_for_each_entry(t, &msg->transfers, transfer_list) {
> > -		ep93xx_spi_process_transfer(espi, msg, t);
> > -		if (msg->status)
> > -			break;
> > +	if (espi->continuous) {
> > +		/*
> > +		 * We can transfer all the transfers continuously.
> > +		 */
> > +		espi->rx = 0;
> > +		espi->tx = 0;
> > +		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
> > +					transfer_list);
> > +
> > +		/* prime the first transfer */
> > +		if (ep93xx_spi_read_write(espi)) {
> 
> On the first read/write for a transfer this condition can never succeed.
> 
> The ep93xx_spi_read_write function first empties the rx fifo then fills the
> tx fifo.  Putting any data in the tx fifo means that you are going to have to
> come back to empty the rx fifo.
> 
> So, the block below never executes.

I also figured that out after I sent the hack to you...

> > +			/*
> > +			 * Transfer was completed. Pick next one and continue
> > +			 * if necessary.
> > +			 */
> > +			t = msg->state;
> > +			if (list_is_last(&t->transfer_list, &msg->transfers))
> > +				goto done;
> > +
> > +			espi->rx = 0;
> > +			espi->tx = 0;
> > +			msg->state = list_entry(t->transfer_list.next,
> > +						struct spi_transfer,
> > +						transfer_list);
> > +		}
> > +
> > +		ep93xx_spi_enable_interrupts(espi);
> > +		wait_for_completion(&espi->wait);
> 
> Even if the first read/write did succeed you are not starting the second transfer.
> This is just passing the operation off to the interrupt routine using the second
> transfer in the message.

Right.

> > -/**
> >   * ep93xx_spi_interrupt() - SPI interrupt handler
> >   * @irq: IRQ number (not used)
> >   * @dev_id: pointer to EP93xx controller struct
> > @@ -792,6 +841,27 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
> >  			 * interrupt then.
> >  			 */
> >  			return IRQ_HANDLED;
> > +		} else {
> > +			struct spi_message *msg = espi->current_msg;
> > +			struct spi_transfer *t = msg->state;
> > +
> > +			if (!espi->continuous)
> > +				goto done;
> > +
> > +			if (!list_is_last(&t->transfer_list, &msg->transfers)) {
> > +				/*
> > +				 * Pick next transfer and refill the FIFO.
> > +				 */
> > +				msg->state = list_entry(t->transfer_list.next,
> > +							struct spi_transfer,
> > +							transfer_list);
> > +				espi->rx = 0;
> > +				espi->tx = 0;
> > +
> > +				ep93xx_spi_read_write(espi);
> > +				return IRQ_HANDLED;
> > +			}
> 
> Here the N transfer has been completed and we are trying to continue with the N+1
> transfer.  This should work but I need to figure out a way to capture it with my
> logic analyzer.  The only problem is if the N transfer is complete that means the
> tx and rx fifos are empty so the SFRM signal is going to be deasserted.  The N+1
> transfer might start really soon after but there will still be a glitch in the SFRM
> signal.

It would be great if you manage to capture it with the logic analyzer.
Even if we get small glitch it means that we are going into right
direction (then we just need to figure out how to keep the FIFO
from emptying).

Other alternative is to use polling mode in v3 of the driver and
see if it works better.

Thanks,
MW

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-23  5:20                                           ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-23  5:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Apr 22, 2010 at 03:43:24PM -0500, H Hartley Sweeten wrote:
> On Thursday, April 22, 2010 10:55 AM, Mika Westerberg wrote:
> > Could you test this in your setup?
> 
> Same results.

OK. thanks for testing.

> I hacked your driver to allow me to toggle a gpio when the interrupt routine
> starts and exits.
> 
> I captured the 4 byte write/2 byte read caused by the spi_write_then_read in
> the sst25l driver when it does the Read-ID command.  The chip select goes low
> followed by the first 4 byte transfer of the message due to the fifo's getting
> primed.  This transfer actually doesn't finish since the rx data has not been
> received.  So the interrupts just get enabled as normal.
> 
> The data starts transferring when the first byte is placed in the tx fifo.  It
> takes about 4.45us to send/receive the 4 bytes.  Approximately 15.9us after the
> last byte has been received the interrupt routine starts.  It then takes about
> 5.7us for the second 2 byte transfer to start.  So there is a total of about
> 21.6us between the two transfers where SFRM is deasserted.

If I understand this correctly, for this particular message it might have worked if
the priming is not done? What I mean is that if we start the transfer in interrupt
handler and after the transfer is finished, immediately continue with the next one
(like in the patch) could it make SFRM to stay asserted (at least shorten the gap)?

> >  /*
> >   * ep93xx_spi_process_message() - process one SPI message
> >   * @espi: ep93xx SPI controller struct
> > @@ -569,6 +669,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
> >  	struct spi_transfer *t;
> >  	int err;
> >  
> > +	espi->continuous = (bool)msg->state;
> > +
> >  	/*
> >  	 * Enable the SPI controller and its clock.
> >  	 */
> > @@ -606,12 +708,43 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
> >  	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
> >  	ep93xx_spi_select_device(espi, msg->spi);
> >  
> > -	list_for_each_entry(t, &msg->transfers, transfer_list) {
> > -		ep93xx_spi_process_transfer(espi, msg, t);
> > -		if (msg->status)
> > -			break;
> > +	if (espi->continuous) {
> > +		/*
> > +		 * We can transfer all the transfers continuously.
> > +		 */
> > +		espi->rx = 0;
> > +		espi->tx = 0;
> > +		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
> > +					transfer_list);
> > +
> > +		/* prime the first transfer */
> > +		if (ep93xx_spi_read_write(espi)) {
> 
> On the first read/write for a transfer this condition can never succeed.
> 
> The ep93xx_spi_read_write function first empties the rx fifo then fills the
> tx fifo.  Putting any data in the tx fifo means that you are going to have to
> come back to empty the rx fifo.
> 
> So, the block below never executes.

I also figured that out after I sent the hack to you...

> > +			/*
> > +			 * Transfer was completed. Pick next one and continue
> > +			 * if necessary.
> > +			 */
> > +			t = msg->state;
> > +			if (list_is_last(&t->transfer_list, &msg->transfers))
> > +				goto done;
> > +
> > +			espi->rx = 0;
> > +			espi->tx = 0;
> > +			msg->state = list_entry(t->transfer_list.next,
> > +						struct spi_transfer,
> > +						transfer_list);
> > +		}
> > +
> > +		ep93xx_spi_enable_interrupts(espi);
> > +		wait_for_completion(&espi->wait);
> 
> Even if the first read/write did succeed you are not starting the second transfer.
> This is just passing the operation off to the interrupt routine using the second
> transfer in the message.

Right.

> > -/**
> >   * ep93xx_spi_interrupt() - SPI interrupt handler
> >   * @irq: IRQ number (not used)
> >   * @dev_id: pointer to EP93xx controller struct
> > @@ -792,6 +841,27 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
> >  			 * interrupt then.
> >  			 */
> >  			return IRQ_HANDLED;
> > +		} else {
> > +			struct spi_message *msg = espi->current_msg;
> > +			struct spi_transfer *t = msg->state;
> > +
> > +			if (!espi->continuous)
> > +				goto done;
> > +
> > +			if (!list_is_last(&t->transfer_list, &msg->transfers)) {
> > +				/*
> > +				 * Pick next transfer and refill the FIFO.
> > +				 */
> > +				msg->state = list_entry(t->transfer_list.next,
> > +							struct spi_transfer,
> > +							transfer_list);
> > +				espi->rx = 0;
> > +				espi->tx = 0;
> > +
> > +				ep93xx_spi_read_write(espi);
> > +				return IRQ_HANDLED;
> > +			}
> 
> Here the N transfer has been completed and we are trying to continue with the N+1
> transfer.  This should work but I need to figure out a way to capture it with my
> logic analyzer.  The only problem is if the N transfer is complete that means the
> tx and rx fifos are empty so the SFRM signal is going to be deasserted.  The N+1
> transfer might start really soon after but there will still be a glitch in the SFRM
> signal.

It would be great if you manage to capture it with the logic analyzer.
Even if we get small glitch it means that we are going into right
direction (then we just need to figure out how to keep the FIFO
from emptying).

Other alternative is to use polling mode in v3 of the driver and
see if it works better.

Thanks,
MW

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-23  5:20                                           ` Mika Westerberg
@ 2010-04-23 17:24                                               ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-23 17:24 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Thursday, April 22, 2010 10:20 PM, Mika Westerberg wrote:
> On Thu, Apr 22, 2010 at 03:43:24PM -0500, H Hartley Sweeten wrote:
>> On Thursday, April 22, 2010 10:55 AM, Mika Westerberg wrote:
>>> Could you test this in your setup?
>> 
>> Same results.
>
> OK. thanks for testing.
>
>> I hacked your driver to allow me to toggle a gpio when the interrupt routine
>> starts and exits.
>> 
>> I captured the 4 byte write/2 byte read caused by the spi_write_then_read in
>> the sst25l driver when it does the Read-ID command.  The chip select goes low
>> followed by the first 4 byte transfer of the message due to the fifo's getting
>> primed.  This transfer actually doesn't finish since the rx data has not been
>> received.  So the interrupts just get enabled as normal.
>> 
>> The data starts transferring when the first byte is placed in the tx fifo.  It
>> takes about 4.45us to send/receive the 4 bytes.  Approximately 15.9us after the
>> last byte has been received the interrupt routine starts.  It then takes about
>> 5.7us for the second 2 byte transfer to start.  So there is a total of about
>> 21.6us between the two transfers where SFRM is deasserted.
>
> If I understand this correctly, for this particular message it might have worked if
> the priming is not done? What I mean is that if we start the transfer in interrupt
> handler and after the transfer is finished, immediately continue with the next one
> (like in the patch) could it make SFRM to stay asserted (at least shorten the gap)?

Hmmm.. It might have.  I didn't test that before I started hacking...

>>>  /*
>>>   * ep93xx_spi_process_message() - process one SPI message
>>>   * @espi: ep93xx SPI controller struct
>>> @@ -569,6 +669,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
>>>  	struct spi_transfer *t;
>>>  	int err;
>>>  
>>> +	espi->continuous = (bool)msg->state;
>>> +
>>>  	/*
>>>  	 * Enable the SPI controller and its clock.
>>>  	 */
>>> @@ -606,12 +708,43 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
>>>  	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
>>>  	ep93xx_spi_select_device(espi, msg->spi);
>>>  
>>> -	list_for_each_entry(t, &msg->transfers, transfer_list) {
>>> -		ep93xx_spi_process_transfer(espi, msg, t);
>>> -		if (msg->status)
>>> -			break;
>>> +	if (espi->continuous) {
>>> +		/*
>>> +		 * We can transfer all the transfers continuously.
>>> +		 */
>>> +		espi->rx = 0;
>>> +		espi->tx = 0;
>>> +		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
>>> +					transfer_list);
>>> +
>>> +		/* prime the first transfer */
>>> +		if (ep93xx_spi_read_write(espi)) {
>> 
>> On the first read/write for a transfer this condition can never succeed.
>> 
>> The ep93xx_spi_read_write function first empties the rx fifo then fills the
>> tx fifo.  Putting any data in the tx fifo means that you are going to have to
>> come back to empty the rx fifo.
>> 
>> So, the block below never executes.
>
> I also figured that out after I sent the hack to you...
>
>>> +			/*
>>> +			 * Transfer was completed. Pick next one and continue
>>> +			 * if necessary.
>>> +			 */
>>> +			t = msg->state;
>>> +			if (list_is_last(&t->transfer_list, &msg->transfers))
>>> +				goto done;
>>> +
>>> +			espi->rx = 0;
>>> +			espi->tx = 0;
>>> +			msg->state = list_entry(t->transfer_list.next,
>>> +						struct spi_transfer,
>>> +						transfer_list);
>>> +		}
>>> +
>>> +		ep93xx_spi_enable_interrupts(espi);
>>> +		wait_for_completion(&espi->wait);
>> 
>> Even if the first read/write did succeed you are not starting the second transfer.
>> This is just passing the operation off to the interrupt routine using the second
>> transfer in the message.
>
> Right.
>
>>> -/**
>>>   * ep93xx_spi_interrupt() - SPI interrupt handler
>>>   * @irq: IRQ number (not used)
>>>   * @dev_id: pointer to EP93xx controller struct
>>> @@ -792,6 +841,27 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
>>>  			 * interrupt then.
>>>  			 */
>>>  			return IRQ_HANDLED;
>>> +		} else {
>>> +			struct spi_message *msg = espi->current_msg;
>>> +			struct spi_transfer *t = msg->state;
>>> +
>>> +			if (!espi->continuous)
>>> +				goto done;
>>> +
>>> +			if (!list_is_last(&t->transfer_list, &msg->transfers)) {
>>> +				/*
>>> +				 * Pick next transfer and refill the FIFO.
>>> +				 */
>>> +				msg->state = list_entry(t->transfer_list.next,
>>> +							struct spi_transfer,
>>> +							transfer_list);
>>> +				espi->rx = 0;
>>> +				espi->tx = 0;
>>> +
>>> +				ep93xx_spi_read_write(espi);
>>> +				return IRQ_HANDLED;
>>> +			}
>>
>> Here the N transfer has been completed and we are trying to continue with the N+1
>> transfer.  This should work but I need to figure out a way to capture it with my
>> logic analyzer.  The only problem is if the N transfer is complete that means the
>> tx and rx fifos are empty so the SFRM signal is going to be deasserted.  The N+1
>> transfer might start really soon after but there will still be a glitch in the SFRM
>> signal.
>
> It would be great if you manage to capture it with the logic analyzer.
> Even if we get small glitch it means that we are going into right
> direction (then we just need to figure out how to keep the FIFO
> from emptying).

I still haven't been able to catch this.

> Other alternative is to use polling mode in v3 of the driver and
> see if it works better.

I think the interrupt mode is still the better way to go.

I was able to hack your driver to keep the continuous transfer going in a multi-transaction
message.  Unfortunately I don't have an easy way to generate a diff to send the necessary
patch.  The hack does work with the sst25l driver.  It correctly detects the end of the
first 4 byte transfer and immediately chains in the second 2 byte transfer.  It ends up
looking like this:

WWWWwwIRRRRFCRRFi

Where:
  'W' is a write for the current transfer
  'w' is a write for the next transfer
  'I' is the start of the interrupt
  'R' is a read for the current transfer
  'F' is the completion of the current transfer
  'C' is the chain to the next transfer
  'i' is the end of the interrupt

So, at the start of the message the fifo's get primed with the 4+2 of the entire message.
Then interrupts are enabled.  When the interrupt occurs the first 4 byte transfer is read.
When that completes the interrupt routine chains to the next transfer and then reads the
next 2 bytes.  When that completes the message is finished so the interrupts get disabled
and espi->wait is completed.

Unfortunately is seems to break the mmc_spi driver for some reason.  I still haven't
figured out why.

If you can post your latest updates to the v4 driver I will create a patch against it
so others can test this also.

Regards,
Hartley
------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-23 17:24                                               ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-23 17:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday, April 22, 2010 10:20 PM, Mika Westerberg wrote:
> On Thu, Apr 22, 2010 at 03:43:24PM -0500, H Hartley Sweeten wrote:
>> On Thursday, April 22, 2010 10:55 AM, Mika Westerberg wrote:
>>> Could you test this in your setup?
>> 
>> Same results.
>
> OK. thanks for testing.
>
>> I hacked your driver to allow me to toggle a gpio when the interrupt routine
>> starts and exits.
>> 
>> I captured the 4 byte write/2 byte read caused by the spi_write_then_read in
>> the sst25l driver when it does the Read-ID command.  The chip select goes low
>> followed by the first 4 byte transfer of the message due to the fifo's getting
>> primed.  This transfer actually doesn't finish since the rx data has not been
>> received.  So the interrupts just get enabled as normal.
>> 
>> The data starts transferring when the first byte is placed in the tx fifo.  It
>> takes about 4.45us to send/receive the 4 bytes.  Approximately 15.9us after the
>> last byte has been received the interrupt routine starts.  It then takes about
>> 5.7us for the second 2 byte transfer to start.  So there is a total of about
>> 21.6us between the two transfers where SFRM is deasserted.
>
> If I understand this correctly, for this particular message it might have worked if
> the priming is not done? What I mean is that if we start the transfer in interrupt
> handler and after the transfer is finished, immediately continue with the next one
> (like in the patch) could it make SFRM to stay asserted (at least shorten the gap)?

Hmmm.. It might have.  I didn't test that before I started hacking...

>>>  /*
>>>   * ep93xx_spi_process_message() - process one SPI message
>>>   * @espi: ep93xx SPI controller struct
>>> @@ -569,6 +669,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
>>>  	struct spi_transfer *t;
>>>  	int err;
>>>  
>>> +	espi->continuous = (bool)msg->state;
>>> +
>>>  	/*
>>>  	 * Enable the SPI controller and its clock.
>>>  	 */
>>> @@ -606,12 +708,43 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
>>>  	ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
>>>  	ep93xx_spi_select_device(espi, msg->spi);
>>>  
>>> -	list_for_each_entry(t, &msg->transfers, transfer_list) {
>>> -		ep93xx_spi_process_transfer(espi, msg, t);
>>> -		if (msg->status)
>>> -			break;
>>> +	if (espi->continuous) {
>>> +		/*
>>> +		 * We can transfer all the transfers continuously.
>>> +		 */
>>> +		espi->rx = 0;
>>> +		espi->tx = 0;
>>> +		msg->state = list_first_entry(&msg->transfers, struct spi_transfer,
>>> +					transfer_list);
>>> +
>>> +		/* prime the first transfer */
>>> +		if (ep93xx_spi_read_write(espi)) {
>> 
>> On the first read/write for a transfer this condition can never succeed.
>> 
>> The ep93xx_spi_read_write function first empties the rx fifo then fills the
>> tx fifo.  Putting any data in the tx fifo means that you are going to have to
>> come back to empty the rx fifo.
>> 
>> So, the block below never executes.
>
> I also figured that out after I sent the hack to you...
>
>>> +			/*
>>> +			 * Transfer was completed. Pick next one and continue
>>> +			 * if necessary.
>>> +			 */
>>> +			t = msg->state;
>>> +			if (list_is_last(&t->transfer_list, &msg->transfers))
>>> +				goto done;
>>> +
>>> +			espi->rx = 0;
>>> +			espi->tx = 0;
>>> +			msg->state = list_entry(t->transfer_list.next,
>>> +						struct spi_transfer,
>>> +						transfer_list);
>>> +		}
>>> +
>>> +		ep93xx_spi_enable_interrupts(espi);
>>> +		wait_for_completion(&espi->wait);
>> 
>> Even if the first read/write did succeed you are not starting the second transfer.
>> This is just passing the operation off to the interrupt routine using the second
>> transfer in the message.
>
> Right.
>
>>> -/**
>>>   * ep93xx_spi_interrupt() - SPI interrupt handler
>>>   * @irq: IRQ number (not used)
>>>   * @dev_id: pointer to EP93xx controller struct
>>> @@ -792,6 +841,27 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
>>>  			 * interrupt then.
>>>  			 */
>>>  			return IRQ_HANDLED;
>>> +		} else {
>>> +			struct spi_message *msg = espi->current_msg;
>>> +			struct spi_transfer *t = msg->state;
>>> +
>>> +			if (!espi->continuous)
>>> +				goto done;
>>> +
>>> +			if (!list_is_last(&t->transfer_list, &msg->transfers)) {
>>> +				/*
>>> +				 * Pick next transfer and refill the FIFO.
>>> +				 */
>>> +				msg->state = list_entry(t->transfer_list.next,
>>> +							struct spi_transfer,
>>> +							transfer_list);
>>> +				espi->rx = 0;
>>> +				espi->tx = 0;
>>> +
>>> +				ep93xx_spi_read_write(espi);
>>> +				return IRQ_HANDLED;
>>> +			}
>>
>> Here the N transfer has been completed and we are trying to continue with the N+1
>> transfer.  This should work but I need to figure out a way to capture it with my
>> logic analyzer.  The only problem is if the N transfer is complete that means the
>> tx and rx fifos are empty so the SFRM signal is going to be deasserted.  The N+1
>> transfer might start really soon after but there will still be a glitch in the SFRM
>> signal.
>
> It would be great if you manage to capture it with the logic analyzer.
> Even if we get small glitch it means that we are going into right
> direction (then we just need to figure out how to keep the FIFO
> from emptying).

I still haven't been able to catch this.

> Other alternative is to use polling mode in v3 of the driver and
> see if it works better.

I think the interrupt mode is still the better way to go.

I was able to hack your driver to keep the continuous transfer going in a multi-transaction
message.  Unfortunately I don't have an easy way to generate a diff to send the necessary
patch.  The hack does work with the sst25l driver.  It correctly detects the end of the
first 4 byte transfer and immediately chains in the second 2 byte transfer.  It ends up
looking like this:

WWWWwwIRRRRFCRRFi

Where:
  'W' is a write for the current transfer
  'w' is a write for the next transfer
  'I' is the start of the interrupt
  'R' is a read for the current transfer
  'F' is the completion of the current transfer
  'C' is the chain to the next transfer
  'i' is the end of the interrupt

So, at the start of the message the fifo's get primed with the 4+2 of the entire message.
Then interrupts are enabled.  When the interrupt occurs the first 4 byte transfer is read.
When that completes the interrupt routine chains to the next transfer and then reads the
next 2 bytes.  When that completes the message is finished so the interrupts get disabled
and espi->wait is completed.

Unfortunately is seems to break the mmc_spi driver for some reason.  I still haven't
figured out why.

If you can post your latest updates to the v4 driver I will create a patch against it
so others can test this also.

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-23 17:24                                               ` H Hartley Sweeten
@ 2010-04-23 23:01                                                   ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-23 23:01 UTC (permalink / raw)
  To: H Hartley Sweeten, Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Friday, April 23, 2010 10:24 AM, H Hartley Sweeten wrote:
> I was able to hack your driver to keep the continuous transfer going in a
> multi-transaction message.  Unfortunately I don't have an easy way to
> generate a diff to send the necessary patch.  The hack does work with the
> sst25l driver.  It correctly detects the end of the first 4 byte transfer
> and immediately chains in the second 2 byte transfer.  It ends up looking
> like this:

Sorry for the length of this message.  I want to give as much detail as
possible so hopefully someone has an idea on this... ;-)


I modified my hack a bit so that the message transactions are dumped at
the end of all transactions in the message.  I'm using Mika's hack to
determine if the message could be continuous then displaying a debug
about the message.  By setting the 'continuous' flag to false right after
that it disables my hack to make the transaction continuous so the
message gets processed in the normal fashion.

The debug output decodes as:
  S   a transfer specific setting was made (in ep93xx_spi_process_transfer)
      NOTE: I have never actually seen this happen.
  +   start of a transfer (in ep93xx_spi_process_fransfer).
  -   end of a transfer (in ep93xx_spi_process_fransfer).
  I   entered ep93xx_spi_interrupt
  I   exited ep93xx_spi_interrupt
  C   chained to the next transfer in a continuous transaction
  nR  the n number of fifo reads (in ep93xx_spi_read_write) or just 'R' if
      only 1 byte is read; !8R if more than 8 reads were done (should never
      happen).
  nW  the n number of fifo writes (in ep93xx_spi_read_write) or just 'W' if
      only 1 byte is written; !8W if more than 8 writes were done (should 
      never happen).
  nw  the n number of fifo writes from the next transfer (in 
      ep93xx_spi_read_write) or just 'w' if only 1 byte is written; !8w if
      more than 8 writes were done (should never happen).  NOTE: this only
      occurs with doing a continuous transaction.
  F   the transfer is complete ((espi->rx == t->len) in ep93xx_spi_read_write)


For the sst25l driver, with continuous transactions disabled, I get this for
the Read-ID command (this is with SPI_DEBUG and MMC_DEBUG enabled):

spi spi0.0: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
ep93xx-spi ep93xx-spi.0: 2 part continuous transaction (6 bytes) for sst25l
ep93xx-spi ep93xx-spi.0: Done: +4WI4RFi-+2WI2RFi-
sst25l spi0.0: sst25lf040a (512 KiB)
Creating 3 MTD partitions on "SPI Flash":
0x000000000000-0x000000001000 : "SPI bootstrap"
0x000000001000-0x000000002000 : "Bootstrap config"
0x000000002000-0x000000080000 : "unallocated"
ep93xx-spi ep93xx-spi.0: registered child spi0.0

With continuous transactions enabled its:

spi spi0.0: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
ep93xx-spi ep93xx-spi.0: 2 part continuous transaction (6 bytes) for sst25l
ep93xx-spi ep93xx-spi.0: Done: 4W2wI4RFC2RFi
sst25l spi0.0: sst25lf040a (512 KiB)
Creating 3 MTD partitions on "SPI Flash":
0x000000000000-0x000000001000 : "SPI bootstrap"
0x000000001000-0x000000002000 : "Bootstrap config"
0x000000002000-0x000000080000 : "unallocated"
ep93xx-spi ep93xx-spi.0: registered child spi0.0

The '+' and '-' are missing since the transfer is started in ep93xx_spi_process_messange
and then handed off to the interrupt routine without first calling ep93xx_spi_process_transfer.
You can see the 2 bytes of the second transfer getting chained to the first 4 bytes
during the priming of the fifo.  Then after the interrupt the first 4 reads finish
the first transaction.  The next transaction is then chained in and also finishes
(2 reads) then the interrupt completes.  Message done!

With the mmc_spi driver the output is WAY to long to post. But, with continuous
transactions disabled the card works fine.  With continuous transactions enabled
it doesn't for some reason.

I have looked over the output a number of times and it appears the continuous transfer
works correctly.  There are 3 that happen when the mmc_spi driver has the spi clock
set to 400000 Hz max, I believe this is while the upper layers are detecting/configuring
the card.  One happens after a CMD10 and is a "mmc_spi: read block, 16 bytes" and is a
16+2 byte message.  This is followed by a CMD9 then another "mmc_spi: read block, 16 bytes"
which is another 16+2 byte message.  Then there is a CMD55 and a CMD51.  The CMD51 does
a 9 byte message then a 1 byte message followed by a "mmc_spi: read block, 8 bytes".
That's followed by 4 separate 1 byte messages then an 8+2 byte message.  All of these
n+m messages appear to work fine as a continuous transfer.

Shortly after this the following is output:

mmc0: new SD card on SPI
mmcblk0: mmc0:0000 S064B 60.6 MiB (ro)
 mmcblk0:

Right after that there is a CMD18.  I think this is where the upper layer is trying to
read the partition table.  This is where it getting interesting compared to the non-
continuous transfer.

mmcblk0: mmc0:0000 S064B 60.6 MiB (ro)
 mmcblk0:
mmc0: starting CMD18 arg 00000000 flags 000000b5
mmc0:     blksz 512 blocks 8 flags 00000200 tsac 100 ms nsac 10000
mmc0:     CMD12 arg 00000000 flags 0000049d
mmc_spi spi0.1:   mmc_spi: CMD18, resp R1
ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
mmc_spi spi0.1:     mmc_spi: read block, 512 bytes
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 3 part continuous transaction (515 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: 8WI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
                               I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R2wFC2RwFCiIRFi
mmc_spi spi0.1:     mmc_spi: read block, 512 bytes
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 3 part continuous transaction (515 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: 8WI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R2wFC2RwFCiIRFi
mmc_spi spi0.1: read - crc error: crc_val=0x0000, computed=0x8258 len=512
mmc_spi spi0.1: read status -84
mmc_spi spi0.1:   mmc_spi: CMD12, resp R1B
ep93xx-spi ep93xx-spi.0: 1 part transaction (29 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +8WI8R8WiI8R8WiI8R5WiI5RFi-
mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
mmc0: req done (CMD18): 0: 00000000 00000000 00000000 00000000
mmc0:     512 bytes transferred: -84
mmc0:     (CMD12): 0: 00000000 00000000 00000000 00000000
mmcblk0: retrying using single block read

At this point everything just goes nuts.  There are a bunch of CMD17 then CMD13.

mmc0: starting CMD17 arg 00000000 flags 000000b5
mmc0:     blksz 512 blocks 1 flags 00000200 tsac 100 ms nsac 10000
mmc_spi spi0.1:   mmc_spi: CMD17, resp R1
ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
mmc_spi spi0.1:   ... CMD17 response SPI_R1: resp 0004 00000000
mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
mmc0: req done (CMD17): -38: 00000004 00000000 00000000 00000000
mmc0:     0 bytes transferred: 0
mmc0: starting CMD13 arg 00000000 flags 00000195
mmc_spi spi0.1:   mmc_spi: CMD13, resp R2/R5
ep93xx-spi ep93xx-spi.0: 1 part transaction (18 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +8WI8R8WiI8R2WiI2RFi-
mmc_spi spi0.1:   ... CMD13 response SPI_R2/R5: resp 0004 00000000
mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
mmc0: req done (CMD13): -38: 00000004 00000000 00000000 00000000
mmcblk0: error -38 sending status comand
mmcblk0: error -38 sending read/write command, response 0x4, card status 0x4
end_request: I/O error, dev mmcblk0, sector 0

The only difference appears the be the arg for CMD17 and the end_request output:

mmc0: starting CMD17 arg 00000000 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 0
mmc0: starting CMD17 arg 00000200 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 1
mmc0: starting CMD17 arg 00000400 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 2
mmc0: starting CMD17 arg 00000600 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 3
mmc0: starting CMD17 arg 00000800 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 4
mmc0: starting CMD17 arg 00000a00 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 5
mmc0: starting CMD17 arg 00000c00 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 6
mmc0: starting CMD17 arg 00000e00 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 7

Then there is a:

Buffer I/O error on device mmcblk0, logical block 0
mmc0: starting CMD18 arg 00000000 flags 000000b5
mmc0:     blksz 512 blocks 8 flags 00000200 tsac 100 ms nsac 10000
mmc0:     CMD12 arg 00000000 flags 0000049d
mmc_spi spi0.1:   mmc_spi: CMD18, resp R1
ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
mmc_spi spi0.1:   ... CMD18 response SPI_R1: resp 0004 00000000
mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
mmc0: req done (CMD18): -38: 00000004 00000000 00000000 00000000
mmc0:     0 bytes transferred: 0
mmc0:     (CMD12): 0: 00000000 00000000 00000000 00000000
mmcblk0: retrying using single block read

Followed by all the CMD17 stuff above again.  Then it ends with:

Buffer I/O error on device mmcblk0, logical block 0
 unable to read partition table

I can't see any reason why the continuous transfer would cause a
crc error.  Even if it did I can't see why the single block reads
would all fail, all of then are composed of 1 transfer messages.

Anyone have some suggestions?

Again, sorry for the long message.

Regards,
Hartley

------------------------------------------------------------------------------

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

* [spi-devel-general] [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-23 23:01                                                   ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-23 23:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday, April 23, 2010 10:24 AM, H Hartley Sweeten wrote:
> I was able to hack your driver to keep the continuous transfer going in a
> multi-transaction message.  Unfortunately I don't have an easy way to
> generate a diff to send the necessary patch.  The hack does work with the
> sst25l driver.  It correctly detects the end of the first 4 byte transfer
> and immediately chains in the second 2 byte transfer.  It ends up looking
> like this:

Sorry for the length of this message.  I want to give as much detail as
possible so hopefully someone has an idea on this... ;-)


I modified my hack a bit so that the message transactions are dumped at
the end of all transactions in the message.  I'm using Mika's hack to
determine if the message could be continuous then displaying a debug
about the message.  By setting the 'continuous' flag to false right after
that it disables my hack to make the transaction continuous so the
message gets processed in the normal fashion.

The debug output decodes as:
  S   a transfer specific setting was made (in ep93xx_spi_process_transfer)
      NOTE: I have never actually seen this happen.
  +   start of a transfer (in ep93xx_spi_process_fransfer).
  -   end of a transfer (in ep93xx_spi_process_fransfer).
  I   entered ep93xx_spi_interrupt
  I   exited ep93xx_spi_interrupt
  C   chained to the next transfer in a continuous transaction
  nR  the n number of fifo reads (in ep93xx_spi_read_write) or just 'R' if
      only 1 byte is read; !8R if more than 8 reads were done (should never
      happen).
  nW  the n number of fifo writes (in ep93xx_spi_read_write) or just 'W' if
      only 1 byte is written; !8W if more than 8 writes were done (should 
      never happen).
  nw  the n number of fifo writes from the next transfer (in 
      ep93xx_spi_read_write) or just 'w' if only 1 byte is written; !8w if
      more than 8 writes were done (should never happen).  NOTE: this only
      occurs with doing a continuous transaction.
  F   the transfer is complete ((espi->rx == t->len) in ep93xx_spi_read_write)


For the sst25l driver, with continuous transactions disabled, I get this for
the Read-ID command (this is with SPI_DEBUG and MMC_DEBUG enabled):

spi spi0.0: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
ep93xx-spi ep93xx-spi.0: 2 part continuous transaction (6 bytes) for sst25l
ep93xx-spi ep93xx-spi.0: Done: +4WI4RFi-+2WI2RFi-
sst25l spi0.0: sst25lf040a (512 KiB)
Creating 3 MTD partitions on "SPI Flash":
0x000000000000-0x000000001000 : "SPI bootstrap"
0x000000001000-0x000000002000 : "Bootstrap config"
0x000000002000-0x000000080000 : "unallocated"
ep93xx-spi ep93xx-spi.0: registered child spi0.0

With continuous transactions enabled its:

spi spi0.0: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
ep93xx-spi ep93xx-spi.0: 2 part continuous transaction (6 bytes) for sst25l
ep93xx-spi ep93xx-spi.0: Done: 4W2wI4RFC2RFi
sst25l spi0.0: sst25lf040a (512 KiB)
Creating 3 MTD partitions on "SPI Flash":
0x000000000000-0x000000001000 : "SPI bootstrap"
0x000000001000-0x000000002000 : "Bootstrap config"
0x000000002000-0x000000080000 : "unallocated"
ep93xx-spi ep93xx-spi.0: registered child spi0.0

The '+' and '-' are missing since the transfer is started in ep93xx_spi_process_messange
and then handed off to the interrupt routine without first calling ep93xx_spi_process_transfer.
You can see the 2 bytes of the second transfer getting chained to the first 4 bytes
during the priming of the fifo.  Then after the interrupt the first 4 reads finish
the first transaction.  The next transaction is then chained in and also finishes
(2 reads) then the interrupt completes.  Message done!

With the mmc_spi driver the output is WAY to long to post. But, with continuous
transactions disabled the card works fine.  With continuous transactions enabled
it doesn't for some reason.

I have looked over the output a number of times and it appears the continuous transfer
works correctly.  There are 3 that happen when the mmc_spi driver has the spi clock
set to 400000 Hz max, I believe this is while the upper layers are detecting/configuring
the card.  One happens after a CMD10 and is a "mmc_spi: read block, 16 bytes" and is a
16+2 byte message.  This is followed by a CMD9 then another "mmc_spi: read block, 16 bytes"
which is another 16+2 byte message.  Then there is a CMD55 and a CMD51.  The CMD51 does
a 9 byte message then a 1 byte message followed by a "mmc_spi: read block, 8 bytes".
That's followed by 4 separate 1 byte messages then an 8+2 byte message.  All of these
n+m messages appear to work fine as a continuous transfer.

Shortly after this the following is output:

mmc0: new SD card on SPI
mmcblk0: mmc0:0000 S064B 60.6 MiB (ro)
 mmcblk0:

Right after that there is a CMD18.  I think this is where the upper layer is trying to
read the partition table.  This is where it getting interesting compared to the non-
continuous transfer.

mmcblk0: mmc0:0000 S064B 60.6 MiB (ro)
 mmcblk0:
mmc0: starting CMD18 arg 00000000 flags 000000b5
mmc0:     blksz 512 blocks 8 flags 00000200 tsac 100 ms nsac 10000
mmc0:     CMD12 arg 00000000 flags 0000049d
mmc_spi spi0.1:   mmc_spi: CMD18, resp R1
ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
mmc_spi spi0.1:     mmc_spi: read block, 512 bytes
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 3 part continuous transaction (515 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: 8WI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
                               I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R2wFC2RwFCiIRFi
mmc_spi spi0.1:     mmc_spi: read block, 512 bytes
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
ep93xx-spi ep93xx-spi.0: 3 part continuous transaction (515 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: 8WI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
					 I8R2wFC2RwFCiIRFi
mmc_spi spi0.1: read - crc error: crc_val=0x0000, computed=0x8258 len=512
mmc_spi spi0.1: read status -84
mmc_spi spi0.1:   mmc_spi: CMD12, resp R1B
ep93xx-spi ep93xx-spi.0: 1 part transaction (29 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +8WI8R8WiI8R8WiI8R5WiI5RFi-
mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
mmc0: req done (CMD18): 0: 00000000 00000000 00000000 00000000
mmc0:     512 bytes transferred: -84
mmc0:     (CMD12): 0: 00000000 00000000 00000000 00000000
mmcblk0: retrying using single block read

At this point everything just goes nuts.  There are a bunch of CMD17 then CMD13.

mmc0: starting CMD17 arg 00000000 flags 000000b5
mmc0:     blksz 512 blocks 1 flags 00000200 tsac 100 ms nsac 10000
mmc_spi spi0.1:   mmc_spi: CMD17, resp R1
ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
mmc_spi spi0.1:   ... CMD17 response SPI_R1: resp 0004 00000000
mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
mmc0: req done (CMD17): -38: 00000004 00000000 00000000 00000000
mmc0:     0 bytes transferred: 0
mmc0: starting CMD13 arg 00000000 flags 00000195
mmc_spi spi0.1:   mmc_spi: CMD13, resp R2/R5
ep93xx-spi ep93xx-spi.0: 1 part transaction (18 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +8WI8R8WiI8R2WiI2RFi-
mmc_spi spi0.1:   ... CMD13 response SPI_R2/R5: resp 0004 00000000
mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
mmc0: req done (CMD13): -38: 00000004 00000000 00000000 00000000
mmcblk0: error -38 sending status comand
mmcblk0: error -38 sending read/write command, response 0x4, card status 0x4
end_request: I/O error, dev mmcblk0, sector 0

The only difference appears the be the arg for CMD17 and the end_request output:

mmc0: starting CMD17 arg 00000000 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 0
mmc0: starting CMD17 arg 00000200 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 1
mmc0: starting CMD17 arg 00000400 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 2
mmc0: starting CMD17 arg 00000600 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 3
mmc0: starting CMD17 arg 00000800 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 4
mmc0: starting CMD17 arg 00000a00 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 5
mmc0: starting CMD17 arg 00000c00 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 6
mmc0: starting CMD17 arg 00000e00 flags 000000b5
...
end_request: I/O error, dev mmcblk0, sector 7

Then there is a:

Buffer I/O error on device mmcblk0, logical block 0
mmc0: starting CMD18 arg 00000000 flags 000000b5
mmc0:     blksz 512 blocks 8 flags 00000200 tsac 100 ms nsac 10000
mmc0:     CMD12 arg 00000000 flags 0000049d
mmc_spi spi0.1:   mmc_spi: CMD18, resp R1
ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
mmc_spi spi0.1:   ... CMD18 response SPI_R1: resp 0004 00000000
mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
mmc0: req done (CMD18): -38: 00000004 00000000 00000000 00000000
mmc0:     0 bytes transferred: 0
mmc0:     (CMD12): 0: 00000000 00000000 00000000 00000000
mmcblk0: retrying using single block read

Followed by all the CMD17 stuff above again.  Then it ends with:

Buffer I/O error on device mmcblk0, logical block 0
 unable to read partition table

I can't see any reason why the continuous transfer would cause a
crc error.  Even if it did I can't see why the single block reads
would all fail, all of then are composed of 1 transfer messages.

Anyone have some suggestions?

Again, sorry for the long message.

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-20 15:11     ` Mika Westerberg
@ 2010-04-24 18:14         ` Martin Guy
  -1 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-24 18:14 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi, another little fix:

EP93xx User's Manual -> Synchronous Serial Port -> Registers

SSPIIR description:
"Read Only
Note: A write to this register clears the receive overrun interrupt,
regardless of the data
      value written."

It doesn't affect the RIS/TIS ones, which are caused by the state of the device.

so

static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
{
...
        if (!(irq_status & (SSPIIR_RORIS | SSPIIR_TIS | SSPIIR_RIS)))
                return IRQ_NONE; /* not for us */

-       /* clear the interrupt */
-       ep93xx_spi_write_u8(espi, SSPICR, 0);

        /*
         * If we got ROR (receive overrun) interrupt we know that something is
         * wrong. Just abort the message.
         */
        if (unlikely(irq_status & SSPIIR_RORIS)) {
+               /* clear the overrun interrupt */
+               ep93xx_spi_write_u8(espi, SSPICR, 0);
                dev_warn(&espi->pdev->dev,
                         "receive overrun, aborting the message\n");
                espi->current_msg->status = -EIO;
        } else {

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-24 18:14         ` Martin Guy
  0 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-24 18:14 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, another little fix:

EP93xx User's Manual -> Synchronous Serial Port -> Registers

SSPIIR description:
"Read Only
Note: A write to this register clears the receive overrun interrupt,
regardless of the data
      value written."

It doesn't affect the RIS/TIS ones, which are caused by the state of the device.

so

static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
{
...
        if (!(irq_status & (SSPIIR_RORIS | SSPIIR_TIS | SSPIIR_RIS)))
                return IRQ_NONE; /* not for us */

-       /* clear the interrupt */
-       ep93xx_spi_write_u8(espi, SSPICR, 0);

        /*
         * If we got ROR (receive overrun) interrupt we know that something is
         * wrong. Just abort the message.
         */
        if (unlikely(irq_status & SSPIIR_RORIS)) {
+               /* clear the overrun interrupt */
+               ep93xx_spi_write_u8(espi, SSPICR, 0);
                dev_warn(&espi->pdev->dev,
                         "receive overrun, aborting the message\n");
                espi->current_msg->status = -EIO;
        } else {

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-23 23:01                                                   ` [spi-devel-general] " H Hartley Sweeten
@ 2010-04-25  9:29                                                       ` Martin Guy
  -1 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-25  9:29 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 4/24/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
> On Friday, April 23, 2010 10:24 AM, H Hartley Sweeten wrote:
>  > I was able to hack your driver to keep the continuous transfer going in a
>  > multi-transaction message.

>  I modified my hack a bit so that the message transactions are dumped at
>  the end of all transactions in the message.

Yes, you cannot issue printk's while the transfer is active, because
that totally changes the timing.

>  I'm using Mika's hack to determine if the message could be continuous

I've thought about this some more, and the "continuity check" seems to
done in the wrong place. Instead of having the loop_for_all thing at
the top level, then having a race to keep the transfer going inside
the interrupt routine, the structure needs to change so that the
looping construct is initialised at the top level, but steps from one
transfer to the next inside the interrupt routine, the same way as it
is the irw routine that steps from one word to the next of a transfer.
This implies adding the "looping" variable into the struct.

But it gets worse. To react in time, we must get from the half-empty
interrupt being asserted to the point where we refill the TX FIFO
within 4 (maybe 5?) words. 32 bits at 3.7MHz is about 8.5 us. With E2
silicon at 7.4MHz this is 4 us. If we don't react in time, for example
because another interrupt routing is already in progress, the TX
buffer empties, and SFRMOUT goes high in the middle of a transfer.
Does this happen in practice? Well, you can check for it in the IRQ
routine: if a transfer has been started, there is more to send but the
device has gone idle, then we have not reacted quickly enough and
SFRMOUT will have gone high:

static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
{
        struct spi_message *msg = espi->current_msg;
        struct spi_transfer *t = msg->state;

        /* read as long as RX FIFO has frames in it */
        while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
                ep93xx_do_read(espi, t);
                espi->fifo_level--;
        }

        if (espi->tx  >0 && espi->tx < t->len&&
!(ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_BSY)) {
                /* More to transmit but device has gone idle means that
                 * SFRMOUT will have gone high */
                printk("ep93xx-spi: Underrun\n");
        }

        /* write as long as TX FIFO has room */
        while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
                ep93xx_do_write(espi, t);
                espi->fifo_level++;
        }



 then displaying a debug
>  about the message.  By setting the 'continuous' flag to false right after
>  that it disables my hack to make the transaction continuous so the
>  message gets processed in the normal fashion.
>
>  The debug output decodes as:
>   S   a transfer specific setting was made (in ep93xx_spi_process_transfer)
>       NOTE: I have never actually seen this happen.
>   +   start of a transfer (in ep93xx_spi_process_fransfer).
>   -   end of a transfer (in ep93xx_spi_process_fransfer).
>   I   entered ep93xx_spi_interrupt
>   I   exited ep93xx_spi_interrupt
>   C   chained to the next transfer in a continuous transaction
>   nR  the n number of fifo reads (in ep93xx_spi_read_write) or just 'R' if
>       only 1 byte is read; !8R if more than 8 reads were done (should never
>       happen).
>   nW  the n number of fifo writes (in ep93xx_spi_read_write) or just 'W' if
>       only 1 byte is written; !8W if more than 8 writes were done (should
>       never happen).
>   nw  the n number of fifo writes from the next transfer (in
>       ep93xx_spi_read_write) or just 'w' if only 1 byte is written; !8w if
>       more than 8 writes were done (should never happen).  NOTE: this only
>       occurs with doing a continuous transaction.
>   F   the transfer is complete ((espi->rx == t->len) in ep93xx_spi_read_write)
>
>
>  For the sst25l driver, with continuous transactions disabled, I get this for
>  the Read-ID command (this is with SPI_DEBUG and MMC_DEBUG enabled):
>
>  spi spi0.0: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  ep93xx-spi ep93xx-spi.0: 2 part continuous transaction (6 bytes) for sst25l
>  ep93xx-spi ep93xx-spi.0: Done: +4WI4RFi-+2WI2RFi-
>  sst25l spi0.0: sst25lf040a (512 KiB)
>  Creating 3 MTD partitions on "SPI Flash":
>  0x000000000000-0x000000001000 : "SPI bootstrap"
>  0x000000001000-0x000000002000 : "Bootstrap config"
>  0x000000002000-0x000000080000 : "unallocated"
>  ep93xx-spi ep93xx-spi.0: registered child spi0.0
>
>  With continuous transactions enabled its:
>
>  spi spi0.0: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  ep93xx-spi ep93xx-spi.0: 2 part continuous transaction (6 bytes) for sst25l
>  ep93xx-spi ep93xx-spi.0: Done: 4W2wI4RFC2RFi
>  sst25l spi0.0: sst25lf040a (512 KiB)
>  Creating 3 MTD partitions on "SPI Flash":
>  0x000000000000-0x000000001000 : "SPI bootstrap"
>  0x000000001000-0x000000002000 : "Bootstrap config"
>  0x000000002000-0x000000080000 : "unallocated"
>  ep93xx-spi ep93xx-spi.0: registered child spi0.0
>
>  The '+' and '-' are missing since the transfer is started in ep93xx_spi_process_messange
>  and then handed off to the interrupt routine without first calling ep93xx_spi_process_transfer.
>  You can see the 2 bytes of the second transfer getting chained to the first 4 bytes
>  during the priming of the fifo.  Then after the interrupt the first 4 reads finish
>  the first transaction.  The next transaction is then chained in and also finishes
>  (2 reads) then the interrupt completes.  Message done!
>
>  With the mmc_spi driver the output is WAY to long to post. But, with continuous
>  transactions disabled the card works fine.  With continuous transactions enabled
>  it doesn't for some reason.
>
>  I have looked over the output a number of times and it appears the continuous transfer
>  works correctly.  There are 3 that happen when the mmc_spi driver has the spi clock
>  set to 400000 Hz max, I believe this is while the upper layers are detecting/configuring
>  the card.  One happens after a CMD10 and is a "mmc_spi: read block, 16 bytes" and is a
>  16+2 byte message.  This is followed by a CMD9 then another "mmc_spi: read block, 16 bytes"
>  which is another 16+2 byte message.  Then there is a CMD55 and a CMD51.  The CMD51 does
>  a 9 byte message then a 1 byte message followed by a "mmc_spi: read block, 8 bytes".
>  That's followed by 4 separate 1 byte messages then an 8+2 byte message.  All of these
>  n+m messages appear to work fine as a continuous transfer.
>
>  Shortly after this the following is output:
>
>
>  mmc0: new SD card on SPI
>
> mmcblk0: mmc0:0000 S064B 60.6 MiB (ro)
>   mmcblk0:
>
>  Right after that there is a CMD18.  I think this is where the upper layer is trying to
>  read the partition table.  This is where it getting interesting compared to the non-
>  continuous transfer.
>
>  mmcblk0: mmc0:0000 S064B 60.6 MiB (ro)
>   mmcblk0:
>  mmc0: starting CMD18 arg 00000000 flags 000000b5
>  mmc0:     blksz 512 blocks 8 flags 00000200 tsac 100 ms nsac 10000
>  mmc0:     CMD12 arg 00000000 flags 0000049d
>  mmc_spi spi0.1:   mmc_spi: CMD18, resp R1
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  mmc_spi spi0.1:     mmc_spi: read block, 512 bytes
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 3 part continuous transaction (515 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: 8WI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R2wFC2RwFCiIRFi
>  mmc_spi spi0.1:     mmc_spi: read block, 512 bytes
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 3 part continuous transaction (515 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: 8WI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R2wFC2RwFCiIRFi
>  mmc_spi spi0.1: read - crc error: crc_val=0x0000, computed=0x8258 len=512
>  mmc_spi spi0.1: read status -84
>  mmc_spi spi0.1:   mmc_spi: CMD12, resp R1B
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (29 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +8WI8R8WiI8R8WiI8R5WiI5RFi-
>  mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  mmc0: req done (CMD18): 0: 00000000 00000000 00000000 00000000
>  mmc0:     512 bytes transferred: -84
>  mmc0:     (CMD12): 0: 00000000 00000000 00000000 00000000
>
> mmcblk0: retrying using single block read
>
>
> At this point everything just goes nuts.  There are a bunch of CMD17 then CMD13.
>
>  mmc0: starting CMD17 arg 00000000 flags 000000b5
>  mmc0:     blksz 512 blocks 1 flags 00000200 tsac 100 ms nsac 10000
>  mmc_spi spi0.1:   mmc_spi: CMD17, resp R1
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
>  mmc_spi spi0.1:   ... CMD17 response SPI_R1: resp 0004 00000000
>  mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  mmc0: req done (CMD17): -38: 00000004 00000000 00000000 00000000
>  mmc0:     0 bytes transferred: 0
>  mmc0: starting CMD13 arg 00000000 flags 00000195
>  mmc_spi spi0.1:   mmc_spi: CMD13, resp R2/R5
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (18 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +8WI8R8WiI8R2WiI2RFi-
>  mmc_spi spi0.1:   ... CMD13 response SPI_R2/R5: resp 0004 00000000
>  mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  mmc0: req done (CMD13): -38: 00000004 00000000 00000000 00000000
>
> mmcblk0: error -38 sending status comand
>
> mmcblk0: error -38 sending read/write command, response 0x4, card status 0x4
>  end_request: I/O error, dev mmcblk0, sector 0
>
>  The only difference appears the be the arg for CMD17 and the end_request output:
>
>  mmc0: starting CMD17 arg 00000000 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 0
>  mmc0: starting CMD17 arg 00000200 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 1
>  mmc0: starting CMD17 arg 00000400 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 2
>  mmc0: starting CMD17 arg 00000600 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 3
>  mmc0: starting CMD17 arg 00000800 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 4
>  mmc0: starting CMD17 arg 00000a00 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 5
>  mmc0: starting CMD17 arg 00000c00 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 6
>  mmc0: starting CMD17 arg 00000e00 flags 000000b5
>  ...
>
> end_request: I/O error, dev mmcblk0, sector 7
>
>
> Then there is a:
>
>  Buffer I/O error on device mmcblk0, logical block 0
>  mmc0: starting CMD18 arg 00000000 flags 000000b5
>  mmc0:     blksz 512 blocks 8 flags 00000200 tsac 100 ms nsac 10000
>  mmc0:     CMD12 arg 00000000 flags 0000049d
>  mmc_spi spi0.1:   mmc_spi: CMD18, resp R1
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
>  mmc_spi spi0.1:   ... CMD18 response SPI_R1: resp 0004 00000000
>  mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  mmc0: req done (CMD18): -38: 00000004 00000000 00000000 00000000
>  mmc0:     0 bytes transferred: 0
>  mmc0:     (CMD12): 0: 00000000 00000000 00000000 00000000
>
> mmcblk0: retrying using single block read
>
>
> Followed by all the CMD17 stuff above again.  Then it ends with:
>
>  Buffer I/O error on device mmcblk0, logical block 0
>   unable to read partition table
>
>  I can't see any reason why the continuous transfer would cause a
>  crc error.  Even if it did I can't see why the single block reads
>  would all fail, all of then are composed of 1 transfer messages.
>
>  Anyone have some suggestions?
>
>  Again, sorry for the long message.
>
>  Regards,
>
> Hartley
>

------------------------------------------------------------------------------

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

* [spi-devel-general] [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-25  9:29                                                       ` Martin Guy
  0 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-25  9:29 UTC (permalink / raw)
  To: linux-arm-kernel

On 4/24/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
> On Friday, April 23, 2010 10:24 AM, H Hartley Sweeten wrote:
>  > I was able to hack your driver to keep the continuous transfer going in a
>  > multi-transaction message.

>  I modified my hack a bit so that the message transactions are dumped at
>  the end of all transactions in the message.

Yes, you cannot issue printk's while the transfer is active, because
that totally changes the timing.

>  I'm using Mika's hack to determine if the message could be continuous

I've thought about this some more, and the "continuity check" seems to
done in the wrong place. Instead of having the loop_for_all thing at
the top level, then having a race to keep the transfer going inside
the interrupt routine, the structure needs to change so that the
looping construct is initialised at the top level, but steps from one
transfer to the next inside the interrupt routine, the same way as it
is the irw routine that steps from one word to the next of a transfer.
This implies adding the "looping" variable into the struct.

But it gets worse. To react in time, we must get from the half-empty
interrupt being asserted to the point where we refill the TX FIFO
within 4 (maybe 5?) words. 32 bits at 3.7MHz is about 8.5 us. With E2
silicon at 7.4MHz this is 4 us. If we don't react in time, for example
because another interrupt routing is already in progress, the TX
buffer empties, and SFRMOUT goes high in the middle of a transfer.
Does this happen in practice? Well, you can check for it in the IRQ
routine: if a transfer has been started, there is more to send but the
device has gone idle, then we have not reacted quickly enough and
SFRMOUT will have gone high:

static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
{
        struct spi_message *msg = espi->current_msg;
        struct spi_transfer *t = msg->state;

        /* read as long as RX FIFO has frames in it */
        while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
                ep93xx_do_read(espi, t);
                espi->fifo_level--;
        }

        if (espi->tx  >0 && espi->tx < t->len&&
!(ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_BSY)) {
                /* More to transmit but device has gone idle means that
                 * SFRMOUT will have gone high */
                printk("ep93xx-spi: Underrun\n");
        }

        /* write as long as TX FIFO has room */
        while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
                ep93xx_do_write(espi, t);
                espi->fifo_level++;
        }



 then displaying a debug
>  about the message.  By setting the 'continuous' flag to false right after
>  that it disables my hack to make the transaction continuous so the
>  message gets processed in the normal fashion.
>
>  The debug output decodes as:
>   S   a transfer specific setting was made (in ep93xx_spi_process_transfer)
>       NOTE: I have never actually seen this happen.
>   +   start of a transfer (in ep93xx_spi_process_fransfer).
>   -   end of a transfer (in ep93xx_spi_process_fransfer).
>   I   entered ep93xx_spi_interrupt
>   I   exited ep93xx_spi_interrupt
>   C   chained to the next transfer in a continuous transaction
>   nR  the n number of fifo reads (in ep93xx_spi_read_write) or just 'R' if
>       only 1 byte is read; !8R if more than 8 reads were done (should never
>       happen).
>   nW  the n number of fifo writes (in ep93xx_spi_read_write) or just 'W' if
>       only 1 byte is written; !8W if more than 8 writes were done (should
>       never happen).
>   nw  the n number of fifo writes from the next transfer (in
>       ep93xx_spi_read_write) or just 'w' if only 1 byte is written; !8w if
>       more than 8 writes were done (should never happen).  NOTE: this only
>       occurs with doing a continuous transaction.
>   F   the transfer is complete ((espi->rx == t->len) in ep93xx_spi_read_write)
>
>
>  For the sst25l driver, with continuous transactions disabled, I get this for
>  the Read-ID command (this is with SPI_DEBUG and MMC_DEBUG enabled):
>
>  spi spi0.0: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  ep93xx-spi ep93xx-spi.0: 2 part continuous transaction (6 bytes) for sst25l
>  ep93xx-spi ep93xx-spi.0: Done: +4WI4RFi-+2WI2RFi-
>  sst25l spi0.0: sst25lf040a (512 KiB)
>  Creating 3 MTD partitions on "SPI Flash":
>  0x000000000000-0x000000001000 : "SPI bootstrap"
>  0x000000001000-0x000000002000 : "Bootstrap config"
>  0x000000002000-0x000000080000 : "unallocated"
>  ep93xx-spi ep93xx-spi.0: registered child spi0.0
>
>  With continuous transactions enabled its:
>
>  spi spi0.0: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  ep93xx-spi ep93xx-spi.0: 2 part continuous transaction (6 bytes) for sst25l
>  ep93xx-spi ep93xx-spi.0: Done: 4W2wI4RFC2RFi
>  sst25l spi0.0: sst25lf040a (512 KiB)
>  Creating 3 MTD partitions on "SPI Flash":
>  0x000000000000-0x000000001000 : "SPI bootstrap"
>  0x000000001000-0x000000002000 : "Bootstrap config"
>  0x000000002000-0x000000080000 : "unallocated"
>  ep93xx-spi ep93xx-spi.0: registered child spi0.0
>
>  The '+' and '-' are missing since the transfer is started in ep93xx_spi_process_messange
>  and then handed off to the interrupt routine without first calling ep93xx_spi_process_transfer.
>  You can see the 2 bytes of the second transfer getting chained to the first 4 bytes
>  during the priming of the fifo.  Then after the interrupt the first 4 reads finish
>  the first transaction.  The next transaction is then chained in and also finishes
>  (2 reads) then the interrupt completes.  Message done!
>
>  With the mmc_spi driver the output is WAY to long to post. But, with continuous
>  transactions disabled the card works fine.  With continuous transactions enabled
>  it doesn't for some reason.
>
>  I have looked over the output a number of times and it appears the continuous transfer
>  works correctly.  There are 3 that happen when the mmc_spi driver has the spi clock
>  set to 400000 Hz max, I believe this is while the upper layers are detecting/configuring
>  the card.  One happens after a CMD10 and is a "mmc_spi: read block, 16 bytes" and is a
>  16+2 byte message.  This is followed by a CMD9 then another "mmc_spi: read block, 16 bytes"
>  which is another 16+2 byte message.  Then there is a CMD55 and a CMD51.  The CMD51 does
>  a 9 byte message then a 1 byte message followed by a "mmc_spi: read block, 8 bytes".
>  That's followed by 4 separate 1 byte messages then an 8+2 byte message.  All of these
>  n+m messages appear to work fine as a continuous transfer.
>
>  Shortly after this the following is output:
>
>
>  mmc0: new SD card on SPI
>
> mmcblk0: mmc0:0000 S064B 60.6 MiB (ro)
>   mmcblk0:
>
>  Right after that there is a CMD18.  I think this is where the upper layer is trying to
>  read the partition table.  This is where it getting interesting compared to the non-
>  continuous transfer.
>
>  mmcblk0: mmc0:0000 S064B 60.6 MiB (ro)
>   mmcblk0:
>  mmc0: starting CMD18 arg 00000000 flags 000000b5
>  mmc0:     blksz 512 blocks 8 flags 00000200 tsac 100 ms nsac 10000
>  mmc0:     CMD12 arg 00000000 flags 0000049d
>  mmc_spi spi0.1:   mmc_spi: CMD18, resp R1
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  mmc_spi spi0.1:     mmc_spi: read block, 512 bytes
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 3 part continuous transaction (515 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: 8WI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R2wFC2RwFCiIRFi
>  mmc_spi spi0.1:     mmc_spi: read block, 512 bytes
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (1 byte) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +WIRFi-
>  ep93xx-spi ep93xx-spi.0: 3 part continuous transaction (515 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: 8WI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8WiI8R8Wi
>                                          I8R2wFC2RwFCiIRFi
>  mmc_spi spi0.1: read - crc error: crc_val=0x0000, computed=0x8258 len=512
>  mmc_spi spi0.1: read status -84
>  mmc_spi spi0.1:   mmc_spi: CMD12, resp R1B
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (29 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +8WI8R8WiI8R8WiI8R5WiI5RFi-
>  mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  mmc0: req done (CMD18): 0: 00000000 00000000 00000000 00000000
>  mmc0:     512 bytes transferred: -84
>  mmc0:     (CMD12): 0: 00000000 00000000 00000000 00000000
>
> mmcblk0: retrying using single block read
>
>
> At this point everything just goes nuts.  There are a bunch of CMD17 then CMD13.
>
>  mmc0: starting CMD17 arg 00000000 flags 000000b5
>  mmc0:     blksz 512 blocks 1 flags 00000200 tsac 100 ms nsac 10000
>  mmc_spi spi0.1:   mmc_spi: CMD17, resp R1
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
>  mmc_spi spi0.1:   ... CMD17 response SPI_R1: resp 0004 00000000
>  mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  mmc0: req done (CMD17): -38: 00000004 00000000 00000000 00000000
>  mmc0:     0 bytes transferred: 0
>  mmc0: starting CMD13 arg 00000000 flags 00000195
>  mmc_spi spi0.1:   mmc_spi: CMD13, resp R2/R5
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (18 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +8WI8R8WiI8R2WiI2RFi-
>  mmc_spi spi0.1:   ... CMD13 response SPI_R2/R5: resp 0004 00000000
>  mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  mmc0: req done (CMD13): -38: 00000004 00000000 00000000 00000000
>
> mmcblk0: error -38 sending status comand
>
> mmcblk0: error -38 sending read/write command, response 0x4, card status 0x4
>  end_request: I/O error, dev mmcblk0, sector 0
>
>  The only difference appears the be the arg for CMD17 and the end_request output:
>
>  mmc0: starting CMD17 arg 00000000 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 0
>  mmc0: starting CMD17 arg 00000200 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 1
>  mmc0: starting CMD17 arg 00000400 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 2
>  mmc0: starting CMD17 arg 00000600 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 3
>  mmc0: starting CMD17 arg 00000800 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 4
>  mmc0: starting CMD17 arg 00000a00 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 5
>  mmc0: starting CMD17 arg 00000c00 flags 000000b5
>  ...
>  end_request: I/O error, dev mmcblk0, sector 6
>  mmc0: starting CMD17 arg 00000e00 flags 000000b5
>  ...
>
> end_request: I/O error, dev mmcblk0, sector 7
>
>
> Then there is a:
>
>  Buffer I/O error on device mmcblk0, logical block 0
>  mmc0: starting CMD18 arg 00000000 flags 000000b5
>  mmc0:     blksz 512 blocks 8 flags 00000200 tsac 100 ms nsac 10000
>  mmc0:     CMD12 arg 00000000 flags 0000049d
>  mmc_spi spi0.1:   mmc_spi: CMD18, resp R1
>  ep93xx-spi ep93xx-spi.0: 1 part transaction (9 bytes) for mmc_spi
>  ep93xx-spi ep93xx-spi.0: Done: +8WI8RWiIRFi-
>  mmc_spi spi0.1:   ... CMD18 response SPI_R1: resp 0004 00000000
>  mmc_spi spi0.1: setup mode 3, 8 bits/w, 20000000 Hz max --> 0
>  mmc0: req done (CMD18): -38: 00000004 00000000 00000000 00000000
>  mmc0:     0 bytes transferred: 0
>  mmc0:     (CMD12): 0: 00000000 00000000 00000000 00000000
>
> mmcblk0: retrying using single block read
>
>
> Followed by all the CMD17 stuff above again.  Then it ends with:
>
>  Buffer I/O error on device mmcblk0, logical block 0
>   unable to read partition table
>
>  I can't see any reason why the continuous transfer would cause a
>  crc error.  Even if it did I can't see why the single block reads
>  would all fail, all of then are composed of 1 transfer messages.
>
>  Anyone have some suggestions?
>
>  Again, sorry for the long message.
>
>  Regards,
>
> Hartley
>

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-25  9:29                                                       ` [spi-devel-general] " Martin Guy
@ 2010-04-25  9:38                                                           ` Martin Guy
  -1 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-25  9:38 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Sorry about the incomplete message. Finger trouble.

On 4/25/10, Martin Guy <martinwguy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
...
>  SFRMOUT will have gone high:

>         if (espi->tx  >0 && espi->tx < t->len
               && !(ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_BSY)) {
>                 /* More to transmit but device has gone idle means that
>                  * SFRMOUT will have gone high */
>                 printk("ep93xx-spi: Underrun\n");
>         }

I've also done a version that doesn't printk() in the middle of it,
which affects timing, but counts the underruns and reports at end of
transfer. The result is that every 512-byte block underruns at least
once, sometimes twice.

I'll run a few more tests, e.g. dropping the clock rate, but at this
point I'd be inclined to declare it impossible to keep SFRMOUT low
during a transfer, and just use the simple non-continuous code with a
comment at the top of the file that explains why you can't use SFRMOUT
as a chip select for devices that require CS to remain asserted for
the duration of a transfer.

    M

------------------------------------------------------------------------------

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

* [spi-devel-general] [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-25  9:38                                                           ` Martin Guy
  0 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-25  9:38 UTC (permalink / raw)
  To: linux-arm-kernel

Sorry about the incomplete message. Finger trouble.

On 4/25/10, Martin Guy <martinwguy@gmail.com> wrote:
...
>  SFRMOUT will have gone high:

>         if (espi->tx  >0 && espi->tx < t->len
               && !(ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_BSY)) {
>                 /* More to transmit but device has gone idle means that
>                  * SFRMOUT will have gone high */
>                 printk("ep93xx-spi: Underrun\n");
>         }

I've also done a version that doesn't printk() in the middle of it,
which affects timing, but counts the underruns and reports at end of
transfer. The result is that every 512-byte block underruns at least
once, sometimes twice.

I'll run a few more tests, e.g. dropping the clock rate, but at this
point I'd be inclined to declare it impossible to keep SFRMOUT low
during a transfer, and just use the simple non-continuous code with a
comment at the top of the file that explains why you can't use SFRMOUT
as a chip select for devices that require CS to remain asserted for
the duration of a transfer.

    M

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-24 18:14         ` Martin Guy
@ 2010-04-25 19:55             ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-25 19:55 UTC (permalink / raw)
  To: Martin Guy, Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Saturday, April 24, 2010 11:15 AM, Martin Guy wrote:
> Hi, another little fix:
> 
> EP93xx User's Manual -> Synchronous Serial Port -> Registers
> 
> SSPIIR description:
> "Read Only
> Note: A write to this register clears the receive overrun interrupt,
> regardless of the data
>       value written."
> 
> It doesn't affect the RIS/TIS ones, which are caused by the state of the device.
> 
> so
> 
> static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
> {
> ...
>         if (!(irq_status & (SSPIIR_RORIS | SSPIIR_TIS | SSPIIR_RIS)))
>                 return IRQ_NONE; /* not for us */
> 
> -       /* clear the interrupt */
> -       ep93xx_spi_write_u8(espi, SSPICR, 0);
> 
>         /*
>          * If we got ROR (receive overrun) interrupt we know that something is
>          * wrong. Just abort the message.
>          */
>         if (unlikely(irq_status & SSPIIR_RORIS)) {
> +               /* clear the overrun interrupt */
> +               ep93xx_spi_write_u8(espi, SSPICR, 0);
>                 dev_warn(&espi->pdev->dev,
>                          "receive overrun, aborting the message\n");
>                 espi->current_msg->status = -EIO;
>         } else {

With this patch the interrupts only get cleared if it's a ROR interrupt.

Do the RIS/TIS interrupts get cleared by the upper layers?  If so, do we
really need to clear the ROR interrupt here?

Regards,
Hartley
------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-25 19:55             ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-25 19:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Saturday, April 24, 2010 11:15 AM, Martin Guy wrote:
> Hi, another little fix:
> 
> EP93xx User's Manual -> Synchronous Serial Port -> Registers
> 
> SSPIIR description:
> "Read Only
> Note: A write to this register clears the receive overrun interrupt,
> regardless of the data
>       value written."
> 
> It doesn't affect the RIS/TIS ones, which are caused by the state of the device.
> 
> so
> 
> static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
> {
> ...
>         if (!(irq_status & (SSPIIR_RORIS | SSPIIR_TIS | SSPIIR_RIS)))
>                 return IRQ_NONE; /* not for us */
> 
> -       /* clear the interrupt */
> -       ep93xx_spi_write_u8(espi, SSPICR, 0);
> 
>         /*
>          * If we got ROR (receive overrun) interrupt we know that something is
>          * wrong. Just abort the message.
>          */
>         if (unlikely(irq_status & SSPIIR_RORIS)) {
> +               /* clear the overrun interrupt */
> +               ep93xx_spi_write_u8(espi, SSPICR, 0);
>                 dev_warn(&espi->pdev->dev,
>                          "receive overrun, aborting the message\n");
>                 espi->current_msg->status = -EIO;
>         } else {

With this patch the interrupts only get cleared if it's a ROR interrupt.

Do the RIS/TIS interrupts get cleared by the upper layers?  If so, do we
really need to clear the ROR interrupt here?

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-25  9:38                                                           ` [spi-devel-general] " Martin Guy
@ 2010-04-25 20:25                                                               ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-25 20:25 UTC (permalink / raw)
  To: Martin Guy
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Sunday, April 25, 2010 2:39 AM, Martin Guy wrote:
>
> Sorry about the incomplete message. Finger trouble.
>
> On 4/25/10, Martin Guy <martinwguy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> ...
>>  SFRMOUT will have gone high:
>
>>         if (espi->tx  >0 && espi->tx < t->len
>>               && !(ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_BSY)) {
>>                 /* More to transmit but device has gone idle means that
>>                  * SFRMOUT will have gone high */
>>                 printk("ep93xx-spi: Underrun\n");
>>         }
>
> I've also done a version that doesn't printk() in the middle of it,
> which affects timing, but counts the underruns and reports at end of
> transfer. The result is that every 512-byte block underruns at least
> once, sometimes twice.

I haven't actually looked for the underrun by checking the SSPSR_BSY
bit but my guess is actually underruns a lot more than that.  Depends
on where you are doing the check above on if you actually see it.

During the 512+2+1 message that is sent when the mmc_spi driver is
doing a block read, the 512 byte transfer goes like this:

1) 8 writes, prime the tx fifo
	SFRMOUT asserts when the first bit of the first byte starts 
	transmitting
2) Interrupt
3) 8 reads, we must have emptied the tx fifo and filled the rx fifo
	SFRMOUT de-asserts after the the last bit of the last byte is
	received
4) 8 writes, fifo's are empty so we re-fill them
	SFRMOUT asserts when the first bit of the first byte starts 
	transmitting
5) end of interupt
6) go back to 2

Basically, anytime the espi->fifo_level == 8 and we can do an 8 byte
read you have to assume that the SFRMOUT signal has already been de-
asserted.

This matches what I am seeing with the logic analyzer.

I have modifed my board so that I now have an external GPIO for the chip
select.  That chip select goes low then shortly after, the SFRMOUT signal
goes low and 8 bytes are pumped out then SFRMOUT goes back high.  A bit 
later the interrupt happens, indicated by another GPIO I toggle in the
interrupt routine.  Right before the interrupt ends I again see SFRMOUT
go low and 8 more bytes are pumped out.  The interrupt actually completes
before the data is all pumped out.  But again SFRMOUT gets de-asserted
before the next interrupt occurs.  This keeps happening until all the
data in the message is finally transferred, at which point the external
GPIO chip select is finally de-asserted.

> I'll run a few more tests, e.g. dropping the clock rate, but at this
> point I'd be inclined to declare it impossible to keep SFRMOUT low
> during a transfer, and just use the simple non-continuous code with a
> comment at the top of the file that explains why you can't use SFRMOUT
> as a chip select for devices that require CS to remain asserted for
> the duration of a transfer.

With a slow enough clock you can probably get to a point where SFRMOUT
will stay deasserted during the entire 512 byte transfer.  But it would
still de-assert during the switch to the next transfer in the message.

Regardless, I tend to agree with you.  Because of the chip design, it's
impossible (or at least you can't guarantee) to keep the SFRMOUT low
during a transfer.  Some devices can live with this others can't.  Oh well.

A Documentation/spi/ep93xx_spi.txt really should be created to note this
limitation as well as showing an example of the platform support needed to
use this driver.

Regards,
Hartley
------------------------------------------------------------------------------

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

* [spi-devel-general] [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-25 20:25                                                               ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-25 20:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday, April 25, 2010 2:39 AM, Martin Guy wrote:
>
> Sorry about the incomplete message. Finger trouble.
>
> On 4/25/10, Martin Guy <martinwguy@gmail.com> wrote:
> ...
>>  SFRMOUT will have gone high:
>
>>         if (espi->tx  >0 && espi->tx < t->len
>>               && !(ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_BSY)) {
>>                 /* More to transmit but device has gone idle means that
>>                  * SFRMOUT will have gone high */
>>                 printk("ep93xx-spi: Underrun\n");
>>         }
>
> I've also done a version that doesn't printk() in the middle of it,
> which affects timing, but counts the underruns and reports at end of
> transfer. The result is that every 512-byte block underruns at least
> once, sometimes twice.

I haven't actually looked for the underrun by checking the SSPSR_BSY
bit but my guess is actually underruns a lot more than that.  Depends
on where you are doing the check above on if you actually see it.

During the 512+2+1 message that is sent when the mmc_spi driver is
doing a block read, the 512 byte transfer goes like this:

1) 8 writes, prime the tx fifo
	SFRMOUT asserts when the first bit of the first byte starts 
	transmitting
2) Interrupt
3) 8 reads, we must have emptied the tx fifo and filled the rx fifo
	SFRMOUT de-asserts after the the last bit of the last byte is
	received
4) 8 writes, fifo's are empty so we re-fill them
	SFRMOUT asserts when the first bit of the first byte starts 
	transmitting
5) end of interupt
6) go back to 2

Basically, anytime the espi->fifo_level == 8 and we can do an 8 byte
read you have to assume that the SFRMOUT signal has already been de-
asserted.

This matches what I am seeing with the logic analyzer.

I have modifed my board so that I now have an external GPIO for the chip
select.  That chip select goes low then shortly after, the SFRMOUT signal
goes low and 8 bytes are pumped out then SFRMOUT goes back high.  A bit 
later the interrupt happens, indicated by another GPIO I toggle in the
interrupt routine.  Right before the interrupt ends I again see SFRMOUT
go low and 8 more bytes are pumped out.  The interrupt actually completes
before the data is all pumped out.  But again SFRMOUT gets de-asserted
before the next interrupt occurs.  This keeps happening until all the
data in the message is finally transferred, at which point the external
GPIO chip select is finally de-asserted.

> I'll run a few more tests, e.g. dropping the clock rate, but at this
> point I'd be inclined to declare it impossible to keep SFRMOUT low
> during a transfer, and just use the simple non-continuous code with a
> comment at the top of the file that explains why you can't use SFRMOUT
> as a chip select for devices that require CS to remain asserted for
> the duration of a transfer.

With a slow enough clock you can probably get to a point where SFRMOUT
will stay deasserted during the entire 512 byte transfer.  But it would
still de-assert during the switch to the next transfer in the message.

Regardless, I tend to agree with you.  Because of the chip design, it's
impossible (or at least you can't guarantee) to keep the SFRMOUT low
during a transfer.  Some devices can live with this others can't.  Oh well.

A Documentation/spi/ep93xx_spi.txt really should be created to note this
limitation as well as showing an example of the platform support needed to
use this driver.

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-25 20:25                                                               ` [spi-devel-general] " H Hartley Sweeten
@ 2010-04-26 10:02                                                                   ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-26 10:02 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi,

I just answer to this last message as it seems that continuous
transfer is really not a 100% solid solution; It makes things more
complicated than need to be and benefit for that is probably not
worth the additional complexity. Feel free to disagree :)

On Sun, Apr 25, 2010 at 03:25:16PM -0500, H Hartley Sweeten wrote:
> On Sunday, April 25, 2010 2:39 AM, Martin Guy wrote:
> > I'll run a few more tests, e.g. dropping the clock rate, but at this
> > point I'd be inclined to declare it impossible to keep SFRMOUT low
> > during a transfer, and just use the simple non-continuous code with a
> > comment at the top of the file that explains why you can't use SFRMOUT
> > as a chip select for devices that require CS to remain asserted for
> > the duration of a transfer.
> 
> With a slow enough clock you can probably get to a point where SFRMOUT
> will stay deasserted during the entire 512 byte transfer.  But it would
> still de-assert during the switch to the next transfer in the message.
> 
> Regardless, I tend to agree with you.  Because of the chip design, it's
> impossible (or at least you can't guarantee) to keep the SFRMOUT low
> during a transfer.  Some devices can live with this others can't.  Oh well.

For the MMC over SPI at least we really cannot ever make fully
compliant solution with SFRMOUT because, during init phase protocol
sends CMD0 (reset) with chipselect active high (SPI_CS_HIGH). This
forces SD/MMC card to SPI mode. However, many cards seem to work
without any chipselect logic at all (with Sim.One for example).

> A Documentation/spi/ep93xx_spi.txt really should be created to note this
> limitation as well as showing an example of the platform support needed to
> use this driver.

Do we all agree that we can live with GPIOs as chipselect? Or do
we continue investigation to make it work with boards that use
SFRMOUT as CS?

I have following plans for v5 (in case we don't care about SFRMOUT).
Before doing the changes I would like to hear your opinnion.

	- prime the FIFO first in every transfer (Hartley's suggestion)
	- address review comments for v4
	- add Martin's patch for clearing SSPICR only if we get ROR
	- add necessary documentation under Documentation/spi/ep93xx_spi.txt

Thanks,
MW

------------------------------------------------------------------------------

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

* [spi-devel-general] [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-26 10:02                                                                   ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-26 10:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

I just answer to this last message as it seems that continuous
transfer is really not a 100% solid solution; It makes things more
complicated than need to be and benefit for that is probably not
worth the additional complexity. Feel free to disagree :)

On Sun, Apr 25, 2010 at 03:25:16PM -0500, H Hartley Sweeten wrote:
> On Sunday, April 25, 2010 2:39 AM, Martin Guy wrote:
> > I'll run a few more tests, e.g. dropping the clock rate, but at this
> > point I'd be inclined to declare it impossible to keep SFRMOUT low
> > during a transfer, and just use the simple non-continuous code with a
> > comment at the top of the file that explains why you can't use SFRMOUT
> > as a chip select for devices that require CS to remain asserted for
> > the duration of a transfer.
> 
> With a slow enough clock you can probably get to a point where SFRMOUT
> will stay deasserted during the entire 512 byte transfer.  But it would
> still de-assert during the switch to the next transfer in the message.
> 
> Regardless, I tend to agree with you.  Because of the chip design, it's
> impossible (or at least you can't guarantee) to keep the SFRMOUT low
> during a transfer.  Some devices can live with this others can't.  Oh well.

For the MMC over SPI at least we really cannot ever make fully
compliant solution with SFRMOUT because, during init phase protocol
sends CMD0 (reset) with chipselect active high (SPI_CS_HIGH). This
forces SD/MMC card to SPI mode. However, many cards seem to work
without any chipselect logic at all (with Sim.One for example).

> A Documentation/spi/ep93xx_spi.txt really should be created to note this
> limitation as well as showing an example of the platform support needed to
> use this driver.

Do we all agree that we can live with GPIOs as chipselect? Or do
we continue investigation to make it work with boards that use
SFRMOUT as CS?

I have following plans for v5 (in case we don't care about SFRMOUT).
Before doing the changes I would like to hear your opinnion.

	- prime the FIFO first in every transfer (Hartley's suggestion)
	- address review comments for v4
	- add Martin's patch for clearing SSPICR only if we get ROR
	- add necessary documentation under Documentation/spi/ep93xx_spi.txt

Thanks,
MW

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-25 20:25                                                               ` [spi-devel-general] " H Hartley Sweeten
@ 2010-04-26 10:09                                                                   ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-26 10:09 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Sun, Apr 25, 2010 at 03:25:16PM -0500, H Hartley Sweeten wrote:
> With a slow enough clock you can probably get to a point where SFRMOUT
> will stay deasserted during the entire 512 byte transfer.  But it would
> still de-assert during the switch to the next transfer in the message.
> 
> Regardless, I tend to agree with you.  Because of the chip design, it's
> impossible (or at least you can't guarantee) to keep the SFRMOUT low
> during a transfer.  Some devices can live with this others can't.  Oh well.

One more thing I forgot to mention. With DMA there are 2 buffers per channel which
means that the controller can continue right to the next transfer so SFRMOUT might
work better.

Regards,
MW

------------------------------------------------------------------------------

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

* [spi-devel-general] [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-26 10:09                                                                   ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-26 10:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Apr 25, 2010 at 03:25:16PM -0500, H Hartley Sweeten wrote:
> With a slow enough clock you can probably get to a point where SFRMOUT
> will stay deasserted during the entire 512 byte transfer.  But it would
> still de-assert during the switch to the next transfer in the message.
> 
> Regardless, I tend to agree with you.  Because of the chip design, it's
> impossible (or at least you can't guarantee) to keep the SFRMOUT low
> during a transfer.  Some devices can live with this others can't.  Oh well.

One more thing I forgot to mention. With DMA there are 2 buffers per channel which
means that the controller can continue right to the next transfer so SFRMOUT might
work better.

Regards,
MW

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-25 19:55             ` H Hartley Sweeten
@ 2010-04-26 10:34                 ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-26 10:34 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Sun, Apr 25, 2010 at 02:55:08PM -0500, H Hartley Sweeten wrote:
> On Saturday, April 24, 2010 11:15 AM, Martin Guy wrote:
> > static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
> > {
> > ...
> >         if (!(irq_status & (SSPIIR_RORIS | SSPIIR_TIS | SSPIIR_RIS)))
> >                 return IRQ_NONE; /* not for us */
> > 
> > -       /* clear the interrupt */
> > -       ep93xx_spi_write_u8(espi, SSPICR, 0);
> > 
> >         /*
> >          * If we got ROR (receive overrun) interrupt we know that something is
> >          * wrong. Just abort the message.
> >          */
> >         if (unlikely(irq_status & SSPIIR_RORIS)) {
> > +               /* clear the overrun interrupt */
> > +               ep93xx_spi_write_u8(espi, SSPICR, 0);
> >                 dev_warn(&espi->pdev->dev,
> >                          "receive overrun, aborting the message\n");
> >                 espi->current_msg->status = -EIO;
> >         } else {
> 
> With this patch the interrupts only get cleared if it's a ROR interrupt.
> 
> Do the RIS/TIS interrupts get cleared by the upper layers?  If so, do we
> really need to clear the ROR interrupt here?

I believe it is not necessary but doesn't hurt either so I would keep it.

Regards,
MW

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-26 10:34                 ` Mika Westerberg
  0 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-26 10:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Apr 25, 2010 at 02:55:08PM -0500, H Hartley Sweeten wrote:
> On Saturday, April 24, 2010 11:15 AM, Martin Guy wrote:
> > static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
> > {
> > ...
> >         if (!(irq_status & (SSPIIR_RORIS | SSPIIR_TIS | SSPIIR_RIS)))
> >                 return IRQ_NONE; /* not for us */
> > 
> > -       /* clear the interrupt */
> > -       ep93xx_spi_write_u8(espi, SSPICR, 0);
> > 
> >         /*
> >          * If we got ROR (receive overrun) interrupt we know that something is
> >          * wrong. Just abort the message.
> >          */
> >         if (unlikely(irq_status & SSPIIR_RORIS)) {
> > +               /* clear the overrun interrupt */
> > +               ep93xx_spi_write_u8(espi, SSPICR, 0);
> >                 dev_warn(&espi->pdev->dev,
> >                          "receive overrun, aborting the message\n");
> >                 espi->current_msg->status = -EIO;
> >         } else {
> 
> With this patch the interrupts only get cleared if it's a ROR interrupt.
> 
> Do the RIS/TIS interrupts get cleared by the upper layers?  If so, do we
> really need to clear the ROR interrupt here?

I believe it is not necessary but doesn't hurt either so I would keep it.

Regards,
MW

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-25 19:55             ` H Hartley Sweeten
@ 2010-04-26 12:58                 ` Martin Guy
  -1 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-26 12:58 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 4/25/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
>  > -       /* clear the interrupt */
>  > -       ep93xx_spi_write_u8(espi, SSPICR, 0);
>  >
>  >         /*
>  >          * If we got ROR (receive overrun) interrupt we know that something is
>  >          * wrong. Just abort the message.
>  >          */
>  >         if (unlikely(irq_status & SSPIIR_RORIS)) {
>  > +               /* clear the overrun interrupt */
>  > +               ep93xx_spi_write_u8(espi, SSPICR, 0);
>  >                 dev_warn(&espi->pdev->dev,
>  >                          "receive overrun, aborting the message\n");
>  >                 espi->current_msg->status = -EIO;
>  >         } else {
>
> With this patch the interrupts only get cleared if it's a ROR interrupt.
>
>  Do the RIS/TIS interrupts get cleared by the upper layers?  If so, do we
>  really need to clear the ROR interrupt here?

RX/TX interrupts are cleared by emptying the RX FIFO or filling the TX
FIFO to less/more than half full. There is no explicit clearing of the
IRQ.

The ROR interrupt instead remains active until you explicitly clear it
by writing (anything( to SSPICR, so it would remain on forever
otherwise.

    M

------------------------------------------------------------------------------

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-26 12:58                 ` Martin Guy
  0 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-26 12:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 4/25/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
>  > -       /* clear the interrupt */
>  > -       ep93xx_spi_write_u8(espi, SSPICR, 0);
>  >
>  >         /*
>  >          * If we got ROR (receive overrun) interrupt we know that something is
>  >          * wrong. Just abort the message.
>  >          */
>  >         if (unlikely(irq_status & SSPIIR_RORIS)) {
>  > +               /* clear the overrun interrupt */
>  > +               ep93xx_spi_write_u8(espi, SSPICR, 0);
>  >                 dev_warn(&espi->pdev->dev,
>  >                          "receive overrun, aborting the message\n");
>  >                 espi->current_msg->status = -EIO;
>  >         } else {
>
> With this patch the interrupts only get cleared if it's a ROR interrupt.
>
>  Do the RIS/TIS interrupts get cleared by the upper layers?  If so, do we
>  really need to clear the ROR interrupt here?

RX/TX interrupts are cleared by emptying the RX FIFO or filling the TX
FIFO to less/more than half full. There is no explicit clearing of the
IRQ.

The ROR interrupt instead remains active until you explicitly clear it
by writing (anything( to SSPICR, so it would remain on forever
otherwise.

    M

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-25 20:25                                                               ` [spi-devel-general] " H Hartley Sweeten
@ 2010-04-26 14:35                                                                   ` Martin Guy
  -1 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-26 14:35 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 4/25/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
>  During the 512+2+1 message that is sent when the mmc_spi driver is
>  doing a block read, the 512 byte transfer goes like this:
>
>  1) 8 writes, prime the tx fifo
>         SFRMOUT asserts when the first bit of the first byte starts
>         transmitting
>  2) Interrupt
>  3) 8 reads, we must have emptied the tx fifo and filled the rx fifo
>         SFRMOUT de-asserts after the the last bit of the last byte is
>         received

Are you printk-ing the diagnostics in the irq routine?
If so, that slows it down enough to ensure every 8-word block underruns.

Here are stats for 512-word transfers from SD card at 3.7 MHz; figures are
number of underruns/total number of reads and the distribution of
words read per interrupt [0..8], collected during the transfer and
printed once the transfer is over)

1/102 [1,0,2,0,0,100,0,0,1]
1/102 [1,0,2,0,0,100,0,0,1]
1/102 [1,0,2,0,0,100,0,0,1]
2/104 [1,1,0,2,21,76,3,1,2]
3/102 [1,1,1,1,11,85,1,1,3]
4/100 [1,0,1,1,7,83,3,2,4]

while 1- and 2-word transfers seem to be caught on the second interrupt.
[1,2,0,0,0,0,0,0,0]
[1,1,0,0,0,0,0,0,0]


>  I have modifed my board so that I now have an external GPIO for the chip
>  select.
Yes, we'll have to do that too.

>  > I'll run a few more tests, e.g. dropping the clock rate
>
> With a slow enough clock you can probably get to a point where SFRMOUT
>  will stay deasserted during the entire 512 byte transfer

I've tried it down to 400kHz and transfers still underrun (!)

So it does seem that SFRMOUT cannot be used as a chip select unless we
revert to the old busy-wait-for-whole-transfer code, which causes 100%
CPU usage during transfers.
and 1ms-long pauses (for 512 words at 3.7MHz).

This suggests that we can only handle SFRMOUT used as chip select
correctly by reinstating polling mode, adding the continuous transfer
code and allowing the board definition code to specify that polling
mode be used for such devices.
(much as I hate polling mode :)

>  But it would
>  still de-assert during the switch to the next transfer in the message.

Am I right in thinking that the GPIO chip select currently remains
asserted as it should during a multi-transfer message?

    M

------------------------------------------------------------------------------

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

* [spi-devel-general] [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-26 14:35                                                                   ` Martin Guy
  0 siblings, 0 replies; 89+ messages in thread
From: Martin Guy @ 2010-04-26 14:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 4/25/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
>  During the 512+2+1 message that is sent when the mmc_spi driver is
>  doing a block read, the 512 byte transfer goes like this:
>
>  1) 8 writes, prime the tx fifo
>         SFRMOUT asserts when the first bit of the first byte starts
>         transmitting
>  2) Interrupt
>  3) 8 reads, we must have emptied the tx fifo and filled the rx fifo
>         SFRMOUT de-asserts after the the last bit of the last byte is
>         received

Are you printk-ing the diagnostics in the irq routine?
If so, that slows it down enough to ensure every 8-word block underruns.

Here are stats for 512-word transfers from SD card at 3.7 MHz; figures are
number of underruns/total number of reads and the distribution of
words read per interrupt [0..8], collected during the transfer and
printed once the transfer is over)

1/102 [1,0,2,0,0,100,0,0,1]
1/102 [1,0,2,0,0,100,0,0,1]
1/102 [1,0,2,0,0,100,0,0,1]
2/104 [1,1,0,2,21,76,3,1,2]
3/102 [1,1,1,1,11,85,1,1,3]
4/100 [1,0,1,1,7,83,3,2,4]

while 1- and 2-word transfers seem to be caught on the second interrupt.
[1,2,0,0,0,0,0,0,0]
[1,1,0,0,0,0,0,0,0]


>  I have modifed my board so that I now have an external GPIO for the chip
>  select.
Yes, we'll have to do that too.

>  > I'll run a few more tests, e.g. dropping the clock rate
>
> With a slow enough clock you can probably get to a point where SFRMOUT
>  will stay deasserted during the entire 512 byte transfer

I've tried it down to 400kHz and transfers still underrun (!)

So it does seem that SFRMOUT cannot be used as a chip select unless we
revert to the old busy-wait-for-whole-transfer code, which causes 100%
CPU usage during transfers.
and 1ms-long pauses (for 512 words at 3.7MHz).

This suggests that we can only handle SFRMOUT used as chip select
correctly by reinstating polling mode, adding the continuous transfer
code and allowing the board definition code to specify that polling
mode be used for such devices.
(much as I hate polling mode :)

>  But it would
>  still de-assert during the switch to the next transfer in the message.

Am I right in thinking that the GPIO chip select currently remains
asserted as it should during a multi-transfer message?

    M

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-26 10:02                                                                   ` [spi-devel-general] " Mika Westerberg
@ 2010-04-26 16:54                                                                       ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-26 16:54 UTC (permalink / raw)
  To: Mika Westerberg
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Martin Guy,
	ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Monday, April 26, 2010 3:03 AM, Mika Westerberg wrote:
>
> Hi,
>
> I just answer to this last message as it seems that continuous
> transfer is really not a 100% solid solution; It makes things more
> complicated than need to be and benefit for that is probably not
> worth the additional complexity. Feel free to disagree :)

I agree.  Trying to make the transfer continuous is not solid and
does complicate the code.  Drop it.

> On Sun, Apr 25, 2010 at 03:25:16PM -0500, H Hartley Sweeten wrote:
>> On Sunday, April 25, 2010 2:39 AM, Martin Guy wrote:
>>> I'll run a few more tests, e.g. dropping the clock rate, but at this
>>> point I'd be inclined to declare it impossible to keep SFRMOUT low
>>> during a transfer, and just use the simple non-continuous code with a
>>> comment at the top of the file that explains why you can't use SFRMOUT
>>> as a chip select for devices that require CS to remain asserted for
>>> the duration of a transfer.
>> 
>> With a slow enough clock you can probably get to a point where SFRMOUT
>> will stay deasserted during the entire 512 byte transfer.  But it would
>> still de-assert during the switch to the next transfer in the message.
>> 
>> Regardless, I tend to agree with you.  Because of the chip design, it's
>> impossible (or at least you can't guarantee) to keep the SFRMOUT low
>> during a transfer.  Some devices can live with this others can't.  Oh well.
>
> For the MMC over SPI at least we really cannot ever make fully
> compliant solution with SFRMOUT because, during init phase protocol
> sends CMD0 (reset) with chipselect active high (SPI_CS_HIGH). This
> forces SD/MMC card to SPI mode. However, many cards seem to work
> without any chipselect logic at all (with Sim.One for example).

Good point.  Any driver that requests SPI_CS_HIGH will be "broken" by using
the SFRMOUT signal for the chip select.  I think the Sim.One board test
have just been lucky with the mmc/sc-cards.  There are probably many cards
that will not work correctly on that platform.

> A Documentation/spi/ep93xx_spi.txt really should be created to note this
> limitation as well as showing an example of the platform support needed to
> use this driver.

> Do we all agree that we can live with GPIOs as chipselect? Or do
> we continue investigation to make it work with boards that use
> SFRMOUT as CS?

I think we can live with the GPIOs for chip selects.

> I have following plans for v5 (in case we don't care about SFRMOUT).
> Before doing the changes I would like to hear your opinnion.
> 
> 	- prime the FIFO first in every transfer (Hartley's suggestion)

I think this helps regardless.  I makes sure the hardware is actually
doing something when a transfer starts instead of waiting for the first
interrupt to get things going.

> 	- address review comments for v4
> 	- add Martin's patch for clearing SSPICR only if we get ROR

Moving the interrupt clear into the unlikely() path probably makes sense.
It keeps the code from having to do the unnecessary memory write every time.

Also, is the IRQ_NONE check before that really necessary?  The IRQ_EP93XX_SSP
is not a chained interrupt so if ep93xx_spi_interrupt gets called I would
assume the interrupt must be valid.

> 	- add necessary documentation under Documentation/spi/ep93xx_spi.txt

Sounds good.

Once you post the v5 version I will test it then send you a patch for allowing
non-built-in GPIOs to be used for chip selects.

Regards,
Hartley

------------------------------------------------------------------------------

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

* [spi-devel-general] [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-26 16:54                                                                       ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-26 16:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday, April 26, 2010 3:03 AM, Mika Westerberg wrote:
>
> Hi,
>
> I just answer to this last message as it seems that continuous
> transfer is really not a 100% solid solution; It makes things more
> complicated than need to be and benefit for that is probably not
> worth the additional complexity. Feel free to disagree :)

I agree.  Trying to make the transfer continuous is not solid and
does complicate the code.  Drop it.

> On Sun, Apr 25, 2010 at 03:25:16PM -0500, H Hartley Sweeten wrote:
>> On Sunday, April 25, 2010 2:39 AM, Martin Guy wrote:
>>> I'll run a few more tests, e.g. dropping the clock rate, but at this
>>> point I'd be inclined to declare it impossible to keep SFRMOUT low
>>> during a transfer, and just use the simple non-continuous code with a
>>> comment at the top of the file that explains why you can't use SFRMOUT
>>> as a chip select for devices that require CS to remain asserted for
>>> the duration of a transfer.
>> 
>> With a slow enough clock you can probably get to a point where SFRMOUT
>> will stay deasserted during the entire 512 byte transfer.  But it would
>> still de-assert during the switch to the next transfer in the message.
>> 
>> Regardless, I tend to agree with you.  Because of the chip design, it's
>> impossible (or at least you can't guarantee) to keep the SFRMOUT low
>> during a transfer.  Some devices can live with this others can't.  Oh well.
>
> For the MMC over SPI at least we really cannot ever make fully
> compliant solution with SFRMOUT because, during init phase protocol
> sends CMD0 (reset) with chipselect active high (SPI_CS_HIGH). This
> forces SD/MMC card to SPI mode. However, many cards seem to work
> without any chipselect logic at all (with Sim.One for example).

Good point.  Any driver that requests SPI_CS_HIGH will be "broken" by using
the SFRMOUT signal for the chip select.  I think the Sim.One board test
have just been lucky with the mmc/sc-cards.  There are probably many cards
that will not work correctly on that platform.

> A Documentation/spi/ep93xx_spi.txt really should be created to note this
> limitation as well as showing an example of the platform support needed to
> use this driver.

> Do we all agree that we can live with GPIOs as chipselect? Or do
> we continue investigation to make it work with boards that use
> SFRMOUT as CS?

I think we can live with the GPIOs for chip selects.

> I have following plans for v5 (in case we don't care about SFRMOUT).
> Before doing the changes I would like to hear your opinnion.
> 
> 	- prime the FIFO first in every transfer (Hartley's suggestion)

I think this helps regardless.  I makes sure the hardware is actually
doing something when a transfer starts instead of waiting for the first
interrupt to get things going.

> 	- address review comments for v4
> 	- add Martin's patch for clearing SSPICR only if we get ROR

Moving the interrupt clear into the unlikely() path probably makes sense.
It keeps the code from having to do the unnecessary memory write every time.

Also, is the IRQ_NONE check before that really necessary?  The IRQ_EP93XX_SSP
is not a chained interrupt so if ep93xx_spi_interrupt gets called I would
assume the interrupt must be valid.

> 	- add necessary documentation under Documentation/spi/ep93xx_spi.txt

Sounds good.

Once you post the v5 version I will test it then send you a patch for allowing
non-built-in GPIOs to be used for chip selects.

Regards,
Hartley

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

* Re: [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-26 14:35                                                                   ` [spi-devel-general] " Martin Guy
@ 2010-04-26 17:05                                                                       ` H Hartley Sweeten
  -1 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-26 17:05 UTC (permalink / raw)
  To: Martin Guy
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	Mika Westerberg, ryan-7Wk5F4Od5/oYd5yxfr4S2w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Monday, April 26, 2010 7:36 AM, Martin Guy wrote:
> On 4/25/10, H Hartley Sweeten <hartleys-3FF4nKcrg1dE2c76skzGb0EOCMrvLtNR@public.gmane.org> wrote:
>>  During the 512+2+1 message that is sent when the mmc_spi driver is
>>  doing a block read, the 512 byte transfer goes like this:
>>
>>  1) 8 writes, prime the tx fifo
>>         SFRMOUT asserts when the first bit of the first byte starts
>>         transmitting
>>  2) Interrupt
>>  3) 8 reads, we must have emptied the tx fifo and filled the rx fifo
>>         SFRMOUT de-asserts after the the last bit of the last byte is
>>         received
>
> Are you printk-ing the diagnostics in the irq routine?
> If so, that slows it down enough to ensure every 8-word block underruns.

No, all my printk's happen outside the interrupt context.

> Here are stats for 512-word transfers from SD card at 3.7 MHz; figures are
> number of underruns/total number of reads and the distribution of
> words read per interrupt [0..8], collected during the transfer and
> printed once the transfer is over)
> 
> 1/102 [1,0,2,0,0,100,0,0,1]
> 1/102 [1,0,2,0,0,100,0,0,1]
> 1/102 [1,0,2,0,0,100,0,0,1]
> 2/104 [1,1,0,2,21,76,3,1,2]
> 3/102 [1,1,1,1,11,85,1,1,3]
> 4/100 [1,0,1,1,7,83,3,2,4]
> 
> while 1- and 2-word transfers seem to be caught on the second interrupt.
> [1,2,0,0,0,0,0,0,0]
> [1,1,0,0,0,0,0,0,0]

External stuff could be causing the differences.  In my testing, I only have
the mmc_spi driver running since I was trying to capture it on the logic
analyzer.  Ethernet, etc. are all shutdown.

>> I have modifed my board so that I now have an external GPIO for the chip
>> select.
> Yes, we'll have to do that too.

>>> I'll run a few more tests, e.g. dropping the clock rate
>>
>> With a slow enough clock you can probably get to a point where SFRMOUT
>>  will stay deasserted during the entire 512 byte transfer
>
> I've tried it down to 400kHz and transfers still underrun (!)
>
> So it does seem that SFRMOUT cannot be used as a chip select unless we
> revert to the old busy-wait-for-whole-transfer code, which causes 100%
> CPU usage during transfers.
> and 1ms-long pauses (for 512 words at 3.7MHz).
>
> This suggests that we can only handle SFRMOUT used as chip select
> correctly by reinstating polling mode, adding the continuous transfer
> code and allowing the board definition code to specify that polling
> mode be used for such devices.
> (much as I hate polling mode :)

I don't think we should worry about polling mode for now.  With the
external GPIO chip select we don't have to worry about what the SFRMOUT
signal is doing.

>>  But it would
>  still de-assert during the switch to the next transfer in the message.
>
> Am I right in thinking that the GPIO chip select currently remains
> asserted as it should during a multi-transfer message?

Yes.  It gets asserted at the start and de-asserted at the end of
ep93xx_spi_process_message.

Actually, I think your supposed to check the cs_change flag at the end
of the message to see if the protocol is hinting to leave the chip
select asserted for the next message.  Of course this also means you need
to verify that the next message is actually for the same device.

Regards,
Hartley
------------------------------------------------------------------------------

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

* [spi-devel-general] [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
@ 2010-04-26 17:05                                                                       ` H Hartley Sweeten
  0 siblings, 0 replies; 89+ messages in thread
From: H Hartley Sweeten @ 2010-04-26 17:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday, April 26, 2010 7:36 AM, Martin Guy wrote:
> On 4/25/10, H Hartley Sweeten <hartleys@visionengravers.com> wrote:
>>  During the 512+2+1 message that is sent when the mmc_spi driver is
>>  doing a block read, the 512 byte transfer goes like this:
>>
>>  1) 8 writes, prime the tx fifo
>>         SFRMOUT asserts when the first bit of the first byte starts
>>         transmitting
>>  2) Interrupt
>>  3) 8 reads, we must have emptied the tx fifo and filled the rx fifo
>>         SFRMOUT de-asserts after the the last bit of the last byte is
>>         received
>
> Are you printk-ing the diagnostics in the irq routine?
> If so, that slows it down enough to ensure every 8-word block underruns.

No, all my printk's happen outside the interrupt context.

> Here are stats for 512-word transfers from SD card at 3.7 MHz; figures are
> number of underruns/total number of reads and the distribution of
> words read per interrupt [0..8], collected during the transfer and
> printed once the transfer is over)
> 
> 1/102 [1,0,2,0,0,100,0,0,1]
> 1/102 [1,0,2,0,0,100,0,0,1]
> 1/102 [1,0,2,0,0,100,0,0,1]
> 2/104 [1,1,0,2,21,76,3,1,2]
> 3/102 [1,1,1,1,11,85,1,1,3]
> 4/100 [1,0,1,1,7,83,3,2,4]
> 
> while 1- and 2-word transfers seem to be caught on the second interrupt.
> [1,2,0,0,0,0,0,0,0]
> [1,1,0,0,0,0,0,0,0]

External stuff could be causing the differences.  In my testing, I only have
the mmc_spi driver running since I was trying to capture it on the logic
analyzer.  Ethernet, etc. are all shutdown.

>> I have modifed my board so that I now have an external GPIO for the chip
>> select.
> Yes, we'll have to do that too.

>>> I'll run a few more tests, e.g. dropping the clock rate
>>
>> With a slow enough clock you can probably get to a point where SFRMOUT
>>  will stay deasserted during the entire 512 byte transfer
>
> I've tried it down to 400kHz and transfers still underrun (!)
>
> So it does seem that SFRMOUT cannot be used as a chip select unless we
> revert to the old busy-wait-for-whole-transfer code, which causes 100%
> CPU usage during transfers.
> and 1ms-long pauses (for 512 words at 3.7MHz).
>
> This suggests that we can only handle SFRMOUT used as chip select
> correctly by reinstating polling mode, adding the continuous transfer
> code and allowing the board definition code to specify that polling
> mode be used for such devices.
> (much as I hate polling mode :)

I don't think we should worry about polling mode for now.  With the
external GPIO chip select we don't have to worry about what the SFRMOUT
signal is doing.

>>  But it would
>  still de-assert during the switch to the next transfer in the message.
>
> Am I right in thinking that the GPIO chip select currently remains
> asserted as it should during a multi-transfer message?

Yes.  It gets asserted at the start and de-asserted at the end of
ep93xx_spi_process_message.

Actually, I think your supposed to check the cs_change flag at the end
of the message to see if the protocol is hinting to leave the chip
select asserted for the next message.  Of course this also means you need
to verify that the next message is actually for the same device.

Regards,
Hartley

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

* [PATCH v4 1/2] spi: implemented driver for Cirrus EP93xx SPI controller
  2010-04-21  1:10                     ` Martin Guy
  (?)
  (?)
@ 2010-04-29 18:30                     ` Mika Westerberg
  -1 siblings, 0 replies; 89+ messages in thread
From: Mika Westerberg @ 2010-04-29 18:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Martin,

On Wed, Apr 21, 2010 at 02:10:08AM +0100, Martin Guy wrote:
> 
> and the SDHC cards I have don't work at all, spewing tons of:
> mmcblk0: error -38 sending status comand
> mmcblk0: error -38 sending read/write command, response 0x4, card status 0xff04
> end_request: I/O error, dev mmcblk0, sector 7744509

I bought today a new 4GB SDHC card and with that I get similar
errors that you are getting. I hacked around quick fix which seems
to work in my case. I'm wondering whether you could check if it
helps with your SDHC card as well?

This problem is easy to reproduce, just read last sector of the
card (I wrote simple C program but running fdisk -l does the same).

Patch is below.

Thanks,
MW

>From d98fcab5f26e3ee8185232b51baeaae66b1ac0f3 Mon Sep 17 00:00:00 2001
From: Mika Westerberg <mika.westerberg@iki.fi>
Date: Thu, 29 Apr 2010 21:14:32 +0300
Subject: [PATCH] mmc_block: use single block reads for last block on SPI

Some SD-cards fail when doing multiblock read for last block with SPI host. Real
reason is not known but as workaround we can perform this last read using
multiple single block reads.

Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi>
---
 drivers/mmc/card/block.c |   19 +++++++++++++++++++
 1 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index cb9fbc8..acf3a88 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -277,6 +277,25 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 		if (brq.data.blocks > card->host->max_blk_count)
 			brq.data.blocks = card->host->max_blk_count;
 
+		if (mmc_host_is_spi(card->host)) {
+			/*
+			 * Some SD-cards fail when we are reading last block
+			 * with multiblock read. In these cases we automatically
+			 * use single block reads. This only happens on SPI
+			 * hosts.
+			 */
+			if (rq_data_dir(req) == READ && brq.data.blocks > 1) {
+				sector_t s = blk_rq_pos(req) + brq.data.blocks;
+
+				if (s >= get_capacity(md->disk)) {
+					disable_multi = 1;
+					printk(KERN_DEBUG "%s: using single block "
+					       "read for this request\n",
+					       req->rq_disk->disk_name);
+				}
+			}
+		}
+
 		/*
 		 * After a read error, we redo the request one sector at a time
 		 * in order to accurately determine which sectors can be read
-- 
1.5.6.5

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

end of thread, other threads:[~2010-04-29 18:30 UTC | newest]

Thread overview: 89+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-20 15:11 [PATCH v4 0/2] spi: driver for Cirrus EP93xx SPI controller Mika Westerberg
2010-04-20 15:11 ` Mika Westerberg
     [not found] ` <cover.1271774845.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
2010-04-20 15:11   ` [PATCH v4 1/2] spi: implemented " Mika Westerberg
2010-04-20 15:11     ` Mika Westerberg
     [not found]     ` <e96939d18bcbfb7a28ba4a925d7788884566db8c.1271774845.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
2010-04-20 17:24       ` H Hartley Sweeten
2010-04-20 17:24         ` H Hartley Sweeten
     [not found]         ` <0D753D10438DA54287A00B0270842697636D7F4E7F-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-21  7:16           ` Mika Westerberg
2010-04-21  7:16             ` Mika Westerberg
     [not found]             ` <20100421071629.GL19534-WfG2TfFPcQ9S6P4I59wummXnswh1EIUO@public.gmane.org>
2010-04-21 16:47               ` H Hartley Sweeten
2010-04-21 16:47                 ` H Hartley Sweeten
     [not found]                 ` <0D753D10438DA54287A00B0270842697636D8C84DA-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-21 16:54                   ` Mika Westerberg
2010-04-21 16:54                     ` Mika Westerberg
     [not found]                     ` <20100421165420.GP19534-WfG2TfFPcQ9S6P4I59wummXnswh1EIUO@public.gmane.org>
2010-04-22  2:47                       ` H Hartley Sweeten
2010-04-22  2:47                         ` H Hartley Sweeten
     [not found]                         ` <0D753D10438DA54287A00B0270842697636D8C8CDD-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-22  5:53                           ` Mika Westerberg
2010-04-22  5:53                             ` Mika Westerberg
2010-04-22 14:11                           ` Martin Guy
2010-04-22 14:11                             ` Martin Guy
2010-04-22 14:28                           ` Martin Guy
2010-04-22 14:28                             ` Martin Guy
     [not found]                             ` <x2g56d259a01004220728i7f07d492t4c4f63e0ef2e38d9-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-04-22 17:39                               ` H Hartley Sweeten
2010-04-22 17:39                                 ` H Hartley Sweeten
     [not found]                                 ` <0D753D10438DA54287A00B0270842697636D940C95-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-22 20:19                                   ` Martin Guy
2010-04-22 20:19                                     ` Martin Guy
2010-04-20 22:16       ` H Hartley Sweeten
2010-04-20 22:16         ` H Hartley Sweeten
     [not found]         ` <0D753D10438DA54287A00B0270842697636D85BCCC-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-20 23:54           ` Martin Guy
2010-04-20 23:54             ` Martin Guy
     [not found]             ` <z2h56d259a01004201654y93f6c533j11b5accd7e2f46e7-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-04-21  0:11               ` H Hartley Sweeten
2010-04-21  0:11                 ` H Hartley Sweeten
     [not found]                 ` <0D753D10438DA54287A00B0270842697636D85BDD8-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-21  0:43                   ` H Hartley Sweeten
2010-04-21  0:43                     ` [spi-devel-general] " H Hartley Sweeten
2010-04-21  1:10                   ` Martin Guy
2010-04-21  1:10                     ` Martin Guy
     [not found]                     ` <n2u56d259a01004201810j22c17bcfn9fee59e9c65c4d7f-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-04-21  1:52                       ` H Hartley Sweeten
2010-04-21  1:52                         ` H Hartley Sweeten
     [not found]                         ` <0D753D10438DA54287A00B0270842697636D85BE26-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-21  7:00                           ` Mika Westerberg
2010-04-21  7:00                             ` Mika Westerberg
2010-04-21 10:46                           ` Mika Westerberg
2010-04-21 10:46                             ` Mika Westerberg
     [not found]                             ` <20100421104651.GO19534-WfG2TfFPcQ9S6P4I59wummXnswh1EIUO@public.gmane.org>
2010-04-21 18:00                               ` H Hartley Sweeten
2010-04-21 18:00                                 ` H Hartley Sweeten
     [not found]                                 ` <0D753D10438DA54287A00B0270842697636D8C8672-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-22  5:45                                   ` Mika Westerberg
2010-04-22  5:45                                     ` Mika Westerberg
     [not found]                                     ` <20100422054519.GA26418-WfG2TfFPcQ9S6P4I59wummXnswh1EIUO@public.gmane.org>
2010-04-22 21:29                                       ` Ryan Mallon
2010-04-22 21:29                                         ` Ryan Mallon
2010-04-22 17:55                                   ` Mika Westerberg
2010-04-22 17:55                                     ` Mika Westerberg
2010-04-22 20:43                                     ` H Hartley Sweeten
2010-04-22 20:43                                       ` H Hartley Sweeten
     [not found]                                       ` <0D753D10438DA54287A00B0270842697636D9410F0-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-23  5:20                                         ` Mika Westerberg
2010-04-23  5:20                                           ` Mika Westerberg
     [not found]                                           ` <20100423052003.GF26418-WfG2TfFPcQ9S6P4I59wummXnswh1EIUO@public.gmane.org>
2010-04-23 17:24                                             ` H Hartley Sweeten
2010-04-23 17:24                                               ` H Hartley Sweeten
     [not found]                                               ` <0D753D10438DA54287A00B0270842697636D9419BC-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-23 23:01                                                 ` H Hartley Sweeten
2010-04-23 23:01                                                   ` [spi-devel-general] " H Hartley Sweeten
     [not found]                                                   ` <0D753D10438DA54287A00B0270842697636D9B794A-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-25  9:29                                                     ` Martin Guy
2010-04-25  9:29                                                       ` [spi-devel-general] " Martin Guy
     [not found]                                                       ` <y2x56d259a01004250229he9cb2ee3pf69669c9226f80fb-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-04-25  9:38                                                         ` Martin Guy
2010-04-25  9:38                                                           ` [spi-devel-general] " Martin Guy
     [not found]                                                           ` <m2l56d259a01004250238s99d6c869s1ee084b36f9736a0-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-04-25 20:25                                                             ` H Hartley Sweeten
2010-04-25 20:25                                                               ` [spi-devel-general] " H Hartley Sweeten
     [not found]                                                               ` <0D753D10438DA54287A00B0270842697636D9B7E66-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-26 10:02                                                                 ` Mika Westerberg
2010-04-26 10:02                                                                   ` [spi-devel-general] " Mika Westerberg
     [not found]                                                                   ` <20100426100258.GG26418-WfG2TfFPcQ9S6P4I59wummXnswh1EIUO@public.gmane.org>
2010-04-26 16:54                                                                     ` H Hartley Sweeten
2010-04-26 16:54                                                                       ` [spi-devel-general] " H Hartley Sweeten
2010-04-26 10:09                                                                 ` Mika Westerberg
2010-04-26 10:09                                                                   ` [spi-devel-general] " Mika Westerberg
2010-04-26 14:35                                                                 ` Martin Guy
2010-04-26 14:35                                                                   ` [spi-devel-general] " Martin Guy
     [not found]                                                                   ` <k2l56d259a01004260735nb44e9dddy5b08668787070ac7-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-04-26 17:05                                                                     ` H Hartley Sweeten
2010-04-26 17:05                                                                       ` [spi-devel-general] " H Hartley Sweeten
2010-04-29 18:30                     ` Mika Westerberg
2010-04-21  6:37         ` Mika Westerberg
2010-04-21  6:37           ` Mika Westerberg
     [not found]           ` <20100421063712.GJ19534-WfG2TfFPcQ9S6P4I59wummXnswh1EIUO@public.gmane.org>
2010-04-21 17:08             ` H Hartley Sweeten
2010-04-21 17:08               ` H Hartley Sweeten
2010-04-24 18:14       ` Martin Guy
2010-04-24 18:14         ` Martin Guy
     [not found]         ` <p2h56d259a01004241114qb1b1815em9657e5a857a9d4ee-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-04-25 19:55           ` H Hartley Sweeten
2010-04-25 19:55             ` H Hartley Sweeten
     [not found]             ` <0D753D10438DA54287A00B0270842697636D9B7E4F-gaq956PjLg32KbjnnMDalRurcAul1UnsRrxOEX5GOmysTnJN9+BGXg@public.gmane.org>
2010-04-26 10:34               ` Mika Westerberg
2010-04-26 10:34                 ` Mika Westerberg
2010-04-26 12:58               ` Martin Guy
2010-04-26 12:58                 ` Martin Guy
2010-04-20 15:11   ` [PATCH v4 2/2] ep93xx: SPI driver platform support code Mika Westerberg
2010-04-20 15:11     ` Mika Westerberg
     [not found]     ` <509a89ad62001de9de23129b4c34148aef28ef19.1271774845.git.mika.westerberg-X3B1VOXEql0@public.gmane.org>
2010-04-20 16:35       ` H Hartley Sweeten
2010-04-20 16:35         ` H Hartley Sweeten

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.