* [PATCH 02/11] spi: fsl-espi: remove unneeded check for SPI_QE_CPU_MODE
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2016-10-02 12:22 ` Heiner Kallweit
[not found] ` <20608368-44e6-21f8-d970-5ade9990ce59-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-10-02 12:22 ` [PATCH 03/11] spi: fsl-espi: fix handling of word sizes other than 8 bit Heiner Kallweit
` (17 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-02 12:22 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
SPI_QE_CPU_MODE doesn't exist for ESPI and is set by of_mpc8xxx_spi_probe
based on DT property "mode". This property is not defined for ESPI,
see Documentation/devicetree/bindings/spi/fsl-spi.txt
Therefore remove the check.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/spi/spi-fsl-espi.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 65bb70d..8281aea1 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -594,11 +594,6 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
if (ret)
goto err_probe;
- if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
- mpc8xxx_spi->rx_shift = 16;
- mpc8xxx_spi->tx_shift = 24;
- }
-
/* SPI controller initializations */
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODE, 0);
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0);
--
2.10.0
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 03/11] spi: fsl-espi: fix handling of word sizes other than 8 bit
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-10-02 12:22 ` [PATCH 02/11] spi: fsl-espi: remove unneeded check for SPI_QE_CPU_MODE Heiner Kallweit
@ 2016-10-02 12:22 ` Heiner Kallweit
2016-10-02 12:23 ` [PATCH 04/11] spi: fsl-espi: fix and improve writing to TX FIFO Heiner Kallweit
` (16 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-02 12:22 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
The code in fsl_espi_tx_buf_lsb and parts of fsl_espi_setup_transfer
look very weird and don't reflect the ESPI spec.
ESPI stores values with <= 8 bit word size right justified as 8 bit
value and values with > 8 bit word size right justified as 16 bit
value. Therefore no such shifting is needed.
Only case MSB-first with 8 bit word size is correctly handled,
and most likely nobody ever used this driver with a different config.
On ESPI only the case LSB-first with word size > 8 bit needs a
special handling. In this case a little endian 16 bit value has
to be written to the TX FIFO what requires a byte swap as the
host system is big endian.
The same applies to reading from the RX FIFO.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/spi/spi-fsl-espi.c | 84 ++++++++++++++++++++--------------------------
1 file changed, 36 insertions(+), 48 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 8281aea1..4a7fe77 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -112,6 +112,32 @@ static inline void fsl_espi_write_reg8(struct mpc8xxx_spi *mspi, int offset,
iowrite8(val, mspi->reg_base + offset);
}
+static void fsl_espi_memcpy_swab(void *to, const void *from,
+ struct spi_message *m,
+ struct spi_transfer *t)
+{
+ unsigned int len = t->len;
+
+ if (!(m->spi->mode & SPI_LSB_FIRST) || t->bits_per_word <= 8) {
+ memcpy(to, from, len);
+ return;
+ }
+
+ /* In case of LSB-first and bits_per_word > 8 byte-swap all words */
+ while (len)
+ if (len >= 4) {
+ *(u32 *)to = swahb32p(from);
+ to += 4;
+ from += 4;
+ len -= 4;
+ } else {
+ *(u16 *)to = swab16p(from);
+ to += 2;
+ from += 2;
+ len -= 2;
+ }
+}
+
static void fsl_espi_copy_to_buf(struct spi_message *m,
struct mpc8xxx_spi *mspi)
{
@@ -120,7 +146,7 @@ static void fsl_espi_copy_to_buf(struct spi_message *m,
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->tx_buf)
- memcpy(buf, t->tx_buf, t->len);
+ fsl_espi_memcpy_swab(buf, t->tx_buf, m, t);
else
memset(buf, 0, t->len);
buf += t->len;
@@ -135,7 +161,7 @@ static void fsl_espi_copy_from_buf(struct spi_message *m,
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->rx_buf)
- memcpy(t->rx_buf, buf, t->len);
+ fsl_espi_memcpy_swab(t->rx_buf, buf, m, t);
buf += t->len;
}
}
@@ -194,27 +220,6 @@ static void fsl_espi_change_mode(struct spi_device *spi)
local_irq_restore(flags);
}
-static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi)
-{
- u32 data;
- u16 data_h;
- u16 data_l;
- const u32 *tx = mpc8xxx_spi->tx;
-
- if (!tx)
- return 0;
-
- data = *tx++ << mpc8xxx_spi->tx_shift;
- data_l = data & 0xffff;
- data_h = (data >> 16) & 0xffff;
- swab16s(&data_l);
- swab16s(&data_h);
- data = data_h | data_l;
-
- mpc8xxx_spi->tx = tx;
- return data;
-}
-
static void fsl_espi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
@@ -224,23 +229,6 @@ static void fsl_espi_setup_transfer(struct spi_device *spi,
u8 pm;
struct spi_mpc8xxx_cs *cs = spi->controller_state;
- cs->rx_shift = 0;
- cs->tx_shift = 0;
- cs->get_rx = mpc8xxx_spi_rx_buf_u32;
- cs->get_tx = mpc8xxx_spi_tx_buf_u32;
- if (bits_per_word <= 8) {
- cs->rx_shift = 8 - bits_per_word;
- } else {
- cs->rx_shift = 16 - bits_per_word;
- if (spi->mode & SPI_LSB_FIRST)
- cs->get_tx = fsl_espi_tx_buf_lsb;
- }
-
- mpc8xxx_spi->rx_shift = cs->rx_shift;
- mpc8xxx_spi->tx_shift = cs->tx_shift;
- mpc8xxx_spi->get_rx = cs->get_rx;
- mpc8xxx_spi->get_tx = cs->get_tx;
-
/* mask out bits we are going to set */
cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16 | CSMODE_PM(0xF));
@@ -271,7 +259,6 @@ static void fsl_espi_setup_transfer(struct spi_device *spi,
static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
- u32 word;
int ret;
mpc8xxx_spi->len = t->len;
@@ -290,8 +277,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_RNE);
/* transmit word */
- word = mpc8xxx_spi->get_tx(mpc8xxx_spi);
- fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPITF, word);
+ fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPITF, *(u32 *)mpc8xxx_spi->tx);
+ mpc8xxx_spi->tx += 4;
/* Won't hang up forever, SPI bus sometimes got lost interrupts... */
ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ);
@@ -468,8 +455,10 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
mspi->len -= rx_nr_bytes;
- if (mspi->rx)
- mspi->get_rx(rx_data, mspi);
+ if (mspi->rx) {
+ *(u32 *)mspi->rx = rx_data;
+ mspi->rx += 4;
+ }
}
if (!(events & SPIE_TNF)) {
@@ -487,9 +476,8 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
mspi->count -= 1;
if (mspi->count) {
- u32 word = mspi->get_tx(mspi);
-
- fsl_espi_write_reg(mspi, ESPI_SPITF, word);
+ fsl_espi_write_reg(mspi, ESPI_SPITF, *(u32 *)mspi->tx);
+ mspi->tx += 4;
} else {
complete(&mspi->done);
}
--
2.10.0
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 04/11] spi: fsl-espi: fix and improve writing to TX FIFO
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-10-02 12:22 ` [PATCH 02/11] spi: fsl-espi: remove unneeded check for SPI_QE_CPU_MODE Heiner Kallweit
2016-10-02 12:22 ` [PATCH 03/11] spi: fsl-espi: fix handling of word sizes other than 8 bit Heiner Kallweit
@ 2016-10-02 12:23 ` Heiner Kallweit
[not found] ` <c246dbf2-c59e-f029-afa1-8a5c6f6dd24b-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-10-02 12:23 ` [PATCH 05/11] spi: fsl-espi: Rename len in struct mpc8xxx_spi to rx_len and make it unsigned Heiner Kallweit
` (15 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-02 12:23 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
This change addresses two issues:
- If the TX FIFO is full the ISR polls until there's free space again.
An ISR should never wait for something.
- Currently the number of bytes to transfer is rounded up to the next
multiple of 4. For most transfers therefore few bytes remain in the
TX FIFO after end of transfer.
This would cause the next transfer to fail and as a workaround the
ESPI block is disabled / re-enabled in fsl_espi_change_mode.
This seems to clear the FIFO's (although it's not mentioned in the
spec).
With this change the TX FIFO is filled as much as possible initially
and whenever the ISR is called. Also the exact number of bytes is
transferred.
The spinlock protects against a potential race if the first interrupt
occurs whilst the TX FIFO is still being initially filled.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/spi/spi-fsl-espi.c | 68 ++++++++++++++++++++++++++++------------------
drivers/spi/spi-fsl-lib.h | 2 ++
2 files changed, 44 insertions(+), 26 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 4a7fe77..9068861 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -54,6 +54,8 @@
#define CSMODE_AFT(x) ((x) << 8)
#define CSMODE_CG(x) ((x) << 3)
+#define FSL_ESPI_FIFO_SIZE 32
+
/* Default mode/csmode for eSPI controller */
#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3))
#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
@@ -200,6 +202,27 @@ static int fsl_espi_check_message(struct spi_message *m)
return 0;
}
+static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events)
+{
+ u32 tx_fifo_avail;
+
+ /* if events is zero transfer has not started and tx fifo is empty */
+ tx_fifo_avail = events ? SPIE_TXCNT(events) : FSL_ESPI_FIFO_SIZE;
+
+ while (tx_fifo_avail >= min(4U, mspi->tx_len) && mspi->tx_len)
+ if (mspi->tx_len >= 4) {
+ fsl_espi_write_reg(mspi, ESPI_SPITF, *(u32 *)mspi->tx);
+ mspi->tx += 4;
+ mspi->tx_len -= 4;
+ tx_fifo_avail -= 4;
+ } else {
+ fsl_espi_write_reg8(mspi, ESPI_SPITF, *(u8 *)mspi->tx);
+ mspi->tx += 1;
+ mspi->tx_len -= 1;
+ tx_fifo_avail -= 1;
+ }
+}
+
static void fsl_espi_change_mode(struct spi_device *spi)
{
struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
@@ -262,7 +285,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
int ret;
mpc8xxx_spi->len = t->len;
- mpc8xxx_spi->count = roundup(t->len, 4) / 4;
+ mpc8xxx_spi->tx_len = t->len;
mpc8xxx_spi->tx = t->tx_buf;
mpc8xxx_spi->rx = t->rx_buf;
@@ -276,21 +299,22 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
/* enable rx ints */
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_RNE);
- /* transmit word */
- fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPITF, *(u32 *)mpc8xxx_spi->tx);
- mpc8xxx_spi->tx += 4;
+ /* Prevent filling the fifo from getting interrupted */
+ spin_lock_irq(&mpc8xxx_spi->lock);
+ fsl_espi_fill_tx_fifo(mpc8xxx_spi, 0);
+ spin_unlock_irq(&mpc8xxx_spi->lock);
/* Won't hang up forever, SPI bus sometimes got lost interrupts... */
ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ);
if (ret == 0)
dev_err(mpc8xxx_spi->dev,
- "Transaction hanging up (left %d bytes)\n",
- mpc8xxx_spi->count);
+ "Transaction hanging up (left %u bytes)\n",
+ mpc8xxx_spi->tx_len);
/* disable rx ints */
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0);
- return mpc8xxx_spi->count > 0 ? -EMSGSIZE : 0;
+ return mpc8xxx_spi->tx_len > 0 ? -EMSGSIZE : 0;
}
static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
@@ -461,26 +485,11 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
}
}
- if (!(events & SPIE_TNF)) {
- int ret;
-
- /* spin until TX is done */
- ret = spin_event_timeout(((events = fsl_espi_read_reg(
- mspi, ESPI_SPIE)) & SPIE_TNF), 1000, 0);
- if (!ret) {
- dev_err(mspi->dev, "tired waiting for SPIE_TNF\n");
- complete(&mspi->done);
- return;
- }
- }
+ if (mspi->tx_len)
+ fsl_espi_fill_tx_fifo(mspi, events);
- mspi->count -= 1;
- if (mspi->count) {
- fsl_espi_write_reg(mspi, ESPI_SPITF, *(u32 *)mspi->tx);
- mspi->tx += 4;
- } else {
+ if (!mspi->tx_len && !mspi->len)
complete(&mspi->done);
- }
}
static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
@@ -488,10 +497,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
struct mpc8xxx_spi *mspi = context_data;
u32 events;
+ spin_lock(&mspi->lock);
+
/* Get interrupt events(tx/rx) */
events = fsl_espi_read_reg(mspi, ESPI_SPIE);
- if (!events)
+ if (!events) {
+ spin_unlock_irq(&mspi->lock);
return IRQ_NONE;
+ }
dev_vdbg(mspi->dev, "%s: events %x\n", __func__, events);
@@ -500,6 +513,8 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
/* Clear the events */
fsl_espi_write_reg(mspi, ESPI_SPIE, events);
+ spin_unlock(&mspi->lock);
+
return IRQ_HANDLED;
}
@@ -562,6 +577,7 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
master->max_message_size = fsl_espi_max_message_size;
mpc8xxx_spi = spi_master_get_devdata(master);
+ spin_lock_init(&mpc8xxx_spi->lock);
mpc8xxx_spi->local_buf =
devm_kmalloc(dev, SPCOM_TRANLEN_MAX, GFP_KERNEL);
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index 2925c80..24d8bc8 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -30,7 +30,9 @@ struct mpc8xxx_spi {
void *rx;
#if IS_ENABLED(CONFIG_SPI_FSL_ESPI)
int len;
+ unsigned int tx_len;
u8 *local_buf;
+ spinlock_t lock;
#endif
int subblock;
--
2.10.0
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 05/11] spi: fsl-espi: Rename len in struct mpc8xxx_spi to rx_len and make it unsigned
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (2 preceding siblings ...)
2016-10-02 12:23 ` [PATCH 04/11] spi: fsl-espi: fix and improve writing to TX FIFO Heiner Kallweit
@ 2016-10-02 12:23 ` Heiner Kallweit
2016-10-02 12:23 ` [PATCH 06/11] spi: fsl-espi: simplify and inline function fsl_espi_change_mode Heiner Kallweit
` (14 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-02 12:23 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
Now that we introduced element tx_len in struct mpc8xxx_spi let's
rename element len to rx_len as it actually is the number of bytes to
receive. In addition make it unsigned.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/spi/spi-fsl-espi.c | 22 +++++++++++-----------
drivers/spi/spi-fsl-lib.h | 2 +-
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 9068861..d9d9f7f 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -284,7 +284,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
int ret;
- mpc8xxx_spi->len = t->len;
+ mpc8xxx_spi->rx_len = t->len;
mpc8xxx_spi->tx_len = t->len;
mpc8xxx_spi->tx = t->tx_buf;
@@ -445,28 +445,28 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
int ret;
/* Spin until RX is done */
- if (SPIE_RXCNT(events) < min(4, mspi->len)) {
+ if (SPIE_RXCNT(events) < min(4U, mspi->rx_len)) {
ret = spin_event_timeout(
!(SPIE_RXCNT(events =
fsl_espi_read_reg(mspi, ESPI_SPIE)) <
- min(4, mspi->len)),
+ min(4U, mspi->rx_len)),
10000, 0); /* 10 msec */
if (!ret)
dev_err(mspi->dev,
"tired waiting for SPIE_RXCNT\n");
}
- if (mspi->len >= 4) {
+ if (mspi->rx_len >= 4) {
rx_data = fsl_espi_read_reg(mspi, ESPI_SPIRF);
- } else if (mspi->len <= 0) {
+ } else if (!mspi->rx_len) {
dev_err(mspi->dev,
"unexpected RX(SPIE_RNE) interrupt occurred,\n"
"(local rxlen %d bytes, reg rxlen %d bytes)\n",
- min(4, mspi->len), SPIE_RXCNT(events));
+ min(4U, mspi->rx_len), SPIE_RXCNT(events));
rx_nr_bytes = 0;
} else {
- rx_nr_bytes = mspi->len;
- tmp = mspi->len;
+ rx_nr_bytes = mspi->rx_len;
+ tmp = mspi->rx_len;
rx_data = 0;
while (tmp--) {
rx_data_8 = fsl_espi_read_reg8(mspi,
@@ -474,10 +474,10 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
rx_data |= (rx_data_8 << (tmp * 8));
}
- rx_data <<= (4 - mspi->len) * 8;
+ rx_data <<= (4 - mspi->rx_len) * 8;
}
- mspi->len -= rx_nr_bytes;
+ mspi->rx_len -= rx_nr_bytes;
if (mspi->rx) {
*(u32 *)mspi->rx = rx_data;
@@ -488,7 +488,7 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
if (mspi->tx_len)
fsl_espi_fill_tx_fifo(mspi, events);
- if (!mspi->tx_len && !mspi->len)
+ if (!mspi->tx_len && !mspi->rx_len)
complete(&mspi->done);
}
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index 24d8bc8..35a7a17 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -29,7 +29,7 @@ struct mpc8xxx_spi {
const void *tx;
void *rx;
#if IS_ENABLED(CONFIG_SPI_FSL_ESPI)
- int len;
+ unsigned int rx_len;
unsigned int tx_len;
u8 *local_buf;
spinlock_t lock;
--
2.10.0
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 06/11] spi: fsl-espi: simplify and inline function fsl_espi_change_mode
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (3 preceding siblings ...)
2016-10-02 12:23 ` [PATCH 05/11] spi: fsl-espi: Rename len in struct mpc8xxx_spi to rx_len and make it unsigned Heiner Kallweit
@ 2016-10-02 12:23 ` Heiner Kallweit
[not found] ` <0aeb49f0-dbfb-7acb-3829-cabafe4e7291-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-10-02 12:23 ` [PATCH 07/11] spi: fsl-espi: fix and improve reading from RX FIFO Heiner Kallweit
` (13 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-02 12:23 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
The ESPI spec mentions no requirement to turn off the ESPI unit prior
to changing the mode. Most likely the ESPI unit is only turned off to
clear the FIFO's as before this patch series single bytes could
remain in the TX FIFO after transfer end.
Therefore remove disabling / re-enabling the ESPI unit.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/spi/spi-fsl-espi.c | 23 ++---------------------
1 file changed, 2 insertions(+), 21 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index d9d9f7f..c3e55c8 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -223,26 +223,6 @@ static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events)
}
}
-static void fsl_espi_change_mode(struct spi_device *spi)
-{
- struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
- struct spi_mpc8xxx_cs *cs = spi->controller_state;
- u32 tmp;
- unsigned long flags;
-
- /* Turn off IRQs locally to minimize time that SPI is disabled. */
- local_irq_save(flags);
-
- /* Turn off SPI unit prior changing mode */
- tmp = fsl_espi_read_reg(mspi, ESPI_SPMODE);
- fsl_espi_write_reg(mspi, ESPI_SPMODE, tmp & ~SPMODE_ENABLE);
- fsl_espi_write_reg(mspi, ESPI_SPMODEx(spi->chip_select),
- cs->hw_mode);
- fsl_espi_write_reg(mspi, ESPI_SPMODE, tmp);
-
- local_irq_restore(flags);
-}
-
static void fsl_espi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
@@ -276,7 +256,8 @@ static void fsl_espi_setup_transfer(struct spi_device *spi,
cs->hw_mode |= CSMODE_PM(pm);
- fsl_espi_change_mode(spi);
+ fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODEx(spi->chip_select),
+ cs->hw_mode);
}
static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
--
2.10.0
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 07/11] spi: fsl-espi: fix and improve reading from RX FIFO
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (4 preceding siblings ...)
2016-10-02 12:23 ` [PATCH 06/11] spi: fsl-espi: simplify and inline function fsl_espi_change_mode Heiner Kallweit
@ 2016-10-02 12:23 ` Heiner Kallweit
2016-10-02 12:23 ` [PATCH 08/11] spi: fsl-espi: make better use of the " Heiner Kallweit
` (12 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-02 12:23 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
Currently the driver polls in the ISR for enough bytes in the RX FIFO.
An ISR should never do this.
Change it to read as much as possible whenever the ISR is called.
This also allows to significantly simplify the code.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/spi/spi-fsl-espi.c | 67 ++++++++++++++--------------------------------
1 file changed, 20 insertions(+), 47 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index c3e55c8..5abbb62 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -223,6 +223,24 @@ static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events)
}
}
+static void fsl_espi_read_rx_fifo(struct mpc8xxx_spi *mspi, u32 events)
+{
+ u32 rx_fifo_avail = SPIE_RXCNT(events);
+
+ while (rx_fifo_avail >= min(4U, mspi->rx_len) && mspi->rx_len)
+ if (mspi->rx_len >= 4) {
+ *(u32 *)mspi->rx = fsl_espi_read_reg(mspi, ESPI_SPIRF);
+ mspi->rx += 4;
+ mspi->rx_len -= 4;
+ rx_fifo_avail -= 4;
+ } else {
+ *(u8 *)mspi->rx = fsl_espi_read_reg8(mspi, ESPI_SPIRF);
+ mspi->rx += 1;
+ mspi->rx_len -= 1;
+ rx_fifo_avail -= 1;
+ }
+}
+
static void fsl_espi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
@@ -418,53 +436,8 @@ static void fsl_espi_cleanup(struct spi_device *spi)
static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
{
- /* We need handle RX first */
- if (events & SPIE_RNE) {
- u32 rx_data, tmp;
- u8 rx_data_8;
- int rx_nr_bytes = 4;
- int ret;
-
- /* Spin until RX is done */
- if (SPIE_RXCNT(events) < min(4U, mspi->rx_len)) {
- ret = spin_event_timeout(
- !(SPIE_RXCNT(events =
- fsl_espi_read_reg(mspi, ESPI_SPIE)) <
- min(4U, mspi->rx_len)),
- 10000, 0); /* 10 msec */
- if (!ret)
- dev_err(mspi->dev,
- "tired waiting for SPIE_RXCNT\n");
- }
-
- if (mspi->rx_len >= 4) {
- rx_data = fsl_espi_read_reg(mspi, ESPI_SPIRF);
- } else if (!mspi->rx_len) {
- dev_err(mspi->dev,
- "unexpected RX(SPIE_RNE) interrupt occurred,\n"
- "(local rxlen %d bytes, reg rxlen %d bytes)\n",
- min(4U, mspi->rx_len), SPIE_RXCNT(events));
- rx_nr_bytes = 0;
- } else {
- rx_nr_bytes = mspi->rx_len;
- tmp = mspi->rx_len;
- rx_data = 0;
- while (tmp--) {
- rx_data_8 = fsl_espi_read_reg8(mspi,
- ESPI_SPIRF);
- rx_data |= (rx_data_8 << (tmp * 8));
- }
-
- rx_data <<= (4 - mspi->rx_len) * 8;
- }
-
- mspi->rx_len -= rx_nr_bytes;
-
- if (mspi->rx) {
- *(u32 *)mspi->rx = rx_data;
- mspi->rx += 4;
- }
- }
+ if (mspi->rx_len)
+ fsl_espi_read_rx_fifo(mspi, events);
if (mspi->tx_len)
fsl_espi_fill_tx_fifo(mspi, events);
--
2.10.0
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 08/11] spi: fsl-espi: make better use of the RX FIFO
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (5 preceding siblings ...)
2016-10-02 12:23 ` [PATCH 07/11] spi: fsl-espi: fix and improve reading from RX FIFO Heiner Kallweit
@ 2016-10-02 12:23 ` Heiner Kallweit
[not found] ` <144b73b1-dff2-a5b6-9df1-837238f20008-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-10-02 12:23 ` [PATCH 09/11] spi: fsl-espi: extend and improve transfer error handling Heiner Kallweit
` (11 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-02 12:23 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
So far an interrupt is triggered whenever there's at least one byte
in the RX FIFO. This results in a unnecessarily high number of
interrupts.
Change this to generate an interrupt if
- RX FIFO is half full (except if all bytes to read fit into the
RX FIFO anyway)
- end of transfer has been reached
This way the number of interrupts can be significantly reduced.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/spi/spi-fsl-espi.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 5abbb62..10d06f2 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -55,9 +55,10 @@
#define CSMODE_CG(x) ((x) << 3)
#define FSL_ESPI_FIFO_SIZE 32
+#define FSL_ESPI_RXTHR 15
/* Default mode/csmode for eSPI controller */
-#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3))
+#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(FSL_ESPI_RXTHR))
#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
| CSMODE_AFT(0) | CSMODE_CG(1))
@@ -281,6 +282,7 @@ static void fsl_espi_setup_transfer(struct spi_device *spi,
static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ u32 mask;
int ret;
mpc8xxx_spi->rx_len = t->len;
@@ -295,8 +297,11 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM,
(SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
- /* enable rx ints */
- fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_RNE);
+ /* enable interrupts */
+ mask = SPIM_DON;
+ if (mpc8xxx_spi->rx_len > FSL_ESPI_FIFO_SIZE)
+ mask |= SPIM_RXT;
+ fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, mask);
/* Prevent filling the fifo from getting interrupted */
spin_lock_irq(&mpc8xxx_spi->lock);
--
2.10.0
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 09/11] spi: fsl-espi: extend and improve transfer error handling
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (6 preceding siblings ...)
2016-10-02 12:23 ` [PATCH 08/11] spi: fsl-espi: make better use of the " Heiner Kallweit
@ 2016-10-02 12:23 ` Heiner Kallweit
[not found] ` <4ba19a7f-9f66-54c4-9119-e85671d608fb-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-10-02 12:23 ` [PATCH 10/11] spi: fsl-espi: add support for RXSKIP mode Heiner Kallweit
` (10 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-02 12:23 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
Extend and improve transfer error handling
- in case of timeout report also number of remaining rx bytes
- in case of timeout return ETIMEDOUT instead of EMSGSIZE
- add sanity checks after all bytes have been sent / read:
- check that HW has flag SPIE_DON set
- check that RX / TX FIFO are empty
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/spi/spi-fsl-espi.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 10d06f2..cbfb6da 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -312,13 +312,13 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ);
if (ret == 0)
dev_err(mpc8xxx_spi->dev,
- "Transaction hanging up (left %u bytes)\n",
- mpc8xxx_spi->tx_len);
+ "Transaction hanging up (left %u tx bytes, %u rx bytes)\n",
+ mpc8xxx_spi->tx_len, mpc8xxx_spi->rx_len);
/* disable rx ints */
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0);
- return mpc8xxx_spi->tx_len > 0 ? -EMSGSIZE : 0;
+ return ret == 0 ? -ETIMEDOUT : 0;
}
static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
@@ -447,8 +447,20 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
if (mspi->tx_len)
fsl_espi_fill_tx_fifo(mspi, events);
- if (!mspi->tx_len && !mspi->rx_len)
- complete(&mspi->done);
+ if (mspi->tx_len || mspi->rx_len)
+ return;
+
+ /* we're done, but check for errors before returning */
+ events = fsl_espi_read_reg(mspi, ESPI_SPIE);
+
+ if (!(events & SPIE_DON))
+ dev_err(mspi->dev,
+ "Transfer done but SPIE_DON isn't set!\n");
+
+ if (SPIE_RXCNT(events) || SPIE_TXCNT(events) != FSL_ESPI_FIFO_SIZE)
+ dev_err(mspi->dev, "Transfer done but rx/tx fifo's aren't empty!\n");
+
+ complete(&mspi->done);
}
static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
--
2.10.0
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 10/11] spi: fsl-espi: add support for RXSKIP mode
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (7 preceding siblings ...)
2016-10-02 12:23 ` [PATCH 09/11] spi: fsl-espi: extend and improve transfer error handling Heiner Kallweit
@ 2016-10-02 12:23 ` Heiner Kallweit
2016-10-02 12:23 ` [PATCH 11/11] spi: fsl-espi: add support for dual read mode Heiner Kallweit
` (9 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-02 12:23 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
This patch adds support for ESPI RXSKIP mode. This mode is optimized
for flash reads:
- sends a number of bytes and then reads a number of bytes
- shifts out zeros automatically when reading
- optionally can be configured for dual read mode
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/spi/spi-fsl-espi.c | 56 ++++++++++++++++++++++++++++++++++++++++++----
drivers/spi/spi-fsl-lib.h | 1 +
2 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index cbfb6da..8cfcf41 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -150,7 +150,8 @@ static void fsl_espi_copy_to_buf(struct spi_message *m,
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->tx_buf)
fsl_espi_memcpy_swab(buf, t->tx_buf, m, t);
- else
+ /* In RXSKIP mode controller shifts zeros automatically */
+ else if (!mspi->rxskip)
memset(buf, 0, t->len);
buf += t->len;
}
@@ -203,6 +204,42 @@ static int fsl_espi_check_message(struct spi_message *m)
return 0;
}
+static void fsl_espi_check_rxskip_mode(struct spi_message *m,
+ struct mpc8xxx_spi *mspi)
+{
+ struct spi_transfer *t;
+ unsigned int i = 0, rxskip_len = 0;
+
+ mspi->rxskip = 0;
+
+ /*
+ * prerequisites for rxskip mode:
+ * - message has two transfers
+ * - first transfer is a write and second is a read
+ *
+ * In addition enable rxskip mode only if length of write transfer
+ * is <= FSL_ESPI_FIFO_SIZE. This allows to keep the current
+ * low-level transfer implementation.
+ * This constraint doesn't affect SPI NOR reads as typical use case
+ * for rxskip mode as the read command has only few bytes.
+ */
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (i == 0) {
+ if (!t->tx_buf || t->rx_buf ||
+ t->len > FSL_ESPI_FIFO_SIZE)
+ return;
+ rxskip_len = t->len;
+ } else if (i == 1) {
+ if (t->tx_buf || !t->rx_buf)
+ return;
+ }
+ i++;
+ }
+
+ if (i == 2)
+ mspi->rxskip = rxskip_len;
+}
+
static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events)
{
u32 tx_fifo_avail;
@@ -282,7 +319,7 @@ static void fsl_espi_setup_transfer(struct spi_device *spi,
static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
- u32 mask;
+ u32 mask, spcom;
int ret;
mpc8xxx_spi->rx_len = t->len;
@@ -294,8 +331,18 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
reinit_completion(&mpc8xxx_spi->done);
/* Set SPCOM[CS] and SPCOM[TRANLEN] field */
- fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM,
- (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
+ spcom = SPCOM_CS(spi->chip_select);
+ spcom |= SPCOM_TRANLEN(t->len - 1);
+
+ /* configure RXSKIP mode */
+ if (mpc8xxx_spi->rxskip) {
+ spcom |= SPCOM_RXSKIP(mpc8xxx_spi->rxskip);
+ mpc8xxx_spi->tx_len = mpc8xxx_spi->rxskip;
+ mpc8xxx_spi->rx_len = t->len - mpc8xxx_spi->rxskip;
+ mpc8xxx_spi->rx = t->rx_buf + mpc8xxx_spi->rxskip;
+ }
+
+ fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM, spcom);
/* enable interrupts */
mask = SPIM_DON;
@@ -327,6 +374,7 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
struct spi_device *spi = m->spi;
int ret;
+ fsl_espi_check_rxskip_mode(m, mspi);
fsl_espi_copy_to_buf(m, mspi);
fsl_espi_setup_transfer(spi, trans);
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index 35a7a17..8096fae 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -32,6 +32,7 @@ struct mpc8xxx_spi {
unsigned int rx_len;
unsigned int tx_len;
u8 *local_buf;
+ unsigned int rxskip;
spinlock_t lock;
#endif
--
2.10.0
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 11/11] spi: fsl-espi: add support for dual read mode
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (8 preceding siblings ...)
2016-10-02 12:23 ` [PATCH 10/11] spi: fsl-espi: add support for RXSKIP mode Heiner Kallweit
@ 2016-10-02 12:23 ` Heiner Kallweit
2016-10-27 19:24 ` [PATCH v2 01/09] spi: fsl-espi: improve check for SPI_QE_CPU_MODE Heiner Kallweit
` (8 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-02 12:23 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
This patch adds support for dual output read mode.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/spi/spi-fsl-espi.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 8cfcf41..cf2a287 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -205,10 +205,11 @@ static int fsl_espi_check_message(struct spi_message *m)
}
static void fsl_espi_check_rxskip_mode(struct spi_message *m,
- struct mpc8xxx_spi *mspi)
+ struct mpc8xxx_spi *mspi,
+ struct spi_transfer *tr)
{
struct spi_transfer *t;
- unsigned int i = 0, rxskip_len = 0;
+ unsigned int i = 0, rxskip_len = 0, rx_nbits = SPI_NBITS_SINGLE;
mspi->rxskip = 0;
@@ -222,6 +223,9 @@ static void fsl_espi_check_rxskip_mode(struct spi_message *m,
* low-level transfer implementation.
* This constraint doesn't affect SPI NOR reads as typical use case
* for rxskip mode as the read command has only few bytes.
+ *
+ * Store rx_nbits of the read transfer for later assessment
+ * whether single or dual mode is requested.
*/
list_for_each_entry(t, &m->transfers, transfer_list) {
if (i == 0) {
@@ -232,12 +236,15 @@ static void fsl_espi_check_rxskip_mode(struct spi_message *m,
} else if (i == 1) {
if (t->tx_buf || !t->rx_buf)
return;
+ rx_nbits = t->rx_nbits;
}
i++;
}
- if (i == 2)
+ if (i == 2) {
mspi->rxskip = rxskip_len;
+ tr->rx_nbits = rx_nbits;
+ }
}
static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events)
@@ -340,6 +347,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
mpc8xxx_spi->tx_len = mpc8xxx_spi->rxskip;
mpc8xxx_spi->rx_len = t->len - mpc8xxx_spi->rxskip;
mpc8xxx_spi->rx = t->rx_buf + mpc8xxx_spi->rxskip;
+ if (t->rx_nbits == SPI_NBITS_DUAL)
+ spcom |= SPCOM_DO;
}
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM, spcom);
@@ -374,7 +383,7 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
struct spi_device *spi = m->spi;
int ret;
- fsl_espi_check_rxskip_mode(m, mspi);
+ fsl_espi_check_rxskip_mode(m, mspi, trans);
fsl_espi_copy_to_buf(m, mspi);
fsl_espi_setup_transfer(spi, trans);
@@ -588,6 +597,7 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
mpc8xxx_spi_probe(dev, mem, irq);
+ master->mode_bits |= SPI_RX_DUAL;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
master->setup = fsl_espi_setup;
master->cleanup = fsl_espi_cleanup;
--
2.10.0
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 01/09] spi: fsl-espi: improve check for SPI_QE_CPU_MODE
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (9 preceding siblings ...)
2016-10-02 12:23 ` [PATCH 11/11] spi: fsl-espi: add support for dual read mode Heiner Kallweit
@ 2016-10-27 19:24 ` Heiner Kallweit
[not found] ` <0b5e7849-88d6-2af5-a428-eeb0de0f2af2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-10-27 19:25 ` [PATCH v2 02/09] spi: fsl-espi: fix and improve writing to TX FIFO Heiner Kallweit
` (7 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-27 19:24 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
SPI_QE_CPU_MODE doesn't exist for ESPI and is set by of_mpc8xxx_spi_probe
based on DT property "mode". This property is not defined for ESPI,
see Documentation/devicetree/bindings/spi/fsl-spi.txt.
So print an error message and bail out if SPI_QE_CPU_MODE is set.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v2:
- print error message and bail out instead of removing the check
---
drivers/spi/spi-fsl-espi.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 4e8a99d..f04c246 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -583,8 +583,9 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
goto err_probe;
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
- mpc8xxx_spi->rx_shift = 16;
- mpc8xxx_spi->tx_shift = 24;
+ dev_err(dev, "SPI_QE_CPU_MODE is not supported on ESPI!\n");
+ ret = -EINVAL;
+ goto err_probe;
}
/* SPI controller initializations */
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 02/09] spi: fsl-espi: fix and improve writing to TX FIFO
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (10 preceding siblings ...)
2016-10-27 19:24 ` [PATCH v2 01/09] spi: fsl-espi: improve check for SPI_QE_CPU_MODE Heiner Kallweit
@ 2016-10-27 19:25 ` Heiner Kallweit
2016-10-27 19:26 ` [PATCH v2 03/09] spi: fsl-espi: Rename len in struct mpc8xxx_spi to rx_len and make it unsigned Heiner Kallweit
` (6 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-27 19:25 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
This change addresses two issues:
- If the TX FIFO is full the ISR polls until there's free space again.
An ISR should never wait for something.
- Currently the number of bytes to transfer is rounded up to the next
multiple of 4. For most transfers therefore few bytes remain in the
TX FIFO after end of transfer.
This would cause the next transfer to fail and as a workaround the
ESPI block is disabled / re-enabled in fsl_espi_change_mode.
This seems to clear the FIFO's (although it's not mentioned in the
spec).
With this change the TX FIFO is filled as much as possible initially
and whenever the ISR is called. Also the exact number of bytes is
transferred.
The spinlock protects against a potential race if the first interrupt
occurs whilst the TX FIFO is still being initially filled.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v2:
- rebased
---
drivers/spi/spi-fsl-espi.c | 68 ++++++++++++++++++++++++++++------------------
drivers/spi/spi-fsl-lib.h | 2 ++
2 files changed, 44 insertions(+), 26 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index f04c246..95c1fbf 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -54,6 +54,8 @@
#define CSMODE_AFT(x) ((x) << 8)
#define CSMODE_CG(x) ((x) << 3)
+#define FSL_ESPI_FIFO_SIZE 32
+
/* Default mode/csmode for eSPI controller */
#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3))
#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
@@ -200,6 +202,27 @@ static int fsl_espi_check_message(struct spi_message *m)
return 0;
}
+static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events)
+{
+ u32 tx_fifo_avail;
+
+ /* if events is zero transfer has not started and tx fifo is empty */
+ tx_fifo_avail = events ? SPIE_TXCNT(events) : FSL_ESPI_FIFO_SIZE;
+
+ while (tx_fifo_avail >= min(4U, mspi->tx_len) && mspi->tx_len)
+ if (mspi->tx_len >= 4) {
+ fsl_espi_write_reg(mspi, ESPI_SPITF, *(u32 *)mspi->tx);
+ mspi->tx += 4;
+ mspi->tx_len -= 4;
+ tx_fifo_avail -= 4;
+ } else {
+ fsl_espi_write_reg8(mspi, ESPI_SPITF, *(u8 *)mspi->tx);
+ mspi->tx += 1;
+ mspi->tx_len -= 1;
+ tx_fifo_avail -= 1;
+ }
+}
+
static void fsl_espi_change_mode(struct spi_device *spi)
{
struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
@@ -262,7 +285,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
int ret;
mpc8xxx_spi->len = t->len;
- mpc8xxx_spi->count = roundup(t->len, 4) / 4;
+ mpc8xxx_spi->tx_len = t->len;
mpc8xxx_spi->tx = t->tx_buf;
mpc8xxx_spi->rx = t->rx_buf;
@@ -276,21 +299,22 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
/* enable rx ints */
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_RNE);
- /* transmit word */
- fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPITF, *(u32 *)mpc8xxx_spi->tx);
- mpc8xxx_spi->tx += 4;
+ /* Prevent filling the fifo from getting interrupted */
+ spin_lock_irq(&mpc8xxx_spi->lock);
+ fsl_espi_fill_tx_fifo(mpc8xxx_spi, 0);
+ spin_unlock_irq(&mpc8xxx_spi->lock);
/* Won't hang up forever, SPI bus sometimes got lost interrupts... */
ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ);
if (ret == 0)
dev_err(mpc8xxx_spi->dev,
- "Transaction hanging up (left %d bytes)\n",
- mpc8xxx_spi->count);
+ "Transaction hanging up (left %u bytes)\n",
+ mpc8xxx_spi->tx_len);
/* disable rx ints */
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0);
- return mpc8xxx_spi->count > 0 ? -EMSGSIZE : 0;
+ return mpc8xxx_spi->tx_len > 0 ? -EMSGSIZE : 0;
}
static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
@@ -461,26 +485,11 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
}
}
- if (!(events & SPIE_TNF)) {
- int ret;
-
- /* spin until TX is done */
- ret = spin_event_timeout(((events = fsl_espi_read_reg(
- mspi, ESPI_SPIE)) & SPIE_TNF), 1000, 0);
- if (!ret) {
- dev_err(mspi->dev, "tired waiting for SPIE_TNF\n");
- complete(&mspi->done);
- return;
- }
- }
+ if (mspi->tx_len)
+ fsl_espi_fill_tx_fifo(mspi, events);
- mspi->count -= 1;
- if (mspi->count) {
- fsl_espi_write_reg(mspi, ESPI_SPITF, *(u32 *)mspi->tx);
- mspi->tx += 4;
- } else {
+ if (!mspi->tx_len && !mspi->len)
complete(&mspi->done);
- }
}
static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
@@ -488,10 +497,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
struct mpc8xxx_spi *mspi = context_data;
u32 events;
+ spin_lock(&mspi->lock);
+
/* Get interrupt events(tx/rx) */
events = fsl_espi_read_reg(mspi, ESPI_SPIE);
- if (!events)
+ if (!events) {
+ spin_unlock_irq(&mspi->lock);
return IRQ_NONE;
+ }
dev_vdbg(mspi->dev, "%s: events %x\n", __func__, events);
@@ -500,6 +513,8 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
/* Clear the events */
fsl_espi_write_reg(mspi, ESPI_SPIE, events);
+ spin_unlock(&mspi->lock);
+
return IRQ_HANDLED;
}
@@ -562,6 +577,7 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
master->max_message_size = fsl_espi_max_message_size;
mpc8xxx_spi = spi_master_get_devdata(master);
+ spin_lock_init(&mpc8xxx_spi->lock);
mpc8xxx_spi->local_buf =
devm_kmalloc(dev, SPCOM_TRANLEN_MAX, GFP_KERNEL);
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index 2925c80..24d8bc8 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -30,7 +30,9 @@ struct mpc8xxx_spi {
void *rx;
#if IS_ENABLED(CONFIG_SPI_FSL_ESPI)
int len;
+ unsigned int tx_len;
u8 *local_buf;
+ spinlock_t lock;
#endif
int subblock;
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 03/09] spi: fsl-espi: Rename len in struct mpc8xxx_spi to rx_len and make it unsigned
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (11 preceding siblings ...)
2016-10-27 19:25 ` [PATCH v2 02/09] spi: fsl-espi: fix and improve writing to TX FIFO Heiner Kallweit
@ 2016-10-27 19:26 ` Heiner Kallweit
[not found] ` <611500a3-d254-f04c-ce20-6905a649bcda-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-10-27 19:26 ` [PATCH v2 04/09] spi: fsl-espi: simplify and inline function fsl_espi_change_mode Heiner Kallweit
` (5 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-27 19:26 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
Now that we introduced element tx_len in struct mpc8xxx_spi let's
rename element len to rx_len as it actually is the number of bytes to
receive. In addition make it unsigned.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v2:
- rebased
---
drivers/spi/spi-fsl-espi.c | 22 +++++++++++-----------
drivers/spi/spi-fsl-lib.h | 2 +-
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 95c1fbf..5a7449f 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -284,7 +284,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
int ret;
- mpc8xxx_spi->len = t->len;
+ mpc8xxx_spi->rx_len = t->len;
mpc8xxx_spi->tx_len = t->len;
mpc8xxx_spi->tx = t->tx_buf;
@@ -445,28 +445,28 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
int ret;
/* Spin until RX is done */
- if (SPIE_RXCNT(events) < min(4, mspi->len)) {
+ if (SPIE_RXCNT(events) < min(4U, mspi->rx_len)) {
ret = spin_event_timeout(
!(SPIE_RXCNT(events =
fsl_espi_read_reg(mspi, ESPI_SPIE)) <
- min(4, mspi->len)),
+ min(4U, mspi->rx_len)),
10000, 0); /* 10 msec */
if (!ret)
dev_err(mspi->dev,
"tired waiting for SPIE_RXCNT\n");
}
- if (mspi->len >= 4) {
+ if (mspi->rx_len >= 4) {
rx_data = fsl_espi_read_reg(mspi, ESPI_SPIRF);
- } else if (mspi->len <= 0) {
+ } else if (!mspi->rx_len) {
dev_err(mspi->dev,
"unexpected RX(SPIE_RNE) interrupt occurred,\n"
"(local rxlen %d bytes, reg rxlen %d bytes)\n",
- min(4, mspi->len), SPIE_RXCNT(events));
+ min(4U, mspi->rx_len), SPIE_RXCNT(events));
rx_nr_bytes = 0;
} else {
- rx_nr_bytes = mspi->len;
- tmp = mspi->len;
+ rx_nr_bytes = mspi->rx_len;
+ tmp = mspi->rx_len;
rx_data = 0;
while (tmp--) {
rx_data_8 = fsl_espi_read_reg8(mspi,
@@ -474,10 +474,10 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
rx_data |= (rx_data_8 << (tmp * 8));
}
- rx_data <<= (4 - mspi->len) * 8;
+ rx_data <<= (4 - mspi->rx_len) * 8;
}
- mspi->len -= rx_nr_bytes;
+ mspi->rx_len -= rx_nr_bytes;
if (rx_nr_bytes && mspi->rx) {
*(u32 *)mspi->rx = rx_data;
@@ -488,7 +488,7 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
if (mspi->tx_len)
fsl_espi_fill_tx_fifo(mspi, events);
- if (!mspi->tx_len && !mspi->len)
+ if (!mspi->tx_len && !mspi->rx_len)
complete(&mspi->done);
}
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index 24d8bc8..35a7a17 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -29,7 +29,7 @@ struct mpc8xxx_spi {
const void *tx;
void *rx;
#if IS_ENABLED(CONFIG_SPI_FSL_ESPI)
- int len;
+ unsigned int rx_len;
unsigned int tx_len;
u8 *local_buf;
spinlock_t lock;
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 04/09] spi: fsl-espi: simplify and inline function fsl_espi_change_mode
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (12 preceding siblings ...)
2016-10-27 19:26 ` [PATCH v2 03/09] spi: fsl-espi: Rename len in struct mpc8xxx_spi to rx_len and make it unsigned Heiner Kallweit
@ 2016-10-27 19:26 ` Heiner Kallweit
2016-10-27 19:27 ` [PATCH v2 05/09] spi: fsl-espi: fix and improve reading from RX FIFO Heiner Kallweit
` (4 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-27 19:26 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
The ESPI spec mentions no requirement to turn off the ESPI unit prior
to changing the mode. Most likely the ESPI unit is only turned off to
clear the FIFO's as before this patch series single bytes could
remain in the TX FIFO after transfer end.
Therefore remove disabling / re-enabling the ESPI unit.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v2:
- rebased
---
drivers/spi/spi-fsl-espi.c | 23 ++---------------------
1 file changed, 2 insertions(+), 21 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 5a7449f..d550685 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -223,26 +223,6 @@ static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events)
}
}
-static void fsl_espi_change_mode(struct spi_device *spi)
-{
- struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
- struct spi_mpc8xxx_cs *cs = spi->controller_state;
- u32 tmp;
- unsigned long flags;
-
- /* Turn off IRQs locally to minimize time that SPI is disabled. */
- local_irq_save(flags);
-
- /* Turn off SPI unit prior changing mode */
- tmp = fsl_espi_read_reg(mspi, ESPI_SPMODE);
- fsl_espi_write_reg(mspi, ESPI_SPMODE, tmp & ~SPMODE_ENABLE);
- fsl_espi_write_reg(mspi, ESPI_SPMODEx(spi->chip_select),
- cs->hw_mode);
- fsl_espi_write_reg(mspi, ESPI_SPMODE, tmp);
-
- local_irq_restore(flags);
-}
-
static void fsl_espi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
@@ -276,7 +256,8 @@ static void fsl_espi_setup_transfer(struct spi_device *spi,
cs->hw_mode |= CSMODE_PM(pm);
- fsl_espi_change_mode(spi);
+ fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPMODEx(spi->chip_select),
+ cs->hw_mode);
}
static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 05/09] spi: fsl-espi: fix and improve reading from RX FIFO
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (13 preceding siblings ...)
2016-10-27 19:26 ` [PATCH v2 04/09] spi: fsl-espi: simplify and inline function fsl_espi_change_mode Heiner Kallweit
@ 2016-10-27 19:27 ` Heiner Kallweit
[not found] ` <6ae20ab9-4068-9be7-654d-12424de35716-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-10-27 19:27 ` [PATCH v2 06/09] spi: fsl-espi: make better use of the RX FIFO Heiner Kallweit
` (3 subsequent siblings)
18 siblings, 1 reply; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-27 19:27 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
Currently the driver polls in the ISR for enough bytes in the RX FIFO.
An ISR should never do this.
Change it to read as much as possible whenever the ISR is called.
This also allows to significantly simplify the code.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v2:
- rebased
---
drivers/spi/spi-fsl-espi.c | 67 ++++++++++++++--------------------------------
1 file changed, 20 insertions(+), 47 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index d550685..ca14575 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -223,6 +223,24 @@ static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events)
}
}
+static void fsl_espi_read_rx_fifo(struct mpc8xxx_spi *mspi, u32 events)
+{
+ u32 rx_fifo_avail = SPIE_RXCNT(events);
+
+ while (rx_fifo_avail >= min(4U, mspi->rx_len) && mspi->rx_len)
+ if (mspi->rx_len >= 4) {
+ *(u32 *)mspi->rx = fsl_espi_read_reg(mspi, ESPI_SPIRF);
+ mspi->rx += 4;
+ mspi->rx_len -= 4;
+ rx_fifo_avail -= 4;
+ } else {
+ *(u8 *)mspi->rx = fsl_espi_read_reg8(mspi, ESPI_SPIRF);
+ mspi->rx += 1;
+ mspi->rx_len -= 1;
+ rx_fifo_avail -= 1;
+ }
+}
+
static void fsl_espi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
@@ -418,53 +436,8 @@ static void fsl_espi_cleanup(struct spi_device *spi)
static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
{
- /* We need handle RX first */
- if (events & SPIE_RNE) {
- u32 rx_data, tmp;
- u8 rx_data_8;
- int rx_nr_bytes = 4;
- int ret;
-
- /* Spin until RX is done */
- if (SPIE_RXCNT(events) < min(4U, mspi->rx_len)) {
- ret = spin_event_timeout(
- !(SPIE_RXCNT(events =
- fsl_espi_read_reg(mspi, ESPI_SPIE)) <
- min(4U, mspi->rx_len)),
- 10000, 0); /* 10 msec */
- if (!ret)
- dev_err(mspi->dev,
- "tired waiting for SPIE_RXCNT\n");
- }
-
- if (mspi->rx_len >= 4) {
- rx_data = fsl_espi_read_reg(mspi, ESPI_SPIRF);
- } else if (!mspi->rx_len) {
- dev_err(mspi->dev,
- "unexpected RX(SPIE_RNE) interrupt occurred,\n"
- "(local rxlen %d bytes, reg rxlen %d bytes)\n",
- min(4U, mspi->rx_len), SPIE_RXCNT(events));
- rx_nr_bytes = 0;
- } else {
- rx_nr_bytes = mspi->rx_len;
- tmp = mspi->rx_len;
- rx_data = 0;
- while (tmp--) {
- rx_data_8 = fsl_espi_read_reg8(mspi,
- ESPI_SPIRF);
- rx_data |= (rx_data_8 << (tmp * 8));
- }
-
- rx_data <<= (4 - mspi->rx_len) * 8;
- }
-
- mspi->rx_len -= rx_nr_bytes;
-
- if (rx_nr_bytes && mspi->rx) {
- *(u32 *)mspi->rx = rx_data;
- mspi->rx += 4;
- }
- }
+ if (mspi->rx_len)
+ fsl_espi_read_rx_fifo(mspi, events);
if (mspi->tx_len)
fsl_espi_fill_tx_fifo(mspi, events);
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 06/09] spi: fsl-espi: make better use of the RX FIFO
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (14 preceding siblings ...)
2016-10-27 19:27 ` [PATCH v2 05/09] spi: fsl-espi: fix and improve reading from RX FIFO Heiner Kallweit
@ 2016-10-27 19:27 ` Heiner Kallweit
2016-10-27 19:28 ` [PATCH v2 07/09] spi: fsl-espi: extend and improve transfer error handling Heiner Kallweit
` (2 subsequent siblings)
18 siblings, 0 replies; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-27 19:27 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
So far an interrupt is triggered whenever there's at least one byte
in the RX FIFO. This results in a unnecessarily high number of
interrupts.
Change this to generate an interrupt if
- RX FIFO is half full (except if all bytes to read fit into the
RX FIFO anyway)
- end of transfer has been reached
This way the number of interrupts can be significantly reduced.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v2:
- rebased
---
drivers/spi/spi-fsl-espi.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index ca14575..06fb185 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -55,9 +55,10 @@
#define CSMODE_CG(x) ((x) << 3)
#define FSL_ESPI_FIFO_SIZE 32
+#define FSL_ESPI_RXTHR 15
/* Default mode/csmode for eSPI controller */
-#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3))
+#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(FSL_ESPI_RXTHR))
#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
| CSMODE_AFT(0) | CSMODE_CG(1))
@@ -281,6 +282,7 @@ static void fsl_espi_setup_transfer(struct spi_device *spi,
static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ u32 mask;
int ret;
mpc8xxx_spi->rx_len = t->len;
@@ -295,8 +297,11 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM,
(SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
- /* enable rx ints */
- fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, SPIM_RNE);
+ /* enable interrupts */
+ mask = SPIM_DON;
+ if (mpc8xxx_spi->rx_len > FSL_ESPI_FIFO_SIZE)
+ mask |= SPIM_RXT;
+ fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, mask);
/* Prevent filling the fifo from getting interrupted */
spin_lock_irq(&mpc8xxx_spi->lock);
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 07/09] spi: fsl-espi: extend and improve transfer error handling
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (15 preceding siblings ...)
2016-10-27 19:27 ` [PATCH v2 06/09] spi: fsl-espi: make better use of the RX FIFO Heiner Kallweit
@ 2016-10-27 19:28 ` Heiner Kallweit
2016-10-27 19:28 ` [PATCH v2 08/09] spi: fsl-espi: add support for RXSKIP mode Heiner Kallweit
2016-10-27 19:29 ` [PATCH v2 09/09] spi: fsl-espi: add support for dual read mode Heiner Kallweit
18 siblings, 0 replies; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-27 19:28 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
Extend and improve transfer error handling
- in case of timeout report also number of remaining rx bytes
- in case of timeout return ETIMEDOUT instead of EMSGSIZE
- add sanity checks after all bytes have been sent / read:
- check that HW has flag SPIE_DON set
- check that RX / TX FIFO are empty
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v2:
- rebased
---
drivers/spi/spi-fsl-espi.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 06fb185..2f95b19 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -312,13 +312,13 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
ret = wait_for_completion_timeout(&mpc8xxx_spi->done, 2 * HZ);
if (ret == 0)
dev_err(mpc8xxx_spi->dev,
- "Transaction hanging up (left %u bytes)\n",
- mpc8xxx_spi->tx_len);
+ "Transaction hanging up (left %u tx bytes, %u rx bytes)\n",
+ mpc8xxx_spi->tx_len, mpc8xxx_spi->rx_len);
/* disable rx ints */
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPIM, 0);
- return mpc8xxx_spi->tx_len > 0 ? -EMSGSIZE : 0;
+ return ret == 0 ? -ETIMEDOUT : 0;
}
static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
@@ -447,8 +447,20 @@ static void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
if (mspi->tx_len)
fsl_espi_fill_tx_fifo(mspi, events);
- if (!mspi->tx_len && !mspi->rx_len)
- complete(&mspi->done);
+ if (mspi->tx_len || mspi->rx_len)
+ return;
+
+ /* we're done, but check for errors before returning */
+ events = fsl_espi_read_reg(mspi, ESPI_SPIE);
+
+ if (!(events & SPIE_DON))
+ dev_err(mspi->dev,
+ "Transfer done but SPIE_DON isn't set!\n");
+
+ if (SPIE_RXCNT(events) || SPIE_TXCNT(events) != FSL_ESPI_FIFO_SIZE)
+ dev_err(mspi->dev, "Transfer done but rx/tx fifo's aren't empty!\n");
+
+ complete(&mspi->done);
}
static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 08/09] spi: fsl-espi: add support for RXSKIP mode
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (16 preceding siblings ...)
2016-10-27 19:28 ` [PATCH v2 07/09] spi: fsl-espi: extend and improve transfer error handling Heiner Kallweit
@ 2016-10-27 19:28 ` Heiner Kallweit
2016-10-27 19:29 ` [PATCH v2 09/09] spi: fsl-espi: add support for dual read mode Heiner Kallweit
18 siblings, 0 replies; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-27 19:28 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
This patch adds support for ESPI RXSKIP mode. This mode is optimized
for flash reads:
- sends a number of bytes and then reads a number of bytes
- shifts out zeros automatically when reading
- optionally can be configured for dual read mode
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v2:
- rebased
---
drivers/spi/spi-fsl-espi.c | 56 ++++++++++++++++++++++++++++++++++++++++++----
drivers/spi/spi-fsl-lib.h | 1 +
2 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 2f95b19..e32dc30 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -150,7 +150,8 @@ static void fsl_espi_copy_to_buf(struct spi_message *m,
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->tx_buf)
fsl_espi_memcpy_swab(buf, t->tx_buf, m, t);
- else
+ /* In RXSKIP mode controller shifts zeros automatically */
+ else if (!mspi->rxskip)
memset(buf, 0, t->len);
buf += t->len;
}
@@ -203,6 +204,42 @@ static int fsl_espi_check_message(struct spi_message *m)
return 0;
}
+static void fsl_espi_check_rxskip_mode(struct spi_message *m,
+ struct mpc8xxx_spi *mspi)
+{
+ struct spi_transfer *t;
+ unsigned int i = 0, rxskip_len = 0;
+
+ mspi->rxskip = 0;
+
+ /*
+ * prerequisites for rxskip mode:
+ * - message has two transfers
+ * - first transfer is a write and second is a read
+ *
+ * In addition enable rxskip mode only if length of write transfer
+ * is <= FSL_ESPI_FIFO_SIZE. This allows to keep the current
+ * low-level transfer implementation.
+ * This constraint doesn't affect SPI NOR reads as typical use case
+ * for rxskip mode as the read command has only few bytes.
+ */
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (i == 0) {
+ if (!t->tx_buf || t->rx_buf ||
+ t->len > FSL_ESPI_FIFO_SIZE)
+ return;
+ rxskip_len = t->len;
+ } else if (i == 1) {
+ if (t->tx_buf || !t->rx_buf)
+ return;
+ }
+ i++;
+ }
+
+ if (i == 2)
+ mspi->rxskip = rxskip_len;
+}
+
static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events)
{
u32 tx_fifo_avail;
@@ -282,7 +319,7 @@ static void fsl_espi_setup_transfer(struct spi_device *spi,
static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
- u32 mask;
+ u32 mask, spcom;
int ret;
mpc8xxx_spi->rx_len = t->len;
@@ -294,8 +331,18 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
reinit_completion(&mpc8xxx_spi->done);
/* Set SPCOM[CS] and SPCOM[TRANLEN] field */
- fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM,
- (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
+ spcom = SPCOM_CS(spi->chip_select);
+ spcom |= SPCOM_TRANLEN(t->len - 1);
+
+ /* configure RXSKIP mode */
+ if (mpc8xxx_spi->rxskip) {
+ spcom |= SPCOM_RXSKIP(mpc8xxx_spi->rxskip);
+ mpc8xxx_spi->tx_len = mpc8xxx_spi->rxskip;
+ mpc8xxx_spi->rx_len = t->len - mpc8xxx_spi->rxskip;
+ mpc8xxx_spi->rx = t->rx_buf + mpc8xxx_spi->rxskip;
+ }
+
+ fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM, spcom);
/* enable interrupts */
mask = SPIM_DON;
@@ -327,6 +374,7 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
struct spi_device *spi = m->spi;
int ret;
+ fsl_espi_check_rxskip_mode(m, mspi);
fsl_espi_copy_to_buf(m, mspi);
fsl_espi_setup_transfer(spi, trans);
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index 35a7a17..8096fae 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -32,6 +32,7 @@ struct mpc8xxx_spi {
unsigned int rx_len;
unsigned int tx_len;
u8 *local_buf;
+ unsigned int rxskip;
spinlock_t lock;
#endif
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v2 09/09] spi: fsl-espi: add support for dual read mode
[not found] ` <5b98be38-17a2-79a2-14da-fb2bb6f8820f-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
` (17 preceding siblings ...)
2016-10-27 19:28 ` [PATCH v2 08/09] spi: fsl-espi: add support for RXSKIP mode Heiner Kallweit
@ 2016-10-27 19:29 ` Heiner Kallweit
18 siblings, 0 replies; 30+ messages in thread
From: Heiner Kallweit @ 2016-10-27 19:29 UTC (permalink / raw)
To: Mark Brown; +Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA
This patch adds support for dual output read mode.
It was successfully tested on a P1014-based device
with a S25FL128S spi nor flash.
Signed-off-by: Heiner Kallweit <hkallweit1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
v2:
- rebased
- extended commit message
---
drivers/spi/spi-fsl-espi.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index e32dc30..5753b1e 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -205,10 +205,11 @@ static int fsl_espi_check_message(struct spi_message *m)
}
static void fsl_espi_check_rxskip_mode(struct spi_message *m,
- struct mpc8xxx_spi *mspi)
+ struct mpc8xxx_spi *mspi,
+ struct spi_transfer *tr)
{
struct spi_transfer *t;
- unsigned int i = 0, rxskip_len = 0;
+ unsigned int i = 0, rxskip_len = 0, rx_nbits = SPI_NBITS_SINGLE;
mspi->rxskip = 0;
@@ -222,6 +223,9 @@ static void fsl_espi_check_rxskip_mode(struct spi_message *m,
* low-level transfer implementation.
* This constraint doesn't affect SPI NOR reads as typical use case
* for rxskip mode as the read command has only few bytes.
+ *
+ * Store rx_nbits of the read transfer for later assessment
+ * whether single or dual mode is requested.
*/
list_for_each_entry(t, &m->transfers, transfer_list) {
if (i == 0) {
@@ -232,12 +236,15 @@ static void fsl_espi_check_rxskip_mode(struct spi_message *m,
} else if (i == 1) {
if (t->tx_buf || !t->rx_buf)
return;
+ rx_nbits = t->rx_nbits;
}
i++;
}
- if (i == 2)
+ if (i == 2) {
mspi->rxskip = rxskip_len;
+ tr->rx_nbits = rx_nbits;
+ }
}
static void fsl_espi_fill_tx_fifo(struct mpc8xxx_spi *mspi, u32 events)
@@ -340,6 +347,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
mpc8xxx_spi->tx_len = mpc8xxx_spi->rxskip;
mpc8xxx_spi->rx_len = t->len - mpc8xxx_spi->rxskip;
mpc8xxx_spi->rx = t->rx_buf + mpc8xxx_spi->rxskip;
+ if (t->rx_nbits == SPI_NBITS_DUAL)
+ spcom |= SPCOM_DO;
}
fsl_espi_write_reg(mpc8xxx_spi, ESPI_SPCOM, spcom);
@@ -374,7 +383,7 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
struct spi_device *spi = m->spi;
int ret;
- fsl_espi_check_rxskip_mode(m, mspi);
+ fsl_espi_check_rxskip_mode(m, mspi, trans);
fsl_espi_copy_to_buf(m, mspi);
fsl_espi_setup_transfer(spi, trans);
@@ -588,6 +597,7 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
mpc8xxx_spi_probe(dev, mem, irq);
+ master->mode_bits |= SPI_RX_DUAL;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
master->setup = fsl_espi_setup;
master->cleanup = fsl_espi_cleanup;
--
2.10.1
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 30+ messages in thread