All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/2] SPI: Enable SPI_PREAMBLE Mode
@ 2013-03-22  6:29 Rajeshwari Shinde
  2013-03-22  6:29 ` [U-Boot] [PATCH 1/2] SPI: Add support for preamble bytes Rajeshwari Shinde
  2013-03-22  6:29 ` [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode Rajeshwari Shinde
  0 siblings, 2 replies; 15+ messages in thread
From: Rajeshwari Shinde @ 2013-03-22  6:29 UTC (permalink / raw)
  To: u-boot

This patch set enables PREAMBLE Mode for EXYNOS SPI.
 
Rajeshwari Shinde (2):
  SPI: Add support for preamble bytes
  EXYNOS: SPI: Support SPI_PREAMBLE mode

 drivers/spi/exynos_spi.c |   62 ++++++++++++++++++++++++++++++++++++++++------
 include/spi.h            |    5 +++
 2 files changed, 59 insertions(+), 8 deletions(-)

-- 
1.7.4.4

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

* [U-Boot] [PATCH 1/2] SPI: Add support for preamble bytes
  2013-03-22  6:29 [U-Boot] [PATCH 0/2] SPI: Enable SPI_PREAMBLE Mode Rajeshwari Shinde
@ 2013-03-22  6:29 ` Rajeshwari Shinde
  2013-05-11 14:42   ` Simon Glass
  2013-03-22  6:29 ` [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode Rajeshwari Shinde
  1 sibling, 1 reply; 15+ messages in thread
From: Rajeshwari Shinde @ 2013-03-22  6:29 UTC (permalink / raw)
  To: u-boot

A SPI slave may take time to react to a request. For SPI flash devices
this time is defined as one bit time, or a whole byte for 'fast read'
mode.

If the SPI slave is another CPU, then the time it takes to react may
vary. It is convenient to allow the slave device to tag the start of
the actual reply so that the host can determine when this 'preamble'
finishes and the actual message starts.

Add a preamble flag to the available SPI flags. If supported by the
driver then it will ignore any received bytes before the preamble
on each transaction. This ensures that reliable communication with
the slave is possible.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
---
 include/spi.h |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/spi.h b/include/spi.h
index 60e85db..5351c59 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -37,11 +37,16 @@
 #define	SPI_LSB_FIRST	0x08			/* per-word bits-on-wire */
 #define	SPI_3WIRE	0x10			/* SI/SO signals shared */
 #define	SPI_LOOP	0x20			/* loopback mode */
+#define	SPI_SLAVE	0x40			/* slave mode */
+#define	SPI_PREAMBLE	0x80			/* Skip preamble bytes */
 
 /* SPI transfer flags */
 #define SPI_XFER_BEGIN	0x01			/* Assert CS before transfer */
 #define SPI_XFER_END	0x02			/* Deassert CS after transfer */
 
+/* Header byte that marks the start of the message */
+#define SPI_PREAMBLE_END_BYTE	0xec
+
 /*-----------------------------------------------------------------------
  * Representation of a SPI slave, i.e. what we're communicating with.
  *
-- 
1.7.4.4

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

* [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode
  2013-03-22  6:29 [U-Boot] [PATCH 0/2] SPI: Enable SPI_PREAMBLE Mode Rajeshwari Shinde
  2013-03-22  6:29 ` [U-Boot] [PATCH 1/2] SPI: Add support for preamble bytes Rajeshwari Shinde
@ 2013-03-22  6:29 ` Rajeshwari Shinde
  2013-05-03  1:28   ` Vadim Bendebury
  2013-05-11 15:04   ` [U-Boot] [PATCH v2] " Simon Glass
  1 sibling, 2 replies; 15+ messages in thread
From: Rajeshwari Shinde @ 2013-03-22  6:29 UTC (permalink / raw)
  To: u-boot

Support interfaces with a preamble before each received message.

We handle this when the client has requested a SPI_XFER_END, meaning
that we must close of the transaction. In this case we read until we
see the preamble (or a timeout occurs), skipping all data before and
including the preamble. The client will receive only data bytes after
the preamble.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
---
 drivers/spi/exynos_spi.c |   62 ++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index be60ada..09e88d5 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -51,6 +51,7 @@ struct exynos_spi_slave {
 	unsigned int mode;
 	enum periph_id periph_id;	/* Peripheral ID for this device */
 	unsigned int fifo_size;
+	int skip_preamble;
 };
 
 static struct spi_bus *spi_get_bus(unsigned dev_index)
@@ -107,6 +108,8 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
 	else
 		spi_slave->fifo_size = 256;
 
+	spi_slave->skip_preamble = 0;
+
 	spi_slave->freq = bus->frequency;
 	if (max_hz)
 		spi_slave->freq = min(max_hz, spi_slave->freq);
@@ -219,17 +222,23 @@ static void spi_request_bytes(struct exynos_spi *regs, int count)
 	writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
 }
 
-static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
-			void **dinp, void const **doutp)
+static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
+			void **dinp, void const **doutp, unsigned long flags)
 {
 	struct exynos_spi *regs = spi_slave->regs;
 	uchar *rxp = *dinp;
 	const uchar *txp = *doutp;
 	int rx_lvl, tx_lvl;
 	uint out_bytes, in_bytes;
+	int toread, preamable_count = 0;
+	unsigned start = get_timer(0);
+	int stopping;
 
 	out_bytes = in_bytes = todo;
 
+	stopping = spi_slave->skip_preamble && (flags & SPI_XFER_END) &&
+					!(spi_slave->mode & SPI_SLAVE);
+
 	/*
 	 * If there's something to send, do a software reset and set a
 	 * transaction size.
@@ -240,6 +249,7 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 	 * Bytes are transmitted/received in pairs. Wait to receive all the
 	 * data because then transmission will be done as well.
 	 */
+	toread = in_bytes;
 	while (in_bytes) {
 		int temp;
 
@@ -252,13 +262,41 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 		}
 		if (rx_lvl > 0 && in_bytes) {
 			temp = readl(&regs->rx_data);
-			if (rxp)
+			if (!rxp && !stopping) {
+				in_bytes--;
+			} else if (spi_slave->skip_preamble) {
+				if (temp == SPI_PREAMBLE_END_BYTE) {
+					spi_slave->skip_preamble = 0;
+					stopping = 0;
+				}
+			} else {
 				*rxp++ = temp;
-			in_bytes--;
+				in_bytes--;
+			}
+			toread--;
+		}
+		/*
+		 * We have run out of input data, but haven't read enough
+		 * bytes after the preamble yet. Read some more, and make
+		 * sure that we transmit dummy bytes too, to keep things
+		 * going.
+		 */
+		else if (in_bytes && !toread) {
+			assert(!out_bytes);
+			toread = out_bytes = in_bytes;
+			txp = NULL;
+			spi_request_bytes(regs, toread);
+		}
+		if (spi_slave->skip_preamble && get_timer(start) > 100) {
+			printf("SPI timeout: in_bytes=%d, out_bytes=%d, ",
+			       in_bytes, out_bytes);
+			printf("count = %d\n", preamable_count);
+			return -1;
 		}
 	}
 	*dinp = rxp;
 	*doutp = txp;
+	return 0;
 }
 
 /**
@@ -278,6 +316,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
 	int upto, todo;
 	int bytelen;
+	int ret = 0;
 
 	/* spi core configured to do 8 bit transfers */
 	if (bitlen % 8) {
@@ -291,16 +330,22 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 
 	/* Exynos SPI limits each transfer to 65535 bytes */
 	bytelen =  bitlen / 8;
-	for (upto = 0; upto < bytelen; upto += todo) {
+	for (upto = 0; !ret && upto < bytelen; upto += todo) {
 		todo = min(bytelen - upto, (1 << 16) - 1);
-		spi_rx_tx(spi_slave, todo, &din, &dout);
+		ret = spi_rx_tx(spi_slave, todo, &din, &dout, flags);
 	}
 
 	/* Stop the transaction, if necessary. */
-	if ((flags & SPI_XFER_END))
+	if ((flags & SPI_XFER_END) && !(spi_slave->mode & SPI_SLAVE)) {
 		spi_cs_deactivate(slave);
+		if (spi_slave->skip_preamble) {
+			assert(!spi_slave->skip_preamble);
+			debug("Failed to complete premable transaction\n");
+			ret = -1;
+		}
+	}
 
-	return 0;
+	return ret;
 }
 
 /**
@@ -327,6 +372,7 @@ void spi_cs_activate(struct spi_slave *slave)
 
 	clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
 	debug("Activate CS, bus %d\n", spi_slave->slave.bus);
+	spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
 }
 
 /**
-- 
1.7.4.4

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

* [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode
  2013-03-22  6:29 ` [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode Rajeshwari Shinde
@ 2013-05-03  1:28   ` Vadim Bendebury
  2013-05-06 12:06     ` Simon Glass
  2013-05-11 14:41     ` Simon Glass
  2013-05-11 15:04   ` [U-Boot] [PATCH v2] " Simon Glass
  1 sibling, 2 replies; 15+ messages in thread
From: Vadim Bendebury @ 2013-05-03  1:28 UTC (permalink / raw)
  To: u-boot

On Thu, Mar 21, 2013 at 11:29 PM, Rajeshwari Shinde
<rajeshwari.s@samsung.com> wrote:
> Support interfaces with a preamble before each received message.
>
> We handle this when the client has requested a SPI_XFER_END, meaning
> that we must close of the transaction. In this case we read until we
> see the preamble (or a timeout occurs), skipping all data before and
> including the preamble. The client will receive only data bytes after
> the preamble.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
> ---
>  drivers/spi/exynos_spi.c |   62 ++++++++++++++++++++++++++++++++++++++++------
>  1 files changed, 54 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
> index be60ada..09e88d5 100644
> --- a/drivers/spi/exynos_spi.c
> +++ b/drivers/spi/exynos_spi.c
> @@ -51,6 +51,7 @@ struct exynos_spi_slave {
>         unsigned int mode;
>         enum periph_id periph_id;       /* Peripheral ID for this device */
>         unsigned int fifo_size;
> +       int skip_preamble;
>  };
>
>  static struct spi_bus *spi_get_bus(unsigned dev_index)
> @@ -107,6 +108,8 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
>         else
>                 spi_slave->fifo_size = 256;
>
> +       spi_slave->skip_preamble = 0;
> +
>         spi_slave->freq = bus->frequency;
>         if (max_hz)
>                 spi_slave->freq = min(max_hz, spi_slave->freq);
> @@ -219,17 +222,23 @@ static void spi_request_bytes(struct exynos_spi *regs, int count)
>         writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
>  }
>
> -static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
> -                       void **dinp, void const **doutp)
> +static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
> +                       void **dinp, void const **doutp, unsigned long flags)
>  {
>         struct exynos_spi *regs = spi_slave->regs;
>         uchar *rxp = *dinp;
>         const uchar *txp = *doutp;
>         int rx_lvl, tx_lvl;
>         uint out_bytes, in_bytes;
> +       int toread, preamable_count = 0;

preamable_count: the name is misspelled, and the variable is never modified.

> +       unsigned start = get_timer(0);
> +       int stopping;
>
>         out_bytes = in_bytes = todo;
>
> +       stopping = spi_slave->skip_preamble && (flags & SPI_XFER_END) &&
> +                                       !(spi_slave->mode & SPI_SLAVE);
> +
>         /*
>          * If there's something to send, do a software reset and set a
>          * transaction size.
> @@ -240,6 +249,7 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
>          * Bytes are transmitted/received in pairs. Wait to receive all the
>          * data because then transmission will be done as well.
>          */
> +       toread = in_bytes;
>         while (in_bytes) {
>                 int temp;
>
> @@ -252,13 +262,41 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
>                 }
>                 if (rx_lvl > 0 && in_bytes) {
>                         temp = readl(&regs->rx_data);
> -                       if (rxp)
> +                       if (!rxp && !stopping) {
> +                               in_bytes--;
> +                       } else if (spi_slave->skip_preamble) {
> +                               if (temp == SPI_PREAMBLE_END_BYTE) {
> +                                       spi_slave->skip_preamble = 0;
> +                                       stopping = 0;
> +                               }
> +                       } else {
>                                 *rxp++ = temp;
> -                       in_bytes--;
> +                               in_bytes--;
> +                       }
> +                       toread--;
> +               }
> +               /*
> +                * We have run out of input data, but haven't read enough
> +                * bytes after the preamble yet. Read some more, and make
> +                * sure that we transmit dummy bytes too, to keep things
> +                * going.
> +                */
> +               else if (in_bytes && !toread) {
> +                       assert(!out_bytes);
> +                       toread = out_bytes = in_bytes;
> +                       txp = NULL;
> +                       spi_request_bytes(regs, toread);
> +               }
> +               if (spi_slave->skip_preamble && get_timer(start) > 100) {
> +                       printf("SPI timeout: in_bytes=%d, out_bytes=%d, ",
> +                              in_bytes, out_bytes);
> +                       printf("count = %d\n", preamable_count);
> +                       return -1;
>                 }
>         }
>         *dinp = rxp;
>         *doutp = txp;
> +       return 0;
>  }
>
>  /**
> @@ -278,6 +316,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
>         struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
>         int upto, todo;
>         int bytelen;
> +       int ret = 0;
>
>         /* spi core configured to do 8 bit transfers */
>         if (bitlen % 8) {
> @@ -291,16 +330,22 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
>
>         /* Exynos SPI limits each transfer to 65535 bytes */
>         bytelen =  bitlen / 8;
> -       for (upto = 0; upto < bytelen; upto += todo) {
> +       for (upto = 0; !ret && upto < bytelen; upto += todo) {
>                 todo = min(bytelen - upto, (1 << 16) - 1);
> -               spi_rx_tx(spi_slave, todo, &din, &dout);
> +               ret = spi_rx_tx(spi_slave, todo, &din, &dout, flags);
>         }
>
>         /* Stop the transaction, if necessary. */
> -       if ((flags & SPI_XFER_END))
> +       if ((flags & SPI_XFER_END) && !(spi_slave->mode & SPI_SLAVE)) {
>                 spi_cs_deactivate(slave);
> +               if (spi_slave->skip_preamble) {
> +                       assert(!spi_slave->skip_preamble);
> +                       debug("Failed to complete premable transaction\n");
> +                       ret = -1;
> +               }
> +       }
>
> -       return 0;
> +       return ret;
>  }
>
>  /**
> @@ -327,6 +372,7 @@ void spi_cs_activate(struct spi_slave *slave)
>
>         clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
>         debug("Activate CS, bus %d\n", spi_slave->slave.bus);
> +       spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;

who sets this bit in the 'mode' field?

>  }
>
>  /**
> --
> 1.7.4.4
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot

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

* [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode
  2013-05-03  1:28   ` Vadim Bendebury
@ 2013-05-06 12:06     ` Simon Glass
  2013-05-11 14:41     ` Simon Glass
  1 sibling, 0 replies; 15+ messages in thread
From: Simon Glass @ 2013-05-06 12:06 UTC (permalink / raw)
  To: u-boot

Hi Vadim,

On Thu, May 2, 2013 at 7:28 PM, Vadim Bendebury <vbendeb@chromium.org> wrote:
> On Thu, Mar 21, 2013 at 11:29 PM, Rajeshwari Shinde
> <rajeshwari.s@samsung.com> wrote:
>> Support interfaces with a preamble before each received message.
>>
>> We handle this when the client has requested a SPI_XFER_END, meaning
>> that we must close of the transaction. In this case we read until we
>> see the preamble (or a timeout occurs), skipping all data before and
>> including the preamble. The client will receive only data bytes after
>> the preamble.
>>
>> Signed-off-by: Simon Glass <sjg@chromium.org>
>> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
>> ---
>>  drivers/spi/exynos_spi.c |   62 ++++++++++++++++++++++++++++++++++++++++------
>>  1 files changed, 54 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
>> index be60ada..09e88d5 100644
>> --- a/drivers/spi/exynos_spi.c
>> +++ b/drivers/spi/exynos_spi.c
>> @@ -51,6 +51,7 @@ struct exynos_spi_slave {
>>         unsigned int mode;
>>         enum periph_id periph_id;       /* Peripheral ID for this device */
>>         unsigned int fifo_size;
>> +       int skip_preamble;
>>  };
>>
>>  static struct spi_bus *spi_get_bus(unsigned dev_index)
>> @@ -107,6 +108,8 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
>>         else
>>                 spi_slave->fifo_size = 256;
>>
>> +       spi_slave->skip_preamble = 0;
>> +
>>         spi_slave->freq = bus->frequency;
>>         if (max_hz)
>>                 spi_slave->freq = min(max_hz, spi_slave->freq);
>> @@ -219,17 +222,23 @@ static void spi_request_bytes(struct exynos_spi *regs, int count)
>>         writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
>>  }
>>
>> -static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
>> -                       void **dinp, void const **doutp)
>> +static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
>> +                       void **dinp, void const **doutp, unsigned long flags)
>>  {
>>         struct exynos_spi *regs = spi_slave->regs;
>>         uchar *rxp = *dinp;
>>         const uchar *txp = *doutp;
>>         int rx_lvl, tx_lvl;
>>         uint out_bytes, in_bytes;
>> +       int toread, preamable_count = 0;
>
> preamable_count: the name is misspelled, and the variable is never modified.
>
>> +       unsigned start = get_timer(0);
>> +       int stopping;
>>
>>         out_bytes = in_bytes = todo;
>>
>> +       stopping = spi_slave->skip_preamble && (flags & SPI_XFER_END) &&
>> +                                       !(spi_slave->mode & SPI_SLAVE);
>> +
>>         /*
>>          * If there's something to send, do a software reset and set a
>>          * transaction size.
>> @@ -240,6 +249,7 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
>>          * Bytes are transmitted/received in pairs. Wait to receive all the
>>          * data because then transmission will be done as well.
>>          */
>> +       toread = in_bytes;
>>         while (in_bytes) {
>>                 int temp;
>>
>> @@ -252,13 +262,41 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
>>                 }
>>                 if (rx_lvl > 0 && in_bytes) {
>>                         temp = readl(&regs->rx_data);
>> -                       if (rxp)
>> +                       if (!rxp && !stopping) {
>> +                               in_bytes--;
>> +                       } else if (spi_slave->skip_preamble) {
>> +                               if (temp == SPI_PREAMBLE_END_BYTE) {
>> +                                       spi_slave->skip_preamble = 0;
>> +                                       stopping = 0;
>> +                               }
>> +                       } else {
>>                                 *rxp++ = temp;
>> -                       in_bytes--;
>> +                               in_bytes--;
>> +                       }
>> +                       toread--;
>> +               }
>> +               /*
>> +                * We have run out of input data, but haven't read enough
>> +                * bytes after the preamble yet. Read some more, and make
>> +                * sure that we transmit dummy bytes too, to keep things
>> +                * going.
>> +                */
>> +               else if (in_bytes && !toread) {
>> +                       assert(!out_bytes);
>> +                       toread = out_bytes = in_bytes;
>> +                       txp = NULL;
>> +                       spi_request_bytes(regs, toread);
>> +               }
>> +               if (spi_slave->skip_preamble && get_timer(start) > 100) {
>> +                       printf("SPI timeout: in_bytes=%d, out_bytes=%d, ",
>> +                              in_bytes, out_bytes);
>> +                       printf("count = %d\n", preamable_count);
>> +                       return -1;
>>                 }
>>         }
>>         *dinp = rxp;
>>         *doutp = txp;
>> +       return 0;
>>  }
>>
>>  /**
>> @@ -278,6 +316,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
>>         struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
>>         int upto, todo;
>>         int bytelen;
>> +       int ret = 0;
>>
>>         /* spi core configured to do 8 bit transfers */
>>         if (bitlen % 8) {
>> @@ -291,16 +330,22 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
>>
>>         /* Exynos SPI limits each transfer to 65535 bytes */
>>         bytelen =  bitlen / 8;
>> -       for (upto = 0; upto < bytelen; upto += todo) {
>> +       for (upto = 0; !ret && upto < bytelen; upto += todo) {
>>                 todo = min(bytelen - upto, (1 << 16) - 1);
>> -               spi_rx_tx(spi_slave, todo, &din, &dout);
>> +               ret = spi_rx_tx(spi_slave, todo, &din, &dout, flags);
>>         }
>>
>>         /* Stop the transaction, if necessary. */
>> -       if ((flags & SPI_XFER_END))
>> +       if ((flags & SPI_XFER_END) && !(spi_slave->mode & SPI_SLAVE)) {
>>                 spi_cs_deactivate(slave);
>> +               if (spi_slave->skip_preamble) {
>> +                       assert(!spi_slave->skip_preamble);
>> +                       debug("Failed to complete premable transaction\n");
>> +                       ret = -1;
>> +               }
>> +       }
>>
>> -       return 0;
>> +       return ret;
>>  }
>>
>>  /**
>> @@ -327,6 +372,7 @@ void spi_cs_activate(struct spi_slave *slave)
>>
>>         clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
>>         debug("Activate CS, bus %d\n", spi_slave->slave.bus);
>> +       spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
>
> who sets this bit in the 'mode' field?

This is set by whoever creates the slave - in the case of snow it is cros_ec.

Regards,
Simon

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

* [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode
  2013-05-03  1:28   ` Vadim Bendebury
  2013-05-06 12:06     ` Simon Glass
@ 2013-05-11 14:41     ` Simon Glass
  1 sibling, 0 replies; 15+ messages in thread
From: Simon Glass @ 2013-05-11 14:41 UTC (permalink / raw)
  To: u-boot

Hi,

On Thu, May 2, 2013 at 7:28 PM, Vadim Bendebury <vbendeb@chromium.org> wrote:
> On Thu, Mar 21, 2013 at 11:29 PM, Rajeshwari Shinde
> <rajeshwari.s@samsung.com> wrote:
>> Support interfaces with a preamble before each received message.
>>
>> We handle this when the client has requested a SPI_XFER_END, meaning
>> that we must close of the transaction. In this case we read until we
>> see the preamble (or a timeout occurs), skipping all data before and
>> including the preamble. The client will receive only data bytes after
>> the preamble.
>>
>> Signed-off-by: Simon Glass <sjg@chromium.org>
>> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
>> ---
>>  drivers/spi/exynos_spi.c |   62 ++++++++++++++++++++++++++++++++++++++++------
>>  1 files changed, 54 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
>> index be60ada..09e88d5 100644
>> --- a/drivers/spi/exynos_spi.c
>> +++ b/drivers/spi/exynos_spi.c
>> @@ -51,6 +51,7 @@ struct exynos_spi_slave {
>>         unsigned int mode;
>>         enum periph_id periph_id;       /* Peripheral ID for this device */
>>         unsigned int fifo_size;
>> +       int skip_preamble;
>>  };
>>
>>  static struct spi_bus *spi_get_bus(unsigned dev_index)
>> @@ -107,6 +108,8 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
>>         else
>>                 spi_slave->fifo_size = 256;
>>
>> +       spi_slave->skip_preamble = 0;
>> +
>>         spi_slave->freq = bus->frequency;
>>         if (max_hz)
>>                 spi_slave->freq = min(max_hz, spi_slave->freq);
>> @@ -219,17 +222,23 @@ static void spi_request_bytes(struct exynos_spi *regs, int count)
>>         writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
>>  }
>>
>> -static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
>> -                       void **dinp, void const **doutp)
>> +static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
>> +                       void **dinp, void const **doutp, unsigned long flags)
>>  {
>>         struct exynos_spi *regs = spi_slave->regs;
>>         uchar *rxp = *dinp;
>>         const uchar *txp = *doutp;
>>         int rx_lvl, tx_lvl;
>>         uint out_bytes, in_bytes;
>> +       int toread, preamable_count = 0;
>
> preamable_count: the name is misspelled, and the variable is never modified.

Yes, it is supposed to count the number of bytes before the preamble,
in the event of an error, but it isn't really needed. I will resend
the patch with it removed.

Regards,
Simon

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

* [U-Boot] [PATCH 1/2] SPI: Add support for preamble bytes
  2013-03-22  6:29 ` [U-Boot] [PATCH 1/2] SPI: Add support for preamble bytes Rajeshwari Shinde
@ 2013-05-11 14:42   ` Simon Glass
  0 siblings, 0 replies; 15+ messages in thread
From: Simon Glass @ 2013-05-11 14:42 UTC (permalink / raw)
  To: u-boot

On Fri, Mar 22, 2013 at 12:29 AM, Rajeshwari Shinde
<rajeshwari.s@samsung.com> wrote:
> A SPI slave may take time to react to a request. For SPI flash devices
> this time is defined as one bit time, or a whole byte for 'fast read'
> mode.
>
> If the SPI slave is another CPU, then the time it takes to react may
> vary. It is convenient to allow the slave device to tag the start of
> the actual reply so that the host can determine when this 'preamble'
> finishes and the actual message starts.
>
> Add a preamble flag to the available SPI flags. If supported by the
> driver then it will ignore any received bytes before the preamble
> on each transaction. This ensures that reliable communication with
> the slave is possible.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>

Acked-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v2] EXYNOS: SPI: Support SPI_PREAMBLE mode
  2013-03-22  6:29 ` [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode Rajeshwari Shinde
  2013-05-03  1:28   ` Vadim Bendebury
@ 2013-05-11 15:04   ` Simon Glass
  2013-05-11 15:05     ` Simon Glass
  2013-05-21 12:30     ` Minkyu Kang
  1 sibling, 2 replies; 15+ messages in thread
From: Simon Glass @ 2013-05-11 15:04 UTC (permalink / raw)
  To: u-boot

From: Rajeshwari Shinde <rajeshwari.s@samsung.com>

Support interfaces with a preamble before each received message.

We handle this when the client has requested a SPI_XFER_END, meaning
that we must close of the transaction. In this case we read until we
see the preamble (or a timeout occurs), skipping all data before and
including the preamble. The client will receive only data bytes after
the preamble.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
---
Changes in v2:
- Remove preamable_count variable which is not really needed
- Fix checkpatch warning (multiple assignments)

 drivers/spi/exynos_spi.c | 62 +++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 54 insertions(+), 8 deletions(-)

diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index 607e1cd..b7b2ea5 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -51,6 +51,7 @@ struct exynos_spi_slave {
 	unsigned int mode;
 	enum periph_id periph_id;	/* Peripheral ID for this device */
 	unsigned int fifo_size;
+	int skip_preamble;
 };
 
 static struct spi_bus *spi_get_bus(unsigned dev_index)
@@ -105,6 +106,8 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
 	else
 		spi_slave->fifo_size = 256;
 
+	spi_slave->skip_preamble = 0;
+
 	spi_slave->freq = bus->frequency;
 	if (max_hz)
 		spi_slave->freq = min(max_hz, spi_slave->freq);
@@ -217,17 +220,23 @@ static void spi_request_bytes(struct exynos_spi *regs, int count)
 	writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
 }
 
-static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
-			void **dinp, void const **doutp)
+static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
+			void **dinp, void const **doutp, unsigned long flags)
 {
 	struct exynos_spi *regs = spi_slave->regs;
 	uchar *rxp = *dinp;
 	const uchar *txp = *doutp;
 	int rx_lvl, tx_lvl;
 	uint out_bytes, in_bytes;
+	int toread;
+	unsigned start = get_timer(0);
+	int stopping;
 
 	out_bytes = in_bytes = todo;
 
+	stopping = spi_slave->skip_preamble && (flags & SPI_XFER_END) &&
+					!(spi_slave->mode & SPI_SLAVE);
+
 	/*
 	 * If there's something to send, do a software reset and set a
 	 * transaction size.
@@ -238,6 +247,7 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 	 * Bytes are transmitted/received in pairs. Wait to receive all the
 	 * data because then transmission will be done as well.
 	 */
+	toread = in_bytes;
 	while (in_bytes) {
 		int temp;
 
@@ -250,13 +260,41 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 		}
 		if (rx_lvl > 0 && in_bytes) {
 			temp = readl(&regs->rx_data);
-			if (rxp)
+			if (!rxp && !stopping) {
+				in_bytes--;
+			} else if (spi_slave->skip_preamble) {
+				if (temp == SPI_PREAMBLE_END_BYTE) {
+					spi_slave->skip_preamble = 0;
+					stopping = 0;
+				}
+			} else {
 				*rxp++ = temp;
-			in_bytes--;
+				in_bytes--;
+			}
+			toread--;
+		}
+		/*
+		 * We have run out of input data, but haven't read enough
+		 * bytes after the preamble yet. Read some more, and make
+		 * sure that we transmit dummy bytes too, to keep things
+		 * going.
+		 */
+		else if (in_bytes && !toread) {
+			assert(!out_bytes);
+			out_bytes = in_bytes;
+			toread = in_bytes;
+			txp = NULL;
+			spi_request_bytes(regs, toread);
+		}
+		if (spi_slave->skip_preamble && get_timer(start) > 100) {
+			printf("SPI timeout: in_bytes=%d, out_bytes=%d, ",
+			       in_bytes, out_bytes);
+			return -1;
 		}
 	}
 	*dinp = rxp;
 	*doutp = txp;
+	return 0;
 }
 
 /**
@@ -276,6 +314,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
 	int upto, todo;
 	int bytelen;
+	int ret = 0;
 
 	/* spi core configured to do 8 bit transfers */
 	if (bitlen % 8) {
@@ -289,16 +328,22 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 
 	/* Exynos SPI limits each transfer to 65535 bytes */
 	bytelen =  bitlen / 8;
-	for (upto = 0; upto < bytelen; upto += todo) {
+	for (upto = 0; !ret && upto < bytelen; upto += todo) {
 		todo = min(bytelen - upto, (1 << 16) - 1);
-		spi_rx_tx(spi_slave, todo, &din, &dout);
+		ret = spi_rx_tx(spi_slave, todo, &din, &dout, flags);
 	}
 
 	/* Stop the transaction, if necessary. */
-	if ((flags & SPI_XFER_END))
+	if ((flags & SPI_XFER_END) && !(spi_slave->mode & SPI_SLAVE)) {
 		spi_cs_deactivate(slave);
+		if (spi_slave->skip_preamble) {
+			assert(!spi_slave->skip_preamble);
+			debug("Failed to complete premable transaction\n");
+			ret = -1;
+		}
+	}
 
-	return 0;
+	return ret;
 }
 
 /**
@@ -325,6 +370,7 @@ void spi_cs_activate(struct spi_slave *slave)
 
 	clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
 	debug("Activate CS, bus %d\n", spi_slave->slave.bus);
+	spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
 }
 
 /**
-- 
1.8.2.1

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

* [U-Boot] [PATCH v2] EXYNOS: SPI: Support SPI_PREAMBLE mode
  2013-05-11 15:04   ` [U-Boot] [PATCH v2] " Simon Glass
@ 2013-05-11 15:05     ` Simon Glass
  2013-05-21 12:30     ` Minkyu Kang
  1 sibling, 0 replies; 15+ messages in thread
From: Simon Glass @ 2013-05-11 15:05 UTC (permalink / raw)
  To: u-boot

On Sat, May 11, 2013 at 9:04 AM, Simon Glass <sjg@chromium.org> wrote:
> From: Rajeshwari Shinde <rajeshwari.s@samsung.com>
>
> Support interfaces with a preamble before each received message.
>
> We handle this when the client has requested a SPI_XFER_END, meaning
> that we must close of the transaction. In this case we read until we
> see the preamble (or a timeout occurs), skipping all data before and
> including the preamble. The client will receive only data bytes after
> the preamble.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
> ---
> Changes in v2:
> - Remove preamable_count variable which is not really needed
> - Fix checkpatch warning (multiple assignments)

This v2 patch fixes the nits reported.

Acked-by: Simon Glass <sjg@chromium.org>

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

* [U-Boot] [PATCH v2] EXYNOS: SPI: Support SPI_PREAMBLE mode
  2013-05-11 15:04   ` [U-Boot] [PATCH v2] " Simon Glass
  2013-05-11 15:05     ` Simon Glass
@ 2013-05-21 12:30     ` Minkyu Kang
  1 sibling, 0 replies; 15+ messages in thread
From: Minkyu Kang @ 2013-05-21 12:30 UTC (permalink / raw)
  To: u-boot

Dear Rajeshwari Shinde,

On 12/05/13 00:04, Simon Glass wrote:
> From: Rajeshwari Shinde <rajeshwari.s@samsung.com>
> 
> Support interfaces with a preamble before each received message.
> 
> We handle this when the client has requested a SPI_XFER_END, meaning
> that we must close of the transaction. In this case we read until we
> see the preamble (or a timeout occurs), skipping all data before and
> including the preamble. The client will receive only data bytes after
> the preamble.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
> ---
> Changes in v2:
> - Remove preamable_count variable which is not really needed
> - Fix checkpatch warning (multiple assignments)
> 
>  drivers/spi/exynos_spi.c | 62 +++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 54 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
> index 607e1cd..b7b2ea5 100644
> --- a/drivers/spi/exynos_spi.c
> +++ b/drivers/spi/exynos_spi.c
> @@ -51,6 +51,7 @@ struct exynos_spi_slave {
>  	unsigned int mode;
>  	enum periph_id periph_id;	/* Peripheral ID for this device */
>  	unsigned int fifo_size;
> +	int skip_preamble;
>  };
>  
>  static struct spi_bus *spi_get_bus(unsigned dev_index)
> @@ -105,6 +106,8 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
>  	else
>  		spi_slave->fifo_size = 256;
>  
> +	spi_slave->skip_preamble = 0;
> +
>  	spi_slave->freq = bus->frequency;
>  	if (max_hz)
>  		spi_slave->freq = min(max_hz, spi_slave->freq);
> @@ -217,17 +220,23 @@ static void spi_request_bytes(struct exynos_spi *regs, int count)
>  	writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
>  }
>  
> -static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
> -			void **dinp, void const **doutp)
> +static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
> +			void **dinp, void const **doutp, unsigned long flags)
>  {
>  	struct exynos_spi *regs = spi_slave->regs;
>  	uchar *rxp = *dinp;
>  	const uchar *txp = *doutp;
>  	int rx_lvl, tx_lvl;
>  	uint out_bytes, in_bytes;
> +	int toread;
> +	unsigned start = get_timer(0);
> +	int stopping;
>  
>  	out_bytes = in_bytes = todo;
>  
> +	stopping = spi_slave->skip_preamble && (flags & SPI_XFER_END) &&
> +					!(spi_slave->mode & SPI_SLAVE);
> +
>  	/*
>  	 * If there's something to send, do a software reset and set a
>  	 * transaction size.
> @@ -238,6 +247,7 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
>  	 * Bytes are transmitted/received in pairs. Wait to receive all the
>  	 * data because then transmission will be done as well.
>  	 */
> +	toread = in_bytes;

please add blank line here.

>  	while (in_bytes) {
>  		int temp;
>  
> @@ -250,13 +260,41 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
>  		}
>  		if (rx_lvl > 0 && in_bytes) {

I think, in_bytes is always true.
It's a redundant checking.

>  			temp = readl(&regs->rx_data);
> -			if (rxp)
> +			if (!rxp && !stopping) {
> +				in_bytes--;
> +			} else if (spi_slave->skip_preamble) {
> +				if (temp == SPI_PREAMBLE_END_BYTE) {
> +					spi_slave->skip_preamble = 0;
> +					stopping = 0;
> +				}
> +			} else {
>  				*rxp++ = temp;
> -			in_bytes--;
> +				in_bytes--;
> +			}
> +			toread--;
> +		}


I think, this if statement is not logical.
The checking condition is differ, so it looks confused.

How about this?

+                       temp = readl(&regs->rx_data);
+                       if (spi_slave->skip_preamble) {
+                               if (temp == SPI_PREAMBLE_END_BYTE) {
+                                       spi_slave->skip_preamble = 0;
+                                       stopping = 0;
+                               }
+                       } else {
+                               if (rxp || stopping)
+                                       *rxp++ = temp;
+                               in_bytes--;
+                       }
+
+                       toread--;


> +		/*
> +		 * We have run out of input data, but haven't read enough
> +		 * bytes after the preamble yet. Read some more, and make
> +		 * sure that we transmit dummy bytes too, to keep things
> +		 * going.
> +		 */

This comment is what for?
please move this comment into the brace.

> +		else if (in_bytes && !toread) {

in_bytes.. ditto.

And please fix brace.
} else if (

> +			assert(!out_bytes);
> +			out_bytes = in_bytes;
> +			toread = in_bytes;
> +			txp = NULL;
> +			spi_request_bytes(regs, toread);
> +		}
> +		if (spi_slave->skip_preamble && get_timer(start) > 100) {
> +			printf("SPI timeout: in_bytes=%d, out_bytes=%d, ",
> +			       in_bytes, out_bytes);
> +			return -1;
>  		}
>  	}
>  	*dinp = rxp;
>  	*doutp = txp;

please add blank line here.

> +	return 0;
>  }
>  
>  /**
> @@ -276,6 +314,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
>  	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
>  	int upto, todo;
>  	int bytelen;
> +	int ret = 0;
>  
>  	/* spi core configured to do 8 bit transfers */
>  	if (bitlen % 8) {
> @@ -289,16 +328,22 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
>  
>  	/* Exynos SPI limits each transfer to 65535 bytes */
>  	bytelen =  bitlen / 8;
> -	for (upto = 0; upto < bytelen; upto += todo) {
> +	for (upto = 0; !ret && upto < bytelen; upto += todo) {
>  		todo = min(bytelen - upto, (1 << 16) - 1);
> -		spi_rx_tx(spi_slave, todo, &din, &dout);
> +		ret = spi_rx_tx(spi_slave, todo, &din, &dout, flags);

It looks good.
But I think, it's better to checking the error explicitly.

if (!ret)
	break;

>  	}
>  
>  	/* Stop the transaction, if necessary. */
> -	if ((flags & SPI_XFER_END))
> +	if ((flags & SPI_XFER_END) && !(spi_slave->mode & SPI_SLAVE)) {
>  		spi_cs_deactivate(slave);
> +		if (spi_slave->skip_preamble) {
> +			assert(!spi_slave->skip_preamble);
> +			debug("Failed to complete premable transaction\n");
> +			ret = -1;
> +		}
> +	}
>  
> -	return 0;
> +	return ret;
>  }
>  
>  /**
> @@ -325,6 +370,7 @@ void spi_cs_activate(struct spi_slave *slave)
>  
>  	clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
>  	debug("Activate CS, bus %d\n", spi_slave->slave.bus);
> +	spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
>  }
>  
>  /**
> 

Thanks,
Minkyu Kang.

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

* [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode
  2013-05-06 16:01     ` Vadim Bendebury
@ 2013-05-11 21:38       ` Simon Glass
  0 siblings, 0 replies; 15+ messages in thread
From: Simon Glass @ 2013-05-11 21:38 UTC (permalink / raw)
  To: u-boot

Hi Vadim,

On Mon, May 6, 2013 at 10:01 AM, Vadim Bendebury <vbendeb@chromium.org> wrote:
> On Mon, May 6, 2013 at 7:37 AM, Simon Glass <sjg@chromium.org> wrote:
>>
>> HI Vadim,
>>
>> On Thu, May 2, 2013 at 11:12 PM, Vadim Bendebury <vbendeb@chromium.org> wrote:
>> > [the original patch removed, re-sending from a registered address]
>> >
>> > So, I spent some more time debugging a system which requires this
>> > patch: a system, where on a SPI interface a response to a command
>> > could come way later then the command data transmission completes.
>> >
>> > The original patch was trying to address many corner cases, but come
>> > to think of it, in this situation the slave does not care about extra
>> > data sent on the transmit interface, as otherwise there is no clock
>> > and no data could be transferred from the slave.
>> >
>> > Then, for this SPI interface we do not need to set the counter of
>> > clocks, and do not need to keep adding more clocks if the data has not
>> > been received yet, the clocks could be just free running. And then the
>> > patch becomes much simpler, what do you think:
>>
>> Does this deal with the performance problems that the old driver code
>> had? There were a number of other patches sent upstream by Rajeshwari
>> also. I wonder if it might be easier to do your improvement as a
>> separate patch on top of those instead. Then it can be considered on
>> its merits.
>>
>
> Hi Simon,
>
> what performance problems are there? Do you mean that u-boot is not
> fast enough when polling the SPI interface? I thought about this -
> even when clocking at 50MHz (resulting in 6.125 MB/s transfer rate)
> with 64 byte FIFOs there should be no problem when serving the
> interface, especially when receive and transmit flows are split in
> time.
>
> Have there been any evidence of performance problems?  Also, I noticed
> that the driver does not pay any respect to error conditions. I am
> planning to add error monitoring/processing code, as this would be a
> good way to know if there indeed are performance problems.

The issue is not the hardware but the software. Yes the hardware is
well able to keep up, but it does have some oddities. For example
reading the FIFO level registers seems to take a while, as does
reading/writing data to the FIFO.

I did a bit of benchmarking comparing the original upstream driver
with the driver after Rajeshwari's patches are applied. I posted that
to the list earlier today, but roughly speaking it is 100x faster, and
SPI boot time is reduced by about half a second. Unfortunately it is a
bit more complicated, but it is reliable and the code is well tested
with lots of units in the field :-)

Regards,
Simon

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

* [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode
  2013-05-06 14:37   ` Simon Glass
@ 2013-05-06 16:01     ` Vadim Bendebury
  2013-05-11 21:38       ` Simon Glass
  0 siblings, 1 reply; 15+ messages in thread
From: Vadim Bendebury @ 2013-05-06 16:01 UTC (permalink / raw)
  To: u-boot

On Mon, May 6, 2013 at 7:37 AM, Simon Glass <sjg@chromium.org> wrote:
>
> HI Vadim,
>
> On Thu, May 2, 2013 at 11:12 PM, Vadim Bendebury <vbendeb@chromium.org> wrote:
> > [the original patch removed, re-sending from a registered address]
> >
> > So, I spent some more time debugging a system which requires this
> > patch: a system, where on a SPI interface a response to a command
> > could come way later then the command data transmission completes.
> >
> > The original patch was trying to address many corner cases, but come
> > to think of it, in this situation the slave does not care about extra
> > data sent on the transmit interface, as otherwise there is no clock
> > and no data could be transferred from the slave.
> >
> > Then, for this SPI interface we do not need to set the counter of
> > clocks, and do not need to keep adding more clocks if the data has not
> > been received yet, the clocks could be just free running. And then the
> > patch becomes much simpler, what do you think:
>
> Does this deal with the performance problems that the old driver code
> had? There were a number of other patches sent upstream by Rajeshwari
> also. I wonder if it might be easier to do your improvement as a
> separate patch on top of those instead. Then it can be considered on
> its merits.
>

Hi Simon,

what performance problems are there? Do you mean that u-boot is not
fast enough when polling the SPI interface? I thought about this -
even when clocking at 50MHz (resulting in 6.125 MB/s transfer rate)
with 64 byte FIFOs there should be no problem when serving the
interface, especially when receive and transmit flows are split in
time.

Have there been any evidence of performance problems?  Also, I noticed
that the driver does not pay any respect to error conditions. I am
planning to add error monitoring/processing code, as this would be a
good way to know if there indeed are performance problems.

cheers, --vb


> Regards,
> Simon

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

* [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode
  2013-05-03  5:12 ` Vadim Bendebury
@ 2013-05-06 14:37   ` Simon Glass
  2013-05-06 16:01     ` Vadim Bendebury
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2013-05-06 14:37 UTC (permalink / raw)
  To: u-boot

HI Vadim,

On Thu, May 2, 2013 at 11:12 PM, Vadim Bendebury <vbendeb@chromium.org> wrote:
> [the original patch removed, re-sending from a registered address]
>
> So, I spent some more time debugging a system which requires this
> patch: a system, where on a SPI interface a response to a command
> could come way later then the command data transmission completes.
>
> The original patch was trying to address many corner cases, but come
> to think of it, in this situation the slave does not care about extra
> data sent on the transmit interface, as otherwise there is no clock
> and no data could be transferred from the slave.
>
> Then, for this SPI interface we do not need to set the counter of
> clocks, and do not need to keep adding more clocks if the data has not
> been received yet, the clocks could be just free running. And then the
> patch becomes much simpler, what do you think:

Does this deal with the performance problems that the old driver code
had? There were a number of other patches sent upstream by Rajeshwari
also. I wonder if it might be easier to do your improvement as a
separate patch on top of those instead. Then it can be considered on
its merits.

Regards,
Simon

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

* [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode
  2013-05-03  4:53 [U-Boot] [PATCH 2/2] " Vadim Bendebury
@ 2013-05-03  5:12 ` Vadim Bendebury
  2013-05-06 14:37   ` Simon Glass
  0 siblings, 1 reply; 15+ messages in thread
From: Vadim Bendebury @ 2013-05-03  5:12 UTC (permalink / raw)
  To: u-boot

[the original patch removed, re-sending from a registered address]

So, I spent some more time debugging a system which requires this
patch: a system, where on a SPI interface a response to a command
could come way later then the command data transmission completes.

The original patch was trying to address many corner cases, but come
to think of it, in this situation the slave does not care about extra
data sent on the transmit interface, as otherwise there is no clock
and no data could be transferred from the slave.

Then, for this SPI interface we do not need to set the counter of
clocks, and do not need to keep adding more clocks if the data has not
been received yet, the clocks could be just free running. And then the
patch becomes much simpler, what do you think:

diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index c697db8..fff8310 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -211,10 +211,10 @@ static void spi_get_fifo_levels(struct exynos_spi *regs,
  */
 static void spi_request_bytes(struct exynos_spi *regs, int count)
 {
-       assert(count && count < (1 << 16));
        setbits_le32(&regs->ch_cfg, SPI_CH_RST);
        clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
-       writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
+       if (count)
+               writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
 }

 static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
@@ -225,14 +225,20 @@ static void spi_rx_tx(struct exynos_spi_slave
*spi_slave, int todo,
        const uchar *txp = *doutp;
        int rx_lvl, tx_lvl;
        uint out_bytes, in_bytes;
-
+       int hunting;
+
+       if (spi_slave->free_running_mode) {
+               spi_request_bytes(regs, 0);
+               hunting = 1;
+       } else {
+               hunting = 0;
+               spi_request_bytes(regs, todo);
+       }
        out_bytes = in_bytes = todo;

-       /*
-        * If there's something to send, do a software reset and set a
-        * transaction size.
-        */
-       spi_request_bytes(regs, todo);
+       /* Software reset the channel. */
+       setbits_le32(&regs->ch_cfg, SPI_CH_RST);
+       clrbits_le32(&regs->ch_cfg, SPI_CH_RST);

        /*
         * Bytes are transmitted/received in pairs. Wait to receive all the
@@ -243,13 +249,23 @@ static void spi_rx_tx(struct exynos_spi_slave
*spi_slave, int todo,

                /* Keep the fifos full/empty. */
                spi_get_fifo_levels(regs, &rx_lvl, &tx_lvl);
-               if (tx_lvl < spi_slave->fifo_size && out_bytes) {
-                       temp = txp ? *txp++ : 0xff;
+               if (tx_lvl < spi_slave->fifo_size) {
+                       if (txp && out_bytes) {
+                               temp = *txp++;
+                               out_bytes--;
+                       } else {
+                               temp = 0xff;
+                       }
                        writel(temp, &regs->tx_data);
-                       out_bytes--;
                }
                if (rx_lvl > 0 && in_bytes) {
                        temp = readl(&regs->rx_data);
+                       if (hunting) {
+                               if ((temp & 0xff) != PREAMBLE_VALUE)
+                                       continue;
+                               else
+                                       hunting = 0;
+                       }
                        if (rxp)
                                *rxp++ = temp;
                        in_bytes--;

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

* [U-Boot]  [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode
@ 2013-05-03  4:53 Vadim Bendebury
  2013-05-03  5:12 ` Vadim Bendebury
  0 siblings, 1 reply; 15+ messages in thread
From: Vadim Bendebury @ 2013-05-03  4:53 UTC (permalink / raw)
  To: u-boot

[the original patch removed]

So, I spent some more time debugging a system which requires this
patch: a system, where on a SPI interface a response to a command
could come way later then the command data transmission completes.

The original patch was trying to address many corner cases, but come
to think of it, in this situation the slave does not care about extra
data sent on the transmit interface, as otherwise there is no clock
and no data could be transferred from the slave.

Then, for this SPI interface we do not need to set the counter of
clocks, and do not need to keep adding more clocks if the data has not
been received yet, the clocks could be just free running. And then the
patch becomes much simpler, what do you think:

diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index c697db8..fff8310 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -211,10 +211,10 @@ static void spi_get_fifo_levels(struct exynos_spi *regs,
  */
 static void spi_request_bytes(struct exynos_spi *regs, int count)
 {
-       assert(count && count < (1 << 16));
        setbits_le32(&regs->ch_cfg, SPI_CH_RST);
        clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
-       writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
+       if (count)
+               writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
 }

 static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
@@ -225,14 +225,20 @@ static void spi_rx_tx(struct exynos_spi_slave
*spi_slave, int todo,
        const uchar *txp = *doutp;
        int rx_lvl, tx_lvl;
        uint out_bytes, in_bytes;
-
+       int hunting;
+
+       if (spi_slave->free_running_mode) {
+               spi_request_bytes(regs, 0);
+               hunting = 1;
+       } else {
+               hunting = 0;
+               spi_request_bytes(regs, todo);
+       }
        out_bytes = in_bytes = todo;

-       /*
-        * If there's something to send, do a software reset and set a
-        * transaction size.
-        */
-       spi_request_bytes(regs, todo);
+       /* Software reset the channel. */
+       setbits_le32(&regs->ch_cfg, SPI_CH_RST);
+       clrbits_le32(&regs->ch_cfg, SPI_CH_RST);

        /*
         * Bytes are transmitted/received in pairs. Wait to receive all the
@@ -243,13 +249,23 @@ static void spi_rx_tx(struct exynos_spi_slave
*spi_slave, int todo,

                /* Keep the fifos full/empty. */
                spi_get_fifo_levels(regs, &rx_lvl, &tx_lvl);
-               if (tx_lvl < spi_slave->fifo_size && out_bytes) {
-                       temp = txp ? *txp++ : 0xff;
+               if (tx_lvl < spi_slave->fifo_size) {
+                       if (txp && out_bytes) {
+                               temp = *txp++;
+                               out_bytes--;
+                       } else {
+                               temp = 0xff;
+                       }
                        writel(temp, &regs->tx_data);
-                       out_bytes--;
                }
                if (rx_lvl > 0 && in_bytes) {
                        temp = readl(&regs->rx_data);
+                       if (hunting) {
+                               if ((temp & 0xff) != PREAMBLE_VALUE)
+                                       continue;
+                               else
+                                       hunting = 0;
+                       }
                        if (rxp)
                                *rxp++ = temp;
                        in_bytes--;

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

end of thread, other threads:[~2013-05-21 12:30 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-22  6:29 [U-Boot] [PATCH 0/2] SPI: Enable SPI_PREAMBLE Mode Rajeshwari Shinde
2013-03-22  6:29 ` [U-Boot] [PATCH 1/2] SPI: Add support for preamble bytes Rajeshwari Shinde
2013-05-11 14:42   ` Simon Glass
2013-03-22  6:29 ` [U-Boot] [PATCH 2/2] EXYNOS: SPI: Support SPI_PREAMBLE mode Rajeshwari Shinde
2013-05-03  1:28   ` Vadim Bendebury
2013-05-06 12:06     ` Simon Glass
2013-05-11 14:41     ` Simon Glass
2013-05-11 15:04   ` [U-Boot] [PATCH v2] " Simon Glass
2013-05-11 15:05     ` Simon Glass
2013-05-21 12:30     ` Minkyu Kang
2013-05-03  4:53 [U-Boot] [PATCH 2/2] " Vadim Bendebury
2013-05-03  5:12 ` Vadim Bendebury
2013-05-06 14:37   ` Simon Glass
2013-05-06 16:01     ` Vadim Bendebury
2013-05-11 21:38       ` Simon Glass

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.